X-Git-Url: http://git.sourceforge.jp/view?p=pf3gnuchains%2Fgcc-fork.git;a=blobdiff_plain;f=gcc%2Fconfig%2Fmips%2Fmips.c;h=aed07e58dda3587e84ca90e8482176bc63ccea00;hp=12a6b2debed723f49e1e34d9dbe0663cda2768a2;hb=595e90415cd831dfd3680ccdb134f5f71392a88e;hpb=c3ceba8e8139354ec6e7fb9510bb3541d5baac23 diff --git a/gcc/config/mips/mips.c b/gcc/config/mips/mips.c index 12a6b2debed..aed07e58dda 100644 --- a/gcc/config/mips/mips.c +++ b/gcc/config/mips/mips.c @@ -20,8 +20,8 @@ GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GCC; see the file COPYING. If not, write to -the Free Software Foundation, 59 Temple Place - Suite 330, -Boston, MA 02111-1307, USA. */ +the Free Software Foundation, 51 Franklin Street, Fifth Floor, +Boston, MA 02110-1301, USA. */ #include "config.h" #include "system.h" @@ -56,6 +56,7 @@ Boston, MA 02111-1307, USA. */ #include "cfglayout.h" #include "sched-int.h" #include "tree-gimple.h" +#include "bitmap.h" /* True if X is an unspec wrapper around a SYMBOL_REF or LABEL_REF. */ #define UNSPEC_ADDRESS_P(X) \ @@ -150,6 +151,35 @@ enum mips_function_type MIPS_DF_FTYPE_DF, MIPS_DF_FTYPE_DF_DF, + /* For MIPS DSP ASE */ + MIPS_DI_FTYPE_DI_SI, + MIPS_DI_FTYPE_DI_SI_SI, + MIPS_DI_FTYPE_DI_V2HI_V2HI, + MIPS_DI_FTYPE_DI_V4QI_V4QI, + MIPS_SI_FTYPE_DI_SI, + MIPS_SI_FTYPE_PTR_SI, + MIPS_SI_FTYPE_SI, + MIPS_SI_FTYPE_SI_SI, + MIPS_SI_FTYPE_V2HI, + MIPS_SI_FTYPE_V2HI_V2HI, + MIPS_SI_FTYPE_V4QI, + MIPS_SI_FTYPE_V4QI_V4QI, + MIPS_SI_FTYPE_VOID, + MIPS_V2HI_FTYPE_SI, + MIPS_V2HI_FTYPE_SI_SI, + MIPS_V2HI_FTYPE_V2HI, + MIPS_V2HI_FTYPE_V2HI_SI, + MIPS_V2HI_FTYPE_V2HI_V2HI, + MIPS_V2HI_FTYPE_V4QI, + MIPS_V2HI_FTYPE_V4QI_V2HI, + MIPS_V4QI_FTYPE_SI, + MIPS_V4QI_FTYPE_V2HI_V2HI, + MIPS_V4QI_FTYPE_V4QI_SI, + MIPS_V4QI_FTYPE_V4QI_V4QI, + MIPS_VOID_FTYPE_SI_SI, + MIPS_VOID_FTYPE_V2HI_V2HI, + MIPS_VOID_FTYPE_V4QI_V4QI, + /* The last type. */ MIPS_MAX_FTYPE_MAX }; @@ -162,6 +192,10 @@ enum mips_builtin_type operands 1 and above. */ MIPS_BUILTIN_DIRECT, + /* The builtin corresponds directly to an .md pattern. There is no return + value and the arguments are mapped to operands 0 and above. */ + MIPS_BUILTIN_DIRECT_NO_TARGET, + /* The builtin corresponds to a comparison instruction followed by a mips_cond_move_tf_ps pattern. The first two arguments are the values to compare and the second two arguments are the vector @@ -185,7 +219,10 @@ enum mips_builtin_type MIPS_BUILTIN_CMP_LOWER, /* As above, but the instruction only sets a single $fcc register. */ - MIPS_BUILTIN_CMP_SINGLE + MIPS_BUILTIN_CMP_SINGLE, + + /* For generating bposge32 branch instructions in MIPS32 DSP ASE. */ + MIPS_BUILTIN_BPOSGE32 }; /* Invokes MACRO (COND) for each c.cond.fmt condition. */ @@ -292,9 +329,9 @@ static void mips_restore_reg (rtx, rtx); static void mips_output_mi_thunk (FILE *, tree, HOST_WIDE_INT, HOST_WIDE_INT, tree); static int symbolic_expression_p (rtx); -static void mips_select_rtx_section (enum machine_mode, rtx, - unsigned HOST_WIDE_INT); -static void mips_function_rodata_section (tree); +static section *mips_select_rtx_section (enum machine_mode, rtx, + unsigned HOST_WIDE_INT); +static section *mips_function_rodata_section (tree); static bool mips_in_small_data_p (tree); static int mips_fpr_return_fields (tree, tree *); static bool mips_return_in_msb (tree); @@ -357,19 +394,21 @@ static bool mips_callee_copies (CUMULATIVE_ARGS *, enum machine_mode mode, static int mips_arg_partial_bytes (CUMULATIVE_ARGS *, enum machine_mode mode, tree, bool); static bool mips_valid_pointer_mode (enum machine_mode); -static bool mips_scalar_mode_supported_p (enum machine_mode); static bool mips_vector_mode_supported_p (enum machine_mode); static rtx mips_prepare_builtin_arg (enum insn_code, unsigned int, tree *); static rtx mips_prepare_builtin_target (enum insn_code, unsigned int, rtx); static rtx mips_expand_builtin (tree, rtx, rtx, enum machine_mode, int); static void mips_init_builtins (void); -static rtx mips_expand_builtin_direct (enum insn_code, rtx, tree); +static rtx mips_expand_builtin_direct (enum insn_code, rtx, tree, bool); static rtx mips_expand_builtin_movtf (enum mips_builtin_type, enum insn_code, enum mips_fp_condition, rtx, tree); static rtx mips_expand_builtin_compare (enum mips_builtin_type, enum insn_code, enum mips_fp_condition, rtx, tree); +static rtx mips_expand_builtin_bposge (enum mips_builtin_type, rtx); +static void mips_encode_section_info (tree, rtx, int); +static void mips_extra_live_on_entry (bitmap); /* Structure to be filled in by compute_frame_size with register save masks, and offsets for the current function. */ @@ -398,6 +437,10 @@ struct machine_function GTY(()) { refers to GP relative global variables. */ rtx mips16_gp_pseudo_rtx; + /* The number of extra stack bytes taken up by register varargs. + This area is allocated by the callee at the very top of the frame. */ + int varargs_size; + /* Current frame information, calculated by compute_frame_size. */ struct mips_frame_info frame; @@ -550,21 +593,18 @@ int mips_isa; /* Which ABI to use. */ int mips_abi = MIPS_ABI_DEFAULT; +/* Cost information to use. */ +const struct mips_rtx_cost_data *mips_cost; + /* Whether we are generating mips16 hard float code. In mips16 mode we always set TARGET_SOFT_FLOAT; this variable is nonzero if -msoft-float was not specified by the user, which means that we should arrange to call mips32 hard floating point code. */ int mips16_hard_float; -/* The arguments passed to -march and -mtune. */ -static const char *mips_arch_string; -static const char *mips_tune_string; - /* The architecture selected by -mipsN. */ static const struct mips_cpu_info *mips_isa_info; -const char *mips_cache_flush_func = CACHE_FLUSH_FUNC; - /* If TRUE, we split addresses into their high and low parts in the RTL. */ int mips_split_addresses; @@ -644,11 +684,18 @@ const enum reg_class mips_regno_to_class[] = COP3_REGS, COP3_REGS, COP3_REGS, COP3_REGS, COP3_REGS, COP3_REGS, COP3_REGS, COP3_REGS, COP3_REGS, COP3_REGS, COP3_REGS, COP3_REGS, - COP3_REGS, COP3_REGS, COP3_REGS, COP3_REGS + COP3_REGS, COP3_REGS, COP3_REGS, COP3_REGS, + DSP_ACC_REGS, DSP_ACC_REGS, DSP_ACC_REGS, DSP_ACC_REGS, + DSP_ACC_REGS, DSP_ACC_REGS, ALL_REGS, ALL_REGS, + ALL_REGS, ALL_REGS, ALL_REGS, ALL_REGS }; -/* Map register constraint character to register class. */ -enum reg_class mips_char_to_class[256]; +/* Table of machine dependent attributes. */ +const struct attribute_spec mips_attribute_table[] = +{ + { "long_call", 0, 0, false, true, true, NULL }, + { NULL, 0, 0, false, false, false, NULL } +}; /* A table describing all the processors gcc knows about. Names are matched in the order listed. The first mention of an ISA level is @@ -696,13 +743,19 @@ const struct mips_cpu_info mips_cpu_info_table[] = { /* MIPS32 */ { "4kc", PROCESSOR_4KC, 32 }, - { "4kp", PROCESSOR_4KC, 32 }, /* = 4kc */ + { "4km", PROCESSOR_4KC, 32 }, /* = 4kc */ + { "4kp", PROCESSOR_4KP, 32 }, /* MIPS32 Release 2 */ { "m4k", PROCESSOR_M4K, 33 }, + { "24k", PROCESSOR_24K, 33 }, + { "24kc", PROCESSOR_24K, 33 }, /* 24K no FPU */ + { "24kf", PROCESSOR_24K, 33 }, /* 24K 1:2 FPU */ + { "24kx", PROCESSOR_24KX, 33 }, /* 24K 1:1 FPU */ /* MIPS64 */ { "5kc", PROCESSOR_5KC, 64 }, + { "5kf", PROCESSOR_5KF, 64 }, { "20kc", PROCESSOR_20KC, 64 }, { "sb1", PROCESSOR_SB1, 64 }, { "sr71000", PROCESSOR_SR71000, 64 }, @@ -710,6 +763,275 @@ const struct mips_cpu_info mips_cpu_info_table[] = { /* End marker */ { 0, 0, 0 } }; + +/* Default costs. If these are used for a processor we should look + up the actual costs. */ +#define DEFAULT_COSTS COSTS_N_INSNS (6), /* fp_add */ \ + COSTS_N_INSNS (7), /* fp_mult_sf */ \ + COSTS_N_INSNS (8), /* fp_mult_df */ \ + COSTS_N_INSNS (23), /* fp_div_sf */ \ + COSTS_N_INSNS (36), /* fp_div_df */ \ + COSTS_N_INSNS (10), /* int_mult_si */ \ + COSTS_N_INSNS (10), /* int_mult_di */ \ + COSTS_N_INSNS (69), /* int_div_si */ \ + COSTS_N_INSNS (69), /* int_div_di */ \ + 2, /* branch_cost */ \ + 4 /* memory_latency */ + +/* Need to replace these with the costs of calling the appropriate + libgcc routine. */ +#define SOFT_FP_COSTS COSTS_N_INSNS (256), /* fp_add */ \ + COSTS_N_INSNS (256), /* fp_mult_sf */ \ + COSTS_N_INSNS (256), /* fp_mult_df */ \ + COSTS_N_INSNS (256), /* fp_div_sf */ \ + COSTS_N_INSNS (256) /* fp_div_df */ + +static struct mips_rtx_cost_data const mips_rtx_cost_data[PROCESSOR_MAX] = + { + { /* R3000 */ + COSTS_N_INSNS (2), /* fp_add */ + COSTS_N_INSNS (4), /* fp_mult_sf */ + COSTS_N_INSNS (5), /* fp_mult_df */ + COSTS_N_INSNS (12), /* fp_div_sf */ + COSTS_N_INSNS (19), /* fp_div_df */ + COSTS_N_INSNS (12), /* int_mult_si */ + COSTS_N_INSNS (12), /* int_mult_di */ + COSTS_N_INSNS (35), /* int_div_si */ + COSTS_N_INSNS (35), /* int_div_di */ + 1, /* branch_cost */ + 4 /* memory_latency */ + + }, + { /* 4KC */ + SOFT_FP_COSTS, + COSTS_N_INSNS (6), /* int_mult_si */ + COSTS_N_INSNS (6), /* int_mult_di */ + COSTS_N_INSNS (36), /* int_div_si */ + COSTS_N_INSNS (36), /* int_div_di */ + 1, /* branch_cost */ + 4 /* memory_latency */ + }, + { /* 4KP */ + SOFT_FP_COSTS, + COSTS_N_INSNS (36), /* int_mult_si */ + COSTS_N_INSNS (36), /* int_mult_di */ + COSTS_N_INSNS (37), /* int_div_si */ + COSTS_N_INSNS (37), /* int_div_di */ + 1, /* branch_cost */ + 4 /* memory_latency */ + }, + { /* 5KC */ + SOFT_FP_COSTS, + COSTS_N_INSNS (4), /* int_mult_si */ + COSTS_N_INSNS (11), /* int_mult_di */ + COSTS_N_INSNS (36), /* int_div_si */ + COSTS_N_INSNS (68), /* int_div_di */ + 1, /* branch_cost */ + 4 /* memory_latency */ + }, + { /* 5KF */ + COSTS_N_INSNS (4), /* fp_add */ + COSTS_N_INSNS (4), /* fp_mult_sf */ + COSTS_N_INSNS (5), /* fp_mult_df */ + COSTS_N_INSNS (17), /* fp_div_sf */ + COSTS_N_INSNS (32), /* fp_div_df */ + COSTS_N_INSNS (4), /* int_mult_si */ + COSTS_N_INSNS (11), /* int_mult_di */ + COSTS_N_INSNS (36), /* int_div_si */ + COSTS_N_INSNS (68), /* int_div_di */ + 1, /* branch_cost */ + 4 /* memory_latency */ + }, + { /* 20KC */ + DEFAULT_COSTS + }, + { /* 24k */ + COSTS_N_INSNS (8), /* fp_add */ + COSTS_N_INSNS (8), /* fp_mult_sf */ + COSTS_N_INSNS (10), /* fp_mult_df */ + COSTS_N_INSNS (34), /* fp_div_sf */ + COSTS_N_INSNS (64), /* fp_div_df */ + COSTS_N_INSNS (5), /* int_mult_si */ + COSTS_N_INSNS (5), /* int_mult_di */ + COSTS_N_INSNS (41), /* int_div_si */ + COSTS_N_INSNS (41), /* int_div_di */ + 1, /* branch_cost */ + 4 /* memory_latency */ + }, + { /* 24kx */ + COSTS_N_INSNS (4), /* fp_add */ + COSTS_N_INSNS (4), /* fp_mult_sf */ + COSTS_N_INSNS (5), /* fp_mult_df */ + COSTS_N_INSNS (17), /* fp_div_sf */ + COSTS_N_INSNS (32), /* fp_div_df */ + COSTS_N_INSNS (5), /* int_mult_si */ + COSTS_N_INSNS (5), /* int_mult_di */ + COSTS_N_INSNS (41), /* int_div_si */ + COSTS_N_INSNS (41), /* int_div_di */ + 1, /* branch_cost */ + 4 /* memory_latency */ + }, + { /* M4k */ + DEFAULT_COSTS + }, + { /* R3900 */ + COSTS_N_INSNS (2), /* fp_add */ + COSTS_N_INSNS (4), /* fp_mult_sf */ + COSTS_N_INSNS (5), /* fp_mult_df */ + COSTS_N_INSNS (12), /* fp_div_sf */ + COSTS_N_INSNS (19), /* fp_div_df */ + COSTS_N_INSNS (2), /* int_mult_si */ + COSTS_N_INSNS (2), /* int_mult_di */ + COSTS_N_INSNS (35), /* int_div_si */ + COSTS_N_INSNS (35), /* int_div_di */ + 1, /* branch_cost */ + 4 /* memory_latency */ + }, + { /* R6000 */ + COSTS_N_INSNS (3), /* fp_add */ + COSTS_N_INSNS (5), /* fp_mult_sf */ + COSTS_N_INSNS (6), /* fp_mult_df */ + COSTS_N_INSNS (15), /* fp_div_sf */ + COSTS_N_INSNS (16), /* fp_div_df */ + COSTS_N_INSNS (17), /* int_mult_si */ + COSTS_N_INSNS (17), /* int_mult_di */ + COSTS_N_INSNS (38), /* int_div_si */ + COSTS_N_INSNS (38), /* int_div_di */ + 2, /* branch_cost */ + 6 /* memory_latency */ + }, + { /* R4000 */ + COSTS_N_INSNS (6), /* fp_add */ + COSTS_N_INSNS (7), /* fp_mult_sf */ + COSTS_N_INSNS (8), /* fp_mult_df */ + COSTS_N_INSNS (23), /* fp_div_sf */ + COSTS_N_INSNS (36), /* fp_div_df */ + COSTS_N_INSNS (10), /* int_mult_si */ + COSTS_N_INSNS (10), /* int_mult_di */ + COSTS_N_INSNS (69), /* int_div_si */ + COSTS_N_INSNS (69), /* int_div_di */ + 2, /* branch_cost */ + 6 /* memory_latency */ + }, + { /* R4100 */ + DEFAULT_COSTS + }, + { /* R4111 */ + DEFAULT_COSTS + }, + { /* R4120 */ + DEFAULT_COSTS + }, + { /* R4130 */ + /* The only costs that appear to be updated here are + integer multiplication. */ + SOFT_FP_COSTS, + COSTS_N_INSNS (4), /* int_mult_si */ + COSTS_N_INSNS (6), /* int_mult_di */ + COSTS_N_INSNS (69), /* int_div_si */ + COSTS_N_INSNS (69), /* int_div_di */ + 1, /* branch_cost */ + 4 /* memory_latency */ + }, + { /* R4300 */ + DEFAULT_COSTS + }, + { /* R4600 */ + DEFAULT_COSTS + }, + { /* R4650 */ + DEFAULT_COSTS + }, + { /* R5000 */ + COSTS_N_INSNS (6), /* fp_add */ + COSTS_N_INSNS (4), /* fp_mult_sf */ + COSTS_N_INSNS (5), /* fp_mult_df */ + COSTS_N_INSNS (23), /* fp_div_sf */ + COSTS_N_INSNS (36), /* fp_div_df */ + COSTS_N_INSNS (5), /* int_mult_si */ + COSTS_N_INSNS (5), /* int_mult_di */ + COSTS_N_INSNS (36), /* int_div_si */ + COSTS_N_INSNS (36), /* int_div_di */ + 1, /* branch_cost */ + 4 /* memory_latency */ + }, + { /* R5400 */ + COSTS_N_INSNS (6), /* fp_add */ + COSTS_N_INSNS (5), /* fp_mult_sf */ + COSTS_N_INSNS (6), /* fp_mult_df */ + COSTS_N_INSNS (30), /* fp_div_sf */ + COSTS_N_INSNS (59), /* fp_div_df */ + COSTS_N_INSNS (3), /* int_mult_si */ + COSTS_N_INSNS (4), /* int_mult_di */ + COSTS_N_INSNS (42), /* int_div_si */ + COSTS_N_INSNS (74), /* int_div_di */ + 1, /* branch_cost */ + 4 /* memory_latency */ + }, + { /* R5500 */ + COSTS_N_INSNS (6), /* fp_add */ + COSTS_N_INSNS (5), /* fp_mult_sf */ + COSTS_N_INSNS (6), /* fp_mult_df */ + COSTS_N_INSNS (30), /* fp_div_sf */ + COSTS_N_INSNS (59), /* fp_div_df */ + COSTS_N_INSNS (5), /* int_mult_si */ + COSTS_N_INSNS (9), /* int_mult_di */ + COSTS_N_INSNS (42), /* int_div_si */ + COSTS_N_INSNS (74), /* int_div_di */ + 1, /* branch_cost */ + 4 /* memory_latency */ + }, + { /* R7000 */ + /* The only costs that are changed here are + integer multiplication. */ + COSTS_N_INSNS (6), /* fp_add */ + COSTS_N_INSNS (7), /* fp_mult_sf */ + COSTS_N_INSNS (8), /* fp_mult_df */ + COSTS_N_INSNS (23), /* fp_div_sf */ + COSTS_N_INSNS (36), /* fp_div_df */ + COSTS_N_INSNS (5), /* int_mult_si */ + COSTS_N_INSNS (9), /* int_mult_di */ + COSTS_N_INSNS (69), /* int_div_si */ + COSTS_N_INSNS (69), /* int_div_di */ + 1, /* branch_cost */ + 4 /* memory_latency */ + }, + { /* R8000 */ + DEFAULT_COSTS + }, + { /* R9000 */ + /* The only costs that are changed here are + integer multiplication. */ + COSTS_N_INSNS (6), /* fp_add */ + COSTS_N_INSNS (7), /* fp_mult_sf */ + COSTS_N_INSNS (8), /* fp_mult_df */ + COSTS_N_INSNS (23), /* fp_div_sf */ + COSTS_N_INSNS (36), /* fp_div_df */ + COSTS_N_INSNS (3), /* int_mult_si */ + COSTS_N_INSNS (8), /* int_mult_di */ + COSTS_N_INSNS (69), /* int_div_si */ + COSTS_N_INSNS (69), /* int_div_di */ + 1, /* branch_cost */ + 4 /* memory_latency */ + }, + { /* SB1 */ + COSTS_N_INSNS (4), /* fp_add */ + COSTS_N_INSNS (4), /* fp_mult_sf */ + COSTS_N_INSNS (4), /* fp_mult_df */ + COSTS_N_INSNS (24), /* fp_div_sf */ + COSTS_N_INSNS (32), /* fp_div_df */ + COSTS_N_INSNS (3), /* int_mult_si */ + COSTS_N_INSNS (4), /* int_mult_di */ + COSTS_N_INSNS (36), /* int_div_si */ + COSTS_N_INSNS (68), /* int_div_di */ + 1, /* branch_cost */ + 4 /* memory_latency */ + }, + { /* SR71000 */ + DEFAULT_COSTS + }, + }; + /* Nonzero if -march should decide the default value of MASK_SOFT_FLOAT. */ #ifndef MIPS_MARCH_CONTROLS_SOFT_FLOAT @@ -820,9 +1142,6 @@ const struct mips_cpu_info mips_cpu_info_table[] = { #undef TARGET_VECTOR_MODE_SUPPORTED_P #define TARGET_VECTOR_MODE_SUPPORTED_P mips_vector_mode_supported_p -#undef TARGET_SCALAR_MODE_SUPPORTED_P -#define TARGET_SCALAR_MODE_SUPPORTED_P mips_scalar_mode_supported_p - #undef TARGET_INIT_BUILTINS #define TARGET_INIT_BUILTINS mips_init_builtins #undef TARGET_EXPAND_BUILTIN @@ -834,6 +1153,18 @@ const struct mips_cpu_info mips_cpu_info_table[] = { #undef TARGET_CANNOT_FORCE_CONST_MEM #define TARGET_CANNOT_FORCE_CONST_MEM mips_cannot_force_const_mem +#undef TARGET_ENCODE_SECTION_INFO +#define TARGET_ENCODE_SECTION_INFO mips_encode_section_info + +#undef TARGET_ATTRIBUTE_TABLE +#define TARGET_ATTRIBUTE_TABLE mips_attribute_table + +#undef TARGET_EXTRA_LIVE_ON_ENTRY +/* With -mabicalls (which is the default on GNU/Linux), + PIC_FUNCTION_ADDR_REGNUM is live on function entry and is to + initialize $28, which is PIC_OFFSET_TABLE_REGNUM. */ +#define TARGET_EXTRA_LIVE_ON_ENTRY mips_extra_live_on_entry + struct gcc_target targetm = TARGET_INITIALIZER; /* Classify symbol X, which must be a SYMBOL_REF or a LABEL_REF. */ @@ -1698,7 +2029,7 @@ mips_legitimize_tls_address (rtx loc) break; default: - abort (); + gcc_unreachable (); } return dest; @@ -2089,75 +2420,78 @@ static bool mips_rtx_costs (rtx x, int code, int outer_code, int *total) { enum machine_mode mode = GET_MODE (x); + bool float_mode_p = FLOAT_MODE_P (mode); switch (code) { case CONST_INT: - if (!TARGET_MIPS16) - { - /* Always return 0, since we don't have different sized - instructions, hence different costs according to Richard - Kenner */ - *total = 0; - return true; - } - - /* 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 - || (outer_code) == LSHIFTRT) + if (TARGET_MIPS16) { - if (INTVAL (x) >= 1 && INTVAL (x) <= 8) - *total = 0; - else - *total = COSTS_N_INSNS (1); - return true; - } + /* 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 + || (outer_code) == LSHIFTRT) + { + if (INTVAL (x) >= 1 && INTVAL (x) <= 8) + *total = 0; + else + *total = COSTS_N_INSNS (1); + return true; + } - /* We can use cmpi for an xor with an unsigned 16 bit value. */ - if ((outer_code) == XOR - && INTVAL (x) >= 0 && INTVAL (x) < 0x10000) - { - *total = 0; - return true; - } + /* We can use cmpi for an xor with an unsigned 16 bit value. */ + if ((outer_code) == XOR + && INTVAL (x) >= 0 && INTVAL (x) < 0x10000) + { + *total = 0; + return true; + } - /* We may be able to use slt or sltu for a comparison with a - signed 16 bit value. (The boundary conditions aren't quite - right, but this is just a heuristic anyhow.) */ - if (((outer_code) == LT || (outer_code) == LE - || (outer_code) == GE || (outer_code) == GT - || (outer_code) == LTU || (outer_code) == LEU - || (outer_code) == GEU || (outer_code) == GTU) - && INTVAL (x) >= -0x8000 && INTVAL (x) < 0x8000) - { - *total = 0; - return true; - } + /* We may be able to use slt or sltu for a comparison with a + signed 16 bit value. (The boundary conditions aren't quite + right, but this is just a heuristic anyhow.) */ + if (((outer_code) == LT || (outer_code) == LE + || (outer_code) == GE || (outer_code) == GT + || (outer_code) == LTU || (outer_code) == LEU + || (outer_code) == GEU || (outer_code) == GTU) + && INTVAL (x) >= -0x8000 && INTVAL (x) < 0x8000) + { + *total = 0; + return true; + } - /* Equality comparisons with 0 are cheap. */ - if (((outer_code) == EQ || (outer_code) == NE) - && INTVAL (x) == 0) - { - *total = 0; - return true; - } + /* Equality comparisons with 0 are cheap. */ + if (((outer_code) == EQ || (outer_code) == NE) + && INTVAL (x) == 0) + { + *total = 0; + return true; + } - /* Constants in the range 0...255 can be loaded with an unextended - instruction. They are therefore as cheap as a register move. + /* Constants in the range 0...255 can be loaded with an unextended + instruction. They are therefore as cheap as a register move. - Given the choice between "li R1,0...255" and "move R1,R2" - (where R2 is a known constant), it is usually better to use "li", - since we do not want to unnecessarily extend the lifetime of R2. */ - if (outer_code == SET - && INTVAL (x) >= 0 - && INTVAL (x) < 256) + Given the choice between "li R1,0...255" and "move R1,R2" + (where R2 is a known constant), it is usually better to use "li", + since we do not want to unnecessarily extend the lifetime + of R2. */ + if (outer_code == SET + && INTVAL (x) >= 0 + && INTVAL (x) < 256) + { + *total = 0; + return true; + } + } + else { + /* These can be used anywhere. */ *total = 0; return true; } - /* Otherwise fall through to the handling below. */ + /* Otherwise fall through to the handling below because + we'll need to construct the constant. */ case CONST: case SYMBOL_REF: @@ -2177,15 +2511,15 @@ mips_rtx_costs (rtx x, int code, int outer_code, int *total) case MEM: { - /* 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) - { - *total = COSTS_N_INSNS (1 + n); - return true; - } - return false; + /* 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) + { + *total = COSTS_N_INSNS (n + 1); + return true; + } + return false; } case FFS: @@ -2218,7 +2552,7 @@ mips_rtx_costs (rtx x, int code, int outer_code, int *total) return false; case ABS: - if (mode == SFmode || mode == DFmode) + if (float_mode_p) *total = COSTS_N_INSNS (1); else *total = COSTS_N_INSNS (4); @@ -2230,19 +2564,13 @@ mips_rtx_costs (rtx x, int code, int outer_code, int *total) case PLUS: case MINUS: - if (mode == SFmode || mode == DFmode) - { - if (TUNE_MIPS3000 || TUNE_MIPS3900) - *total = COSTS_N_INSNS (2); - else if (TUNE_MIPS6000) - *total = COSTS_N_INSNS (3); - else if (TUNE_SB1) - *total = COSTS_N_INSNS (4); - else - *total = COSTS_N_INSNS (6); - return true; - } - if (mode == DImode && !TARGET_64BIT) + if (float_mode_p) + { + *total = mips_cost->fp_add; + return true; + } + + else if (mode == DImode && !TARGET_64BIT) { *total = COSTS_N_INSNS (4); return true; @@ -2252,115 +2580,46 @@ mips_rtx_costs (rtx x, int code, int outer_code, int *total) case NEG: if (mode == DImode && !TARGET_64BIT) { - *total = 4; + *total = COSTS_N_INSNS (4); return true; } return false; case MULT: if (mode == SFmode) - { - if (TUNE_MIPS3000 - || TUNE_MIPS3900 - || TUNE_MIPS5000 - || TUNE_SB1) - *total = COSTS_N_INSNS (4); - else if (TUNE_MIPS6000 - || TUNE_MIPS5400 - || TUNE_MIPS5500) - *total = COSTS_N_INSNS (5); - else - *total = COSTS_N_INSNS (7); - return true; - } + *total = mips_cost->fp_mult_sf; - if (mode == DFmode) - { - if (TUNE_SB1) - *total = COSTS_N_INSNS (4); - else if (TUNE_MIPS3000 - || TUNE_MIPS3900 - || TUNE_MIPS5000) - *total = COSTS_N_INSNS (5); - else if (TUNE_MIPS6000 - || TUNE_MIPS5400 - || TUNE_MIPS5500) - *total = COSTS_N_INSNS (6); - else - *total = COSTS_N_INSNS (8); - return true; - } + else if (mode == DFmode) + *total = mips_cost->fp_mult_df; + + else if (mode == SImode) + *total = mips_cost->int_mult_si; - if (TUNE_MIPS3000) - *total = COSTS_N_INSNS (12); - else if (TUNE_MIPS3900) - *total = COSTS_N_INSNS (2); - else if (TUNE_MIPS4130) - *total = COSTS_N_INSNS (mode == DImode ? 6 : 4); - else if (TUNE_MIPS5400 || TUNE_SB1) - *total = COSTS_N_INSNS (mode == DImode ? 4 : 3); - else if (TUNE_MIPS5500 || TUNE_MIPS7000) - *total = COSTS_N_INSNS (mode == DImode ? 9 : 5); - else if (TUNE_MIPS9000) - *total = COSTS_N_INSNS (mode == DImode ? 8 : 3); - else if (TUNE_MIPS6000) - *total = COSTS_N_INSNS (17); - else if (TUNE_MIPS5000) - *total = COSTS_N_INSNS (5); else - *total = COSTS_N_INSNS (10); + *total = mips_cost->int_mult_di; + return true; case DIV: case MOD: - if (mode == SFmode) - { - if (TUNE_MIPS3000 - || TUNE_MIPS3900) - *total = COSTS_N_INSNS (12); - else if (TUNE_MIPS6000) - *total = COSTS_N_INSNS (15); - else if (TUNE_SB1) - *total = COSTS_N_INSNS (24); - else if (TUNE_MIPS5400 || TUNE_MIPS5500) - *total = COSTS_N_INSNS (30); - else - *total = COSTS_N_INSNS (23); - return true; - } + if (float_mode_p) + { + if (mode == SFmode) + *total = mips_cost->fp_div_sf; + else + *total = mips_cost->fp_div_df; - if (mode == DFmode) - { - if (TUNE_MIPS3000 - || TUNE_MIPS3900) - *total = COSTS_N_INSNS (19); - else if (TUNE_MIPS5400 || TUNE_MIPS5500) - *total = COSTS_N_INSNS (59); - else if (TUNE_MIPS6000) - *total = COSTS_N_INSNS (16); - else if (TUNE_SB1) - *total = COSTS_N_INSNS (32); - else - *total = COSTS_N_INSNS (36); - return true; - } + return true; + } /* Fall through. */ case UDIV: case UMOD: - if (TUNE_MIPS3000 - || TUNE_MIPS3900) - *total = COSTS_N_INSNS (35); - else if (TUNE_MIPS6000) - *total = COSTS_N_INSNS (38); - else if (TUNE_MIPS5000) - *total = COSTS_N_INSNS (36); - else if (TUNE_SB1) - *total = COSTS_N_INSNS ((mode == SImode) ? 36 : 68); - else if (TUNE_MIPS5400 || TUNE_MIPS5500) - *total = COSTS_N_INSNS ((mode == SImode) ? 42 : 74); + if (mode == DImode) + *total = mips_cost->int_div_di; else - *total = COSTS_N_INSNS (69); + *total = mips_cost->int_div_si; + return true; case SIGN_EXTEND: @@ -2382,6 +2641,15 @@ mips_rtx_costs (rtx x, int code, int outer_code, int *total) *total = COSTS_N_INSNS (1); return true; + case FLOAT: + case UNSIGNED_FLOAT: + case FIX: + case FLOAT_EXTEND: + case FLOAT_TRUNCATE: + case SQRT: + *total = mips_cost->fp_add; + return true; + default: return false; } @@ -2419,8 +2687,8 @@ mips_subword (rtx op, int high_p) { if (FP_REG_P (REGNO (op))) return gen_rtx_REG (word_mode, high_p ? REGNO (op) + 1 : REGNO (op)); - if (REGNO (op) == HI_REGNUM) - return gen_rtx_REG (word_mode, high_p ? HI_REGNUM : LO_REGNUM); + if (ACC_HI_REG_P (REGNO (op))) + return gen_rtx_REG (word_mode, high_p ? REGNO (op) : REGNO (op) + 1); } if (MEM_P (op)) @@ -2534,6 +2802,14 @@ mips_output_move (rtx dest, rtx src) if (MD_REG_P (REGNO (dest))) return "mt%0\t%z1"; + if (DSP_ACC_REG_P (REGNO (dest))) + { + static char retval[] = "mt__\t%z1,%q0"; + retval[2] = reg_names[REGNO (dest)][4]; + retval[3] = reg_names[REGNO (dest)][5]; + return retval; + } + if (FP_REG_P (REGNO (dest))) return (dbl_p ? "dmtc1\t%z1,%0" : "mtc1\t%z1,%0"); @@ -2552,6 +2828,14 @@ mips_output_move (rtx dest, rtx src) { if (src_code == REG) { + if (DSP_ACC_REG_P (REGNO (src))) + { + static char retval[] = "mf__\t%0,%q1"; + retval[2] = reg_names[REGNO (src)][4]; + retval[3] = reg_names[REGNO (src)][5]; + return retval; + } + if (ST_REG_P (REGNO (src)) && ISA_HAS_8CC) return "lui\t%0,0x3f80\n\tmovf\t%0,%.,%1"; @@ -2692,6 +2976,50 @@ mips_relational_operand_ok_p (enum rtx_code code, rtx cmp1) } } +/* Canonicalize LE or LEU comparisons into LT comparisons when + possible to avoid extra instructions or inverting the + comparison. */ + +static bool +mips_canonicalize_comparison (enum rtx_code *code, rtx *cmp1, + enum machine_mode mode) +{ + HOST_WIDE_INT original, plus_one; + + if (GET_CODE (*cmp1) != CONST_INT) + return false; + + original = INTVAL (*cmp1); + plus_one = trunc_int_for_mode ((unsigned HOST_WIDE_INT) original + 1, mode); + + switch (*code) + { + case LE: + if (original < plus_one) + { + *code = LT; + *cmp1 = force_reg (mode, GEN_INT (plus_one)); + return true; + } + break; + + case LEU: + if (plus_one != 0) + { + *code = LTU; + *cmp1 = force_reg (mode, GEN_INT (plus_one)); + return true; + } + break; + + default: + return false; + } + + return false; + +} + /* Compare CMP0 and CMP1 using relational operator CODE and store the result in TARGET. CMP0 and TARGET are register_operands that have the same integer mode. If INVERT_PTR is nonnull, it's OK to set @@ -2702,11 +3030,14 @@ mips_emit_int_relational (enum rtx_code code, bool *invert_ptr, rtx target, rtx cmp0, rtx cmp1) { /* First see if there is a MIPS instruction that can do this operation - with CMP1 in its current form. If not, try doing the same for the + with CMP1 in its current form. If not, try to canonicalize the + comparison to LT. If that fails, try doing the same for the inverse operation. If that also fails, force CMP1 into a register and try again. */ if (mips_relational_operand_ok_p (code, cmp1)) mips_emit_binary (code, target, cmp0, cmp1); + else if (mips_canonicalize_comparison (&code, &cmp1, GET_MODE (target))) + mips_emit_binary (code, target, cmp0, cmp1); else { enum rtx_code inv_code = reverse_condition (code); @@ -2806,8 +3137,6 @@ mips_emit_compare (enum rtx_code *code, rtx *op0, rtx *op1, bool need_eq_ne_p) switch (*code) { case NE: - case UNGE: - case UNGT: case LTGT: case ORDERED: cmp_code = reverse_condition_maybe_unordered (*code); @@ -3602,7 +3931,8 @@ mips_pad_reg_upward (enum machine_mode mode, tree type) static void mips_setup_incoming_varargs (CUMULATIVE_ARGS *cum, enum machine_mode mode, - tree type, int *pretend_size, int no_rtl) + tree type, int *pretend_size ATTRIBUTE_UNUSED, + int no_rtl) { CUMULATIVE_ARGS local_cum; int gp_saved, fp_saved; @@ -3626,18 +3956,9 @@ mips_setup_incoming_varargs (CUMULATIVE_ARGS *cum, enum machine_mode mode, { rtx ptr, mem; - ptr = virtual_incoming_args_rtx; - switch (mips_abi) - { - case ABI_32: - case ABI_O64: - ptr = plus_constant (ptr, local_cum.num_gprs * UNITS_PER_WORD); - break; - - case ABI_EABI: - ptr = plus_constant (ptr, -gp_saved * UNITS_PER_WORD); - break; - } + ptr = plus_constant (virtual_incoming_args_rtx, + REG_PARM_STACK_SPACE (cfun->decl) + - gp_saved * UNITS_PER_WORD); mem = gen_rtx_MEM (BLKmode, ptr); set_mem_alias_set (mem, get_varargs_alias_set ()); @@ -3672,14 +3993,9 @@ mips_setup_incoming_varargs (CUMULATIVE_ARGS *cum, enum machine_mode mode, } } } - if (TARGET_OLDABI) - { - /* No need for pretend arguments: the register parameter area was - allocated by the caller. */ - *pretend_size = 0; - return; - } - *pretend_size = (gp_saved * UNITS_PER_WORD) + (fp_saved * UNITS_PER_FPREG); + if (REG_PARM_STACK_SPACE (cfun->decl) == 0) + cfun->machine->varargs_size = (gp_saved * UNITS_PER_WORD + + fp_saved * UNITS_PER_FPREG); } /* Create the va_list data type. @@ -3759,101 +4075,84 @@ mips_build_builtin_va_list (void) void mips_va_start (tree valist, rtx nextarg) { - const CUMULATIVE_ARGS *cum = ¤t_function_args_info; - - /* ARG_POINTER_REGNUM is initialized to STACK_POINTER_BOUNDARY, but - since the stack is aligned for a pair of argument-passing slots, - and the beginning of a variable argument list may be an odd slot, - we have to decrease its alignment. */ - if (cfun && cfun->emit->regno_pointer_align) - while (((current_function_pretend_args_size * BITS_PER_UNIT) - & (REGNO_POINTER_ALIGN (ARG_POINTER_REGNUM) - 1)) != 0) - REGNO_POINTER_ALIGN (ARG_POINTER_REGNUM) /= 2; - - if (mips_abi == ABI_EABI) + if (EABI_FLOAT_VARARGS_P) { + const CUMULATIVE_ARGS *cum; + tree f_ovfl, f_gtop, f_ftop, f_goff, f_foff; + tree ovfl, gtop, ftop, goff, foff; + tree t; int gpr_save_area_size; + int fpr_save_area_size; + int fpr_offset; + cum = ¤t_function_args_info; gpr_save_area_size = (MAX_ARGS_IN_REGISTERS - cum->num_gprs) * UNITS_PER_WORD; + fpr_save_area_size + = (MAX_ARGS_IN_REGISTERS - cum->num_fprs) * UNITS_PER_FPREG; - if (EABI_FLOAT_VARARGS_P) - { - tree f_ovfl, f_gtop, f_ftop, f_goff, f_foff; - tree ovfl, gtop, ftop, goff, foff; - tree t; - int fpr_offset; - int fpr_save_area_size; - - f_ovfl = TYPE_FIELDS (va_list_type_node); - f_gtop = TREE_CHAIN (f_ovfl); - f_ftop = TREE_CHAIN (f_gtop); - f_goff = TREE_CHAIN (f_ftop); - f_foff = TREE_CHAIN (f_goff); - - ovfl = build (COMPONENT_REF, TREE_TYPE (f_ovfl), valist, f_ovfl, - NULL_TREE); - gtop = build (COMPONENT_REF, TREE_TYPE (f_gtop), valist, f_gtop, - NULL_TREE); - ftop = build (COMPONENT_REF, TREE_TYPE (f_ftop), valist, f_ftop, - NULL_TREE); - goff = build (COMPONENT_REF, TREE_TYPE (f_goff), valist, f_goff, - NULL_TREE); - foff = build (COMPONENT_REF, TREE_TYPE (f_foff), valist, f_foff, - NULL_TREE); - - /* Emit code to initialize OVFL, which points to the next varargs - stack argument. CUM->STACK_WORDS gives the number of stack - words used by named arguments. */ - t = make_tree (TREE_TYPE (ovfl), virtual_incoming_args_rtx); - if (cum->stack_words > 0) - t = build (PLUS_EXPR, TREE_TYPE (ovfl), t, - build_int_cst (NULL_TREE, - cum->stack_words * UNITS_PER_WORD)); - t = build (MODIFY_EXPR, TREE_TYPE (ovfl), ovfl, t); - expand_expr (t, const0_rtx, VOIDmode, EXPAND_NORMAL); - - /* Emit code to initialize GTOP, the top of the GPR save area. */ - t = make_tree (TREE_TYPE (gtop), virtual_incoming_args_rtx); - t = build (MODIFY_EXPR, TREE_TYPE (gtop), gtop, t); - expand_expr (t, const0_rtx, VOIDmode, EXPAND_NORMAL); - - /* Emit code to initialize FTOP, the top of the FPR save area. - This address is gpr_save_area_bytes below GTOP, rounded - down to the next fp-aligned boundary. */ - t = make_tree (TREE_TYPE (ftop), virtual_incoming_args_rtx); - fpr_offset = gpr_save_area_size + UNITS_PER_FPVALUE - 1; - fpr_offset &= ~(UNITS_PER_FPVALUE - 1); - if (fpr_offset) - t = build (PLUS_EXPR, TREE_TYPE (ftop), t, - build_int_cst (NULL_TREE, -fpr_offset)); - t = build (MODIFY_EXPR, TREE_TYPE (ftop), ftop, t); - expand_expr (t, const0_rtx, VOIDmode, EXPAND_NORMAL); - - /* Emit code to initialize GOFF, the offset from GTOP of the - next GPR argument. */ - t = build (MODIFY_EXPR, TREE_TYPE (goff), goff, - build_int_cst (NULL_TREE, gpr_save_area_size)); - expand_expr (t, const0_rtx, VOIDmode, EXPAND_NORMAL); - - /* Likewise emit code to initialize FOFF, the offset from FTOP - of the next FPR argument. */ - fpr_save_area_size - = (MAX_ARGS_IN_REGISTERS - cum->num_fprs) * UNITS_PER_FPREG; - t = build (MODIFY_EXPR, TREE_TYPE (foff), foff, - build_int_cst (NULL_TREE, fpr_save_area_size)); - expand_expr (t, const0_rtx, VOIDmode, EXPAND_NORMAL); - } - else - { - /* Everything is in the GPR save area, or in the overflow - area which is contiguous with it. */ - nextarg = plus_constant (nextarg, -gpr_save_area_size); - std_expand_builtin_va_start (valist, nextarg); - } + f_ovfl = TYPE_FIELDS (va_list_type_node); + f_gtop = TREE_CHAIN (f_ovfl); + f_ftop = TREE_CHAIN (f_gtop); + f_goff = TREE_CHAIN (f_ftop); + f_foff = TREE_CHAIN (f_goff); + + ovfl = build3 (COMPONENT_REF, TREE_TYPE (f_ovfl), valist, f_ovfl, + NULL_TREE); + gtop = build3 (COMPONENT_REF, TREE_TYPE (f_gtop), valist, f_gtop, + NULL_TREE); + ftop = build3 (COMPONENT_REF, TREE_TYPE (f_ftop), valist, f_ftop, + NULL_TREE); + goff = build3 (COMPONENT_REF, TREE_TYPE (f_goff), valist, f_goff, + NULL_TREE); + foff = build3 (COMPONENT_REF, TREE_TYPE (f_foff), valist, f_foff, + NULL_TREE); + + /* Emit code to initialize OVFL, which points to the next varargs + stack argument. CUM->STACK_WORDS gives the number of stack + words used by named arguments. */ + t = make_tree (TREE_TYPE (ovfl), virtual_incoming_args_rtx); + if (cum->stack_words > 0) + t = build2 (PLUS_EXPR, TREE_TYPE (ovfl), t, + build_int_cst (NULL_TREE, + cum->stack_words * UNITS_PER_WORD)); + t = build2 (MODIFY_EXPR, TREE_TYPE (ovfl), ovfl, t); + expand_expr (t, const0_rtx, VOIDmode, EXPAND_NORMAL); + + /* Emit code to initialize GTOP, the top of the GPR save area. */ + t = make_tree (TREE_TYPE (gtop), virtual_incoming_args_rtx); + t = build2 (MODIFY_EXPR, TREE_TYPE (gtop), gtop, t); + expand_expr (t, const0_rtx, VOIDmode, EXPAND_NORMAL); + + /* Emit code to initialize FTOP, the top of the FPR save area. + This address is gpr_save_area_bytes below GTOP, rounded + down to the next fp-aligned boundary. */ + t = make_tree (TREE_TYPE (ftop), virtual_incoming_args_rtx); + fpr_offset = gpr_save_area_size + UNITS_PER_FPVALUE - 1; + fpr_offset &= ~(UNITS_PER_FPVALUE - 1); + if (fpr_offset) + t = build2 (PLUS_EXPR, TREE_TYPE (ftop), t, + build_int_cst (NULL_TREE, -fpr_offset)); + t = build2 (MODIFY_EXPR, TREE_TYPE (ftop), ftop, t); + expand_expr (t, const0_rtx, VOIDmode, EXPAND_NORMAL); + + /* Emit code to initialize GOFF, the offset from GTOP of the + next GPR argument. */ + t = build2 (MODIFY_EXPR, TREE_TYPE (goff), goff, + build_int_cst (NULL_TREE, gpr_save_area_size)); + expand_expr (t, const0_rtx, VOIDmode, EXPAND_NORMAL); + + /* Likewise emit code to initialize FOFF, the offset from FTOP + of the next FPR argument. */ + t = build2 (MODIFY_EXPR, TREE_TYPE (foff), foff, + build_int_cst (NULL_TREE, fpr_save_area_size)); + expand_expr (t, const0_rtx, VOIDmode, EXPAND_NORMAL); } else - std_expand_builtin_va_start (valist, nextarg); + { + nextarg = plus_constant (nextarg, -cfun->machine->varargs_size); + std_expand_builtin_va_start (valist, nextarg); + } } /* Implement va_arg. */ @@ -3920,16 +4219,16 @@ mips_gimplify_va_arg_expr (tree valist, tree type, tree *pre_p, tree *post_p) [1] and [9] can sometimes be optimized away. */ - ovfl = build (COMPONENT_REF, TREE_TYPE (f_ovfl), valist, f_ovfl, - NULL_TREE); + ovfl = build3 (COMPONENT_REF, TREE_TYPE (f_ovfl), valist, f_ovfl, + NULL_TREE); if (GET_MODE_CLASS (TYPE_MODE (type)) == MODE_FLOAT && GET_MODE_SIZE (TYPE_MODE (type)) <= UNITS_PER_FPVALUE) { - top = build (COMPONENT_REF, TREE_TYPE (f_ftop), valist, f_ftop, - NULL_TREE); - off = build (COMPONENT_REF, TREE_TYPE (f_foff), valist, f_foff, - NULL_TREE); + top = build3 (COMPONENT_REF, TREE_TYPE (f_ftop), valist, f_ftop, + NULL_TREE); + off = build3 (COMPONENT_REF, TREE_TYPE (f_foff), valist, f_foff, + NULL_TREE); /* When floating-point registers are saved to the stack, each one will take up UNITS_PER_HWFPVALUE bytes, regardless @@ -3957,42 +4256,42 @@ mips_gimplify_va_arg_expr (tree valist, tree type, tree *pre_p, tree *post_p) } else { - top = build (COMPONENT_REF, TREE_TYPE (f_gtop), valist, f_gtop, - NULL_TREE); - off = build (COMPONENT_REF, TREE_TYPE (f_goff), valist, f_goff, - NULL_TREE); + top = build3 (COMPONENT_REF, TREE_TYPE (f_gtop), valist, f_gtop, + NULL_TREE); + off = build3 (COMPONENT_REF, TREE_TYPE (f_goff), valist, f_goff, + NULL_TREE); if (rsize > UNITS_PER_WORD) { /* [1] Emit code for: off &= -rsize. */ - t = build (BIT_AND_EXPR, TREE_TYPE (off), off, - build_int_cst (NULL_TREE, -rsize)); - t = build (MODIFY_EXPR, TREE_TYPE (off), off, t); + t = build2 (BIT_AND_EXPR, TREE_TYPE (off), off, + build_int_cst (NULL_TREE, -rsize)); + t = build2 (MODIFY_EXPR, TREE_TYPE (off), off, t); gimplify_and_add (t, pre_p); } osize = rsize; } /* [2] Emit code to branch if off == 0. */ - t = build (NE_EXPR, boolean_type_node, off, - build_int_cst (TREE_TYPE (off), 0)); - addr = build (COND_EXPR, ptr_type_node, t, NULL, NULL); + t = build2 (NE_EXPR, boolean_type_node, off, + build_int_cst (TREE_TYPE (off), 0)); + addr = build3 (COND_EXPR, ptr_type_node, t, NULL_TREE, NULL_TREE); /* [5] Emit code for: off -= rsize. We do this as a form of post-increment not available to C. Also widen for the coming pointer arithmetic. */ t = fold_convert (TREE_TYPE (off), build_int_cst (NULL_TREE, rsize)); - t = build (POSTDECREMENT_EXPR, TREE_TYPE (off), off, t); + t = build2 (POSTDECREMENT_EXPR, TREE_TYPE (off), off, t); t = fold_convert (sizetype, t); t = fold_convert (TREE_TYPE (top), t); /* [4] Emit code for: addr_rtx = top - off. On big endian machines, the argument has RSIZE - SIZE bytes of leading padding. */ - t = build (MINUS_EXPR, TREE_TYPE (top), top, t); + t = build2 (MINUS_EXPR, TREE_TYPE (top), top, t); if (BYTES_BIG_ENDIAN && rsize > size) { u = fold_convert (TREE_TYPE (t), build_int_cst (NULL_TREE, rsize - size)); - t = build (PLUS_EXPR, TREE_TYPE (t), t, u); + t = build2 (PLUS_EXPR, TREE_TYPE (t), t, u); } COND_EXPR_THEN (addr) = t; @@ -4001,11 +4300,11 @@ mips_gimplify_va_arg_expr (tree valist, tree type, tree *pre_p, tree *post_p) /* [9] Emit: ovfl += ((intptr_t) ovfl + osize - 1) & -osize. */ u = fold_convert (TREE_TYPE (ovfl), build_int_cst (NULL_TREE, osize - 1)); - t = build (PLUS_EXPR, TREE_TYPE (ovfl), ovfl, u); + t = build2 (PLUS_EXPR, TREE_TYPE (ovfl), ovfl, u); u = fold_convert (TREE_TYPE (ovfl), build_int_cst (NULL_TREE, -osize)); - t = build (BIT_AND_EXPR, TREE_TYPE (ovfl), t, u); - align = build (MODIFY_EXPR, TREE_TYPE (ovfl), ovfl, t); + t = build2 (BIT_AND_EXPR, TREE_TYPE (ovfl), t, u); + align = build2 (MODIFY_EXPR, TREE_TYPE (ovfl), ovfl, t); } else align = NULL; @@ -4015,25 +4314,25 @@ mips_gimplify_va_arg_expr (tree valist, tree type, tree *pre_p, tree *post_p) the argument has OSIZE - SIZE bytes of leading padding. */ u = fold_convert (TREE_TYPE (ovfl), build_int_cst (NULL_TREE, osize)); - t = build (POSTINCREMENT_EXPR, TREE_TYPE (ovfl), ovfl, u); + t = build2 (POSTINCREMENT_EXPR, TREE_TYPE (ovfl), ovfl, u); if (BYTES_BIG_ENDIAN && osize > size) { u = fold_convert (TREE_TYPE (t), build_int_cst (NULL_TREE, osize - size)); - t = build (PLUS_EXPR, TREE_TYPE (t), t, u); + t = build2 (PLUS_EXPR, TREE_TYPE (t), t, u); } /* String [9] and [10,11] together. */ if (align) - t = build (COMPOUND_EXPR, TREE_TYPE (t), align, t); + t = build2 (COMPOUND_EXPR, TREE_TYPE (t), align, t); COND_EXPR_ELSE (addr) = t; addr = fold_convert (build_pointer_type (type), addr); - addr = build_fold_indirect_ref (addr); + addr = build_va_arg_indirect_ref (addr); } if (indirect) - addr = build_fold_indirect_ref (addr); + addr = build_va_arg_indirect_ref (addr); return addr; } @@ -4049,7 +4348,7 @@ mips_gimplify_va_arg_expr (tree valist, tree type, tree *pre_p, tree *post_p) left-side instructions (lwl, swl, ldl, sdl). *RIGHT is a QImode reference to the opposite end of the field and - can be used in the parterning right-side instruction. */ + can be used in the patterning right-side instruction. */ static bool mips_get_unaligned_mem (rtx *op, unsigned int width, int bitpos, @@ -4165,7 +4464,39 @@ mips_expand_unaligned_store (rtx dest, rtx src, unsigned int width, int bitpos) } return true; } - + +/* Return true if (zero_extract OP SIZE POSITION) can be used as the + source of an "ext" instruction or the destination of an "ins" + instruction. OP must be a register operand and the following + conditions must hold: + + 0 <= POSITION < GET_MODE_BITSIZE (GET_MODE (op)) + 0 < SIZE <= GET_MODE_BITSIZE (GET_MODE (op)) + 0 < POSITION + SIZE <= GET_MODE_BITSIZE (GET_MODE (op)) + + Also reject lengths equal to a word as they are better handled + by the move patterns. */ + +bool +mips_use_ins_ext_p (rtx op, rtx size, rtx position) +{ + HOST_WIDE_INT len, pos; + + if (!ISA_HAS_EXT_INS + || !register_operand (op, VOIDmode) + || GET_MODE_BITSIZE (GET_MODE (op)) > BITS_PER_WORD) + return false; + + len = INTVAL (size); + pos = INTVAL (position); + + if (len <= 0 || len >= GET_MODE_BITSIZE (GET_MODE (op)) + || pos < 0 || pos + len > GET_MODE_BITSIZE (GET_MODE (op))) + return false; + + return true; +} + /* Set up globals to generate code for the ISA or processor described by INFO. */ @@ -4216,21 +4547,13 @@ mips_handle_option (size_t code, const char *arg, int value ATTRIBUTE_UNUSED) return true; case OPT_march_: - mips_arch_string = arg; - return mips_parse_cpu (arg) != 0; - case OPT_mtune_: - mips_tune_string = arg; return mips_parse_cpu (arg) != 0; case OPT_mips: mips_isa_info = mips_parse_cpu (ACONCAT (("mips", arg, NULL))); return mips_isa_info != 0; - case OPT_mflush_func_: - mips_cache_flush_func = arg; - return true; - case OPT_mno_flush_func: mips_cache_flush_func = NULL; return true; @@ -4289,6 +4612,9 @@ override_options (void) if (mips_tune_info == 0) mips_set_tune (mips_arch_info); + /* Set cost structure for the processor. */ + mips_cost = &mips_rtx_cost_data[mips_tune]; + if ((target_flags_explicit & MASK_64BIT) != 0) { /* The user specified the size of the integer registers. Make sure @@ -4336,25 +4662,12 @@ override_options (void) if ((target_flags_explicit & MASK_LONG64) == 0) { - if (TARGET_INT64) - target_flags |= MASK_LONG64; - /* If no type size setting options (-mlong64,-mint64,-mlong32) - were used, then set the type sizes. In the EABI in 64 bit mode, - longs and pointers are 64 bits. Likewise for the SGI Irix6 N64 - ABI. */ - else if ((mips_abi == ABI_EABI && TARGET_64BIT) || mips_abi == ABI_64) + if ((mips_abi == ABI_EABI && TARGET_64BIT) || mips_abi == ABI_64) target_flags |= MASK_LONG64; else target_flags &= ~MASK_LONG64; } - /* Deprecate -mint64. Remove after 4.0 branches. */ - if (TARGET_INT64) - warning (0, "-mint64 is a deprecated option"); - - if (TARGET_INT64 && !TARGET_LONG64) - error ("unsupported combination: %s", "-mint64 -mlong32"); - if (MIPS_MARCH_CONTROLS_SOFT_FLOAT && (target_flags_explicit & MASK_SOFT_FLOAT) == 0) { @@ -4504,6 +4817,9 @@ override_options (void) if (TARGET_PAIRED_SINGLE_FLOAT && !ISA_MIPS64) error ("-mips3d/-mpaired-single must be used with -mips64"); + if (TARGET_MIPS16 && TARGET_DSP) + error ("-mips16 and -mdsp cannot be used together"); + mips_print_operand_punct['?'] = 1; mips_print_operand_punct['#'] = 1; mips_print_operand_punct['/'] = 1; @@ -4525,25 +4841,6 @@ override_options (void) mips_print_operand_punct['+'] = 1; mips_print_operand_punct['~'] = 1; - mips_char_to_class['d'] = TARGET_MIPS16 ? M16_REGS : GR_REGS; - mips_char_to_class['t'] = T_REG; - mips_char_to_class['f'] = (TARGET_HARD_FLOAT ? FP_REGS : NO_REGS); - mips_char_to_class['h'] = HI_REG; - mips_char_to_class['l'] = LO_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['e'] = LEA_REGS; - mips_char_to_class['j'] = PIC_FN_ADDR_REG; - mips_char_to_class['v'] = V1_REG; - mips_char_to_class['y'] = GR_REGS; - mips_char_to_class['z'] = ST_REGS; - mips_char_to_class['B'] = COP0_REGS; - mips_char_to_class['C'] = COP2_REGS; - mips_char_to_class['D'] = COP3_REGS; - /* Set up array to map GCC register number to debug register number. Ignore the special purpose register numbers. */ @@ -4603,15 +4900,20 @@ override_options (void) && size <= UNITS_PER_FPVALUE) /* Allow integer modes that fit into a single register. We need to put integers into FPRs - when using instructions like cvt and trunc. */ - || (class == MODE_INT && size <= UNITS_PER_FPREG) + when using instructions like cvt and trunc. + We can't allow sizes smaller than a word, + the FPU has no appropriate load/store + instructions for those. */ + || (class == MODE_INT + && size >= MIN_UNITS_PER_WORD + && size <= UNITS_PER_FPREG) /* Allow TFmode for CCmode reloads. */ || (ISA_HAS_8CC && mode == TFmode)); - else if (MD_REG_P (regno)) + else if (ACC_REG_P (regno)) temp = (INTEGRAL_MODE_P (mode) && (size <= UNITS_PER_WORD - || (regno == MD_REG_FIRST + || (ACC_HI_REG_P (regno) && size == 2 * UNITS_PER_WORD))); else if (ALL_COP_REG_P (regno)) @@ -4760,6 +5062,13 @@ override_options (void) void mips_conditional_register_usage (void) { + if (!TARGET_DSP) + { + int regno; + + for (regno = DSP_ACC_REG_FIRST; regno <= DSP_ACC_REG_LAST; regno++) + fixed_regs[regno] = call_used_regs[regno] = 1; + } if (!TARGET_HARD_FLOAT) { int regno; @@ -4904,6 +5213,7 @@ mips_debugger_offset (rtx addr, HOST_WIDE_INT offset) 'Y' for a CONST_INT X, print mips_fp_conditions[X] 'Z' print the operand and a comma for ISA_HAS_8CC, otherwise print nothing 'R' print the reloc associated with LO_SUM + 'q' print DSP accumulator registers The punctuation characters are: @@ -5154,6 +5464,22 @@ print_operand (FILE *file, rtx op, int letter) } } + else if (letter == 'q') + { + int regnum; + + if (code != REG) + fatal_insn ("PRINT_OPERAND, invalid insn for %%q", op); + + regnum = REGNO (op); + if (MD_REG_P (regnum)) + fprintf (file, "$ac0"); + else if (DSP_ACC_REG_P (regnum)) + fprintf (file, "$ac%c", reg_names[regnum][3]); + else + fatal_insn ("PRINT_OPERAND, invalid insn for %%q", op); + } + else if (code == REG || code == SUBREG) { register int regnum; @@ -5425,7 +5751,7 @@ mips_file_start (void) default: gcc_unreachable (); } - /* Note - we use fprintf directly rather than called named_section() + /* Note - we use fprintf directly rather than calling switch_to_section because in this way we can avoid creating an allocated section. We do not want this section to take up any space in the running executable. */ @@ -5467,9 +5793,9 @@ mips_output_aligned_bss (FILE *stream, tree decl, const char *name, extern tree last_assemble_variable_decl; if (mips_in_small_data_p (decl)) - named_section (0, ".sbss", 0); + switch_to_section (get_named_section (NULL, ".sbss", 0)); else - bss_section (); + switch_to_section (bss_section); ASM_OUTPUT_ALIGN (stream, floor_log2 (align / BITS_PER_UNIT)); last_assemble_variable_decl = decl; ASM_DECLARE_OBJECT_NAME (stream, name, decl); @@ -5538,7 +5864,7 @@ mips_output_aligned_decl_common (FILE *stream, tree decl, const char *name, if (TREE_PUBLIC (decl) && DECL_NAME (decl)) targetm.asm_out.globalize_label (stream, name); - readonly_data_section (); + switch_to_section (readonly_data_section); ASM_OUTPUT_ALIGN (stream, floor_log2 (align / BITS_PER_UNIT)); mips_declare_object (stream, name, "", ":\n\t.space\t" HOST_WIDE_INT_PRINT_UNSIGNED "\n", @@ -5623,7 +5949,7 @@ mips_declare_object_name (FILE *stream, const char *name, ASM_OUTPUT_SIZE_DIRECTIVE (stream, name, size); } - mips_declare_object (stream, name, "", ":\n", 0); + mips_declare_object (stream, name, "", ":\n"); } /* Implement ASM_FINISH_DECLARE_OBJECT. This is generic ELF stuff. */ @@ -5847,7 +6173,7 @@ mips_save_reg_p (unsigned int regno) /* Return the bytes needed to compute the frame pointer from the current stack pointer. SIZE is the size (in bytes) of the local variables. - Mips stack frames look like: + MIPS stack frames look like: Before call After call +-----------------------+ +-----------------------+ @@ -5975,10 +6301,9 @@ compute_frame_size (HOST_WIDE_INT size) gp_reg_rounded = MIPS_STACK_ALIGN (gp_reg_size); total_size += gp_reg_rounded + MIPS_STACK_ALIGN (fp_reg_size); - /* Add in space reserved on the stack by the callee for storing arguments - passed in registers. */ - if (!TARGET_OLDABI) - total_size += MIPS_STACK_ALIGN (current_function_pretend_args_size); + /* Add in the space required for saving incoming register arguments. */ + total_size += current_function_pretend_args_size; + total_size += MIPS_STACK_ALIGN (cfun->machine->varargs_size); /* Save other computed information. */ cfun->machine->frame.total_size = total_size; @@ -6047,9 +6372,8 @@ mips_initial_elimination_offset (int from, int to) break; case ARG_POINTER_REGNUM: - offset = cfun->machine->frame.total_size; - if (TARGET_NEWABI) - offset -= current_function_pretend_args_size; + offset = (cfun->machine->frame.total_size + - current_function_pretend_args_size); break; default: @@ -6401,10 +6725,23 @@ mips_expand_prologue (void) if (TARGET_MIPS16 && cfun->machine->frame.args_size != 0) { rtx offset = GEN_INT (cfun->machine->frame.args_size); - RTX_FRAME_RELATED_P - (emit_insn (gen_add3_insn (hard_frame_pointer_rtx, - stack_pointer_rtx, - offset))) = 1; + if (SMALL_OPERAND (cfun->machine->frame.args_size)) + RTX_FRAME_RELATED_P + (emit_insn (gen_add3_insn (hard_frame_pointer_rtx, + stack_pointer_rtx, + offset))) = 1; + else + { + emit_move_insn (MIPS_PROLOGUE_TEMP (Pmode), offset); + emit_move_insn (hard_frame_pointer_rtx, stack_pointer_rtx); + emit_insn (gen_add3_insn (hard_frame_pointer_rtx, + hard_frame_pointer_rtx, + MIPS_PROLOGUE_TEMP (Pmode))); + mips_set_frame_expr + (gen_rtx_SET (VOIDmode, hard_frame_pointer_rtx, + plus_constant (stack_pointer_rtx, + cfun->machine->frame.args_size))); + } } else RTX_FRAME_RELATED_P (emit_move_insn (hard_frame_pointer_rtx, @@ -6762,7 +7099,7 @@ symbolic_expression_p (rtx x) /* Choose the section to use for the constant rtx expression X that has mode MODE. */ -static void +static section * mips_select_rtx_section (enum machine_mode mode, rtx x, unsigned HOST_WIDE_INT align) { @@ -6771,13 +7108,13 @@ mips_select_rtx_section (enum machine_mode mode, rtx x, /* In mips16 mode, the constant table always goes in the same section as the function, so that constants can be loaded using PC relative addressing. */ - function_section (current_function_decl); + return function_section (current_function_decl); } else if (TARGET_EMBEDDED_DATA) { /* For embedded applications, always put constants in read-only data, in order to reduce RAM usage. */ - mergeable_constant_section (mode, align, 0); + return mergeable_constant_section (mode, align, 0); } else { @@ -6787,11 +7124,11 @@ mips_select_rtx_section (enum machine_mode mode, rtx x, if (GET_MODE_SIZE (mode) <= (unsigned) mips_section_threshold && mips_section_threshold > 0) - named_section (0, ".sdata", 0); + return get_named_section (NULL, ".sdata", 0); else if (flag_pic && symbolic_expression_p (x)) - named_section (0, ".data.rel.ro", 3); + return get_named_section (NULL, ".data.rel.ro", 3); else - mergeable_constant_section (mode, align, 0); + return mergeable_constant_section (mode, align, 0); } } @@ -6803,32 +7140,30 @@ mips_select_rtx_section (enum machine_mode mode, rtx x, cases by selecting a normal data section instead of a read-only one. The logic apes that in default_function_rodata_section. */ -static void +static section * mips_function_rodata_section (tree decl) { if (!TARGET_ABICALLS || TARGET_GPWORD) - default_function_rodata_section (decl); - else if (decl && DECL_SECTION_NAME (decl)) + return default_function_rodata_section (decl); + + if (decl && DECL_SECTION_NAME (decl)) { const char *name = TREE_STRING_POINTER (DECL_SECTION_NAME (decl)); if (DECL_ONE_ONLY (decl) && strncmp (name, ".gnu.linkonce.t.", 16) == 0) { char *rname = ASTRDUP (name); rname[14] = 'd'; - named_section_real (rname, SECTION_LINKONCE | SECTION_WRITE, decl); + return get_section (rname, SECTION_LINKONCE | SECTION_WRITE, decl); } else if (flag_function_sections && flag_data_sections && strncmp (name, ".text.", 6) == 0) { char *rname = ASTRDUP (name); memcpy (rname + 1, "data", 4); - named_section_flags (rname, SECTION_WRITE); + return get_section (rname, SECTION_WRITE, decl); } - else - data_section (); } - else - data_section (); + return data_section; } /* Implement TARGET_IN_SMALL_DATA_P. Return true if it would be safe to @@ -7100,8 +7435,10 @@ mips_cannot_change_mode_class (enum machine_mode from, /* LO_REGNO == HI_REGNO + 1, so if a multi-word value is stored in LO and HI, the high word always comes first. We therefore can't allow values stored in HI to change between single-word - and multi-word modes. */ - if (reg_classes_intersect_p (HI_REG, class)) + and multi-word modes. + This rule applies to both the original HI/LO pair and the new + DSP accumulators. */ + if (reg_classes_intersect_p (ACC_REGS, class)) return true; } } @@ -7182,8 +7519,10 @@ mips_secondary_reload_class (enum reg_class class, } /* Copying from HI or LO to anywhere other than a general register - requires a general register. */ - if (class == HI_REG || class == LO_REG || class == MD_REGS) + requires a general register. + This rule applies to both the original HI/LO pair and the new + DSP accumulators. */ + if (reg_class_subset_p (class, ACC_REGS)) { if (TARGET_MIPS16 && in_p) { @@ -7192,7 +7531,7 @@ mips_secondary_reload_class (enum reg_class class, } return gp_reg_p ? NO_REGS : gr_regs; } - if (MD_REG_P (regno)) + if (ACC_REG_P (regno)) { if (TARGET_MIPS16 && ! in_p) { @@ -7298,52 +7637,24 @@ mips_valid_pointer_mode (enum machine_mode mode) return (mode == SImode || (TARGET_64BIT && mode == DImode)); } -/* Define this so that we can deal with a testcase like: - - char foo __attribute__ ((mode (SI))); - - then compiled with -mabi=64 and -mint64. We have no - 32-bit type at that point and so the default case - always fails. */ +/* Target hook for vector_mode_supported_p. */ static bool -mips_scalar_mode_supported_p (enum machine_mode mode) +mips_vector_mode_supported_p (enum machine_mode mode) { switch (mode) { - case QImode: - case HImode: - case SImode: - case DImode: - return true; + case V2SFmode: + return TARGET_PAIRED_SINGLE_FLOAT; - /* Handled via optabs.c. */ - case TImode: - return TARGET_64BIT; - - case SFmode: - case DFmode: - return true; - - /* LONG_DOUBLE_TYPE_SIZE is 128 for TARGET_NEWABI only. */ - case TFmode: - return TARGET_NEWABI; + case V2HImode: + case V4QImode: + return TARGET_DSP; default: return false; } } - - -/* Target hook for vector_mode_supported_p. */ -static bool -mips_vector_mode_supported_p (enum machine_mode mode) -{ - if (mode == V2SFmode && TARGET_PAIRED_SINGLE_FLOAT) - return true; - else - return false; -} /* If we can access small data directly (using gp-relative relocation operators) return the small data pointer, otherwise return null. @@ -7483,7 +7794,7 @@ build_mips16_function_stub (FILE *file) fprintf (file, ")\n"); fprintf (file, "\t.set\tnomips16\n"); - function_section (stubdecl); + switch_to_section (function_section (stubdecl)); ASM_OUTPUT_ALIGN (file, floor_log2 (FUNCTION_BOUNDARY / BITS_PER_UNIT)); /* ??? If FUNCTION_NAME_ALREADY_DECLARED is defined, then we are @@ -7528,7 +7839,7 @@ build_mips16_function_stub (FILE *file) fprintf (file, "\t.set\tmips16\n"); - function_section (current_function_decl); + switch_to_section (function_section (current_function_decl)); } /* We keep a list of functions for which we have already built stubs @@ -8587,7 +8898,7 @@ mips_reorg (void) else if (TARGET_EXPLICIT_RELOCS) { if (mips_flag_delayed_branch) - dbr_schedule (get_insns (), dump_file); + dbr_schedule (get_insns ()); mips_avoid_hazards (); if (TUNE_MIPS4130 && TARGET_VR4130_ALIGN) vr4130_align_insns (); @@ -8707,7 +9018,7 @@ mips_register_move_cost (enum machine_mode mode ATTRIBUTE_UNUSED, } else if (to == FP_REGS) return 4; - else if (to == HI_REG || to == LO_REG || to == MD_REGS) + else if (reg_class_subset_p (to, ACC_REGS)) { if (TARGET_MIPS16) return 12; @@ -8718,7 +9029,7 @@ mips_register_move_cost (enum machine_mode mode ATTRIBUTE_UNUSED, { return 5; } - } /* GR_REG_CLASS_P (from) */ + } else if (from == FP_REGS) { if (GR_REG_CLASS_P (to)) @@ -8727,8 +9038,8 @@ mips_register_move_cost (enum machine_mode mode ATTRIBUTE_UNUSED, return 2; else if (to == ST_REGS) return 8; - } /* from == FP_REGS */ - else if (from == HI_REG || from == LO_REG || from == MD_REGS) + } + else if (reg_class_subset_p (from, ACC_REGS)) { if (GR_REG_CLASS_P (to)) { @@ -8737,15 +9048,16 @@ mips_register_move_cost (enum machine_mode mode ATTRIBUTE_UNUSED, else return 6; } - } /* from == HI_REG, etc. */ + } else if (from == ST_REGS && GR_REG_CLASS_P (to)) return 4; else if (COP_REG_CLASS_P (from)) { return 5; - } /* COP_REG_CLASS_P (from) */ + } - /* Fall through. */ + /* Fall through. + ??? What cases are these? Shouldn't we return 2 here? */ return 12; } @@ -9729,6 +10041,116 @@ static const struct builtin_description sb1_bdesc[] = DIRECT_BUILTIN (sqrt_ps, MIPS_V2SF_FTYPE_V2SF, MASK_PAIRED_SINGLE_FLOAT) }; +/* Builtin functions for DSP ASE. */ + +#define CODE_FOR_mips_addq_ph CODE_FOR_addv2hi3 +#define CODE_FOR_mips_addu_qb CODE_FOR_addv4qi3 +#define CODE_FOR_mips_subq_ph CODE_FOR_subv2hi3 +#define CODE_FOR_mips_subu_qb CODE_FOR_subv4qi3 + +/* Define a MIPS_BUILTIN_DIRECT_NO_TARGET function for instruction + CODE_FOR_mips_. FUNCTION_TYPE and TARGET_FLAGS are + builtin_description fields. */ +#define DIRECT_NO_TARGET_BUILTIN(INSN, FUNCTION_TYPE, TARGET_FLAGS) \ + { CODE_FOR_mips_ ## INSN, 0, "__builtin_mips_" #INSN, \ + MIPS_BUILTIN_DIRECT_NO_TARGET, FUNCTION_TYPE, TARGET_FLAGS } + +/* Define __builtin_mips_bposge. is 32 for the MIPS32 DSP + branch instruction. TARGET_FLAGS is a builtin_description field. */ +#define BPOSGE_BUILTIN(VALUE, TARGET_FLAGS) \ + { CODE_FOR_mips_bposge, 0, "__builtin_mips_bposge" #VALUE, \ + MIPS_BUILTIN_BPOSGE ## VALUE, MIPS_SI_FTYPE_VOID, TARGET_FLAGS } + +static const struct builtin_description dsp_bdesc[] = +{ + DIRECT_BUILTIN (addq_ph, MIPS_V2HI_FTYPE_V2HI_V2HI, MASK_DSP), + DIRECT_BUILTIN (addq_s_ph, MIPS_V2HI_FTYPE_V2HI_V2HI, MASK_DSP), + DIRECT_BUILTIN (addq_s_w, MIPS_SI_FTYPE_SI_SI, MASK_DSP), + DIRECT_BUILTIN (addu_qb, MIPS_V4QI_FTYPE_V4QI_V4QI, MASK_DSP), + DIRECT_BUILTIN (addu_s_qb, MIPS_V4QI_FTYPE_V4QI_V4QI, MASK_DSP), + DIRECT_BUILTIN (subq_ph, MIPS_V2HI_FTYPE_V2HI_V2HI, MASK_DSP), + DIRECT_BUILTIN (subq_s_ph, MIPS_V2HI_FTYPE_V2HI_V2HI, MASK_DSP), + DIRECT_BUILTIN (subq_s_w, MIPS_SI_FTYPE_SI_SI, MASK_DSP), + DIRECT_BUILTIN (subu_qb, MIPS_V4QI_FTYPE_V4QI_V4QI, MASK_DSP), + DIRECT_BUILTIN (subu_s_qb, MIPS_V4QI_FTYPE_V4QI_V4QI, MASK_DSP), + DIRECT_BUILTIN (addsc, MIPS_SI_FTYPE_SI_SI, MASK_DSP), + DIRECT_BUILTIN (addwc, MIPS_SI_FTYPE_SI_SI, MASK_DSP), + DIRECT_BUILTIN (modsub, MIPS_SI_FTYPE_SI_SI, MASK_DSP), + DIRECT_BUILTIN (raddu_w_qb, MIPS_SI_FTYPE_V4QI, MASK_DSP), + DIRECT_BUILTIN (absq_s_ph, MIPS_V2HI_FTYPE_V2HI, MASK_DSP), + DIRECT_BUILTIN (absq_s_w, MIPS_SI_FTYPE_SI, MASK_DSP), + DIRECT_BUILTIN (precrq_qb_ph, MIPS_V4QI_FTYPE_V2HI_V2HI, MASK_DSP), + DIRECT_BUILTIN (precrq_ph_w, MIPS_V2HI_FTYPE_SI_SI, MASK_DSP), + DIRECT_BUILTIN (precrq_rs_ph_w, MIPS_V2HI_FTYPE_SI_SI, MASK_DSP), + DIRECT_BUILTIN (precrqu_s_qb_ph, MIPS_V4QI_FTYPE_V2HI_V2HI, MASK_DSP), + DIRECT_BUILTIN (preceq_w_phl, MIPS_SI_FTYPE_V2HI, MASK_DSP), + DIRECT_BUILTIN (preceq_w_phr, MIPS_SI_FTYPE_V2HI, MASK_DSP), + DIRECT_BUILTIN (precequ_ph_qbl, MIPS_V2HI_FTYPE_V4QI, MASK_DSP), + DIRECT_BUILTIN (precequ_ph_qbr, MIPS_V2HI_FTYPE_V4QI, MASK_DSP), + DIRECT_BUILTIN (precequ_ph_qbla, MIPS_V2HI_FTYPE_V4QI, MASK_DSP), + DIRECT_BUILTIN (precequ_ph_qbra, MIPS_V2HI_FTYPE_V4QI, MASK_DSP), + DIRECT_BUILTIN (preceu_ph_qbl, MIPS_V2HI_FTYPE_V4QI, MASK_DSP), + DIRECT_BUILTIN (preceu_ph_qbr, MIPS_V2HI_FTYPE_V4QI, MASK_DSP), + DIRECT_BUILTIN (preceu_ph_qbla, MIPS_V2HI_FTYPE_V4QI, MASK_DSP), + DIRECT_BUILTIN (preceu_ph_qbra, MIPS_V2HI_FTYPE_V4QI, MASK_DSP), + DIRECT_BUILTIN (shll_qb, MIPS_V4QI_FTYPE_V4QI_SI, MASK_DSP), + DIRECT_BUILTIN (shll_ph, MIPS_V2HI_FTYPE_V2HI_SI, MASK_DSP), + DIRECT_BUILTIN (shll_s_ph, MIPS_V2HI_FTYPE_V2HI_SI, MASK_DSP), + DIRECT_BUILTIN (shll_s_w, MIPS_SI_FTYPE_SI_SI, MASK_DSP), + DIRECT_BUILTIN (shrl_qb, MIPS_V4QI_FTYPE_V4QI_SI, MASK_DSP), + DIRECT_BUILTIN (shra_ph, MIPS_V2HI_FTYPE_V2HI_SI, MASK_DSP), + DIRECT_BUILTIN (shra_r_ph, MIPS_V2HI_FTYPE_V2HI_SI, MASK_DSP), + DIRECT_BUILTIN (shra_r_w, MIPS_SI_FTYPE_SI_SI, MASK_DSP), + DIRECT_BUILTIN (muleu_s_ph_qbl, MIPS_V2HI_FTYPE_V4QI_V2HI, MASK_DSP), + DIRECT_BUILTIN (muleu_s_ph_qbr, MIPS_V2HI_FTYPE_V4QI_V2HI, MASK_DSP), + DIRECT_BUILTIN (mulq_rs_ph, MIPS_V2HI_FTYPE_V2HI_V2HI, MASK_DSP), + DIRECT_BUILTIN (muleq_s_w_phl, MIPS_SI_FTYPE_V2HI_V2HI, MASK_DSP), + DIRECT_BUILTIN (muleq_s_w_phr, MIPS_SI_FTYPE_V2HI_V2HI, MASK_DSP), + DIRECT_BUILTIN (dpau_h_qbl, MIPS_DI_FTYPE_DI_V4QI_V4QI, MASK_DSP), + DIRECT_BUILTIN (dpau_h_qbr, MIPS_DI_FTYPE_DI_V4QI_V4QI, MASK_DSP), + DIRECT_BUILTIN (dpsu_h_qbl, MIPS_DI_FTYPE_DI_V4QI_V4QI, MASK_DSP), + DIRECT_BUILTIN (dpsu_h_qbr, MIPS_DI_FTYPE_DI_V4QI_V4QI, MASK_DSP), + DIRECT_BUILTIN (dpaq_s_w_ph, MIPS_DI_FTYPE_DI_V2HI_V2HI, MASK_DSP), + DIRECT_BUILTIN (dpsq_s_w_ph, MIPS_DI_FTYPE_DI_V2HI_V2HI, MASK_DSP), + DIRECT_BUILTIN (mulsaq_s_w_ph, MIPS_DI_FTYPE_DI_V2HI_V2HI, MASK_DSP), + DIRECT_BUILTIN (dpaq_sa_l_w, MIPS_DI_FTYPE_DI_SI_SI, MASK_DSP), + DIRECT_BUILTIN (dpsq_sa_l_w, MIPS_DI_FTYPE_DI_SI_SI, MASK_DSP), + DIRECT_BUILTIN (maq_s_w_phl, MIPS_DI_FTYPE_DI_V2HI_V2HI, MASK_DSP), + DIRECT_BUILTIN (maq_s_w_phr, MIPS_DI_FTYPE_DI_V2HI_V2HI, MASK_DSP), + DIRECT_BUILTIN (maq_sa_w_phl, MIPS_DI_FTYPE_DI_V2HI_V2HI, MASK_DSP), + DIRECT_BUILTIN (maq_sa_w_phr, MIPS_DI_FTYPE_DI_V2HI_V2HI, MASK_DSP), + DIRECT_BUILTIN (bitrev, MIPS_SI_FTYPE_SI, MASK_DSP), + DIRECT_BUILTIN (insv, MIPS_SI_FTYPE_SI_SI, MASK_DSP), + DIRECT_BUILTIN (repl_qb, MIPS_V4QI_FTYPE_SI, MASK_DSP), + DIRECT_BUILTIN (repl_ph, MIPS_V2HI_FTYPE_SI, MASK_DSP), + DIRECT_NO_TARGET_BUILTIN (cmpu_eq_qb, MIPS_VOID_FTYPE_V4QI_V4QI, MASK_DSP), + DIRECT_NO_TARGET_BUILTIN (cmpu_lt_qb, MIPS_VOID_FTYPE_V4QI_V4QI, MASK_DSP), + DIRECT_NO_TARGET_BUILTIN (cmpu_le_qb, MIPS_VOID_FTYPE_V4QI_V4QI, MASK_DSP), + DIRECT_BUILTIN (cmpgu_eq_qb, MIPS_SI_FTYPE_V4QI_V4QI, MASK_DSP), + DIRECT_BUILTIN (cmpgu_lt_qb, MIPS_SI_FTYPE_V4QI_V4QI, MASK_DSP), + DIRECT_BUILTIN (cmpgu_le_qb, MIPS_SI_FTYPE_V4QI_V4QI, MASK_DSP), + DIRECT_NO_TARGET_BUILTIN (cmp_eq_ph, MIPS_VOID_FTYPE_V2HI_V2HI, MASK_DSP), + DIRECT_NO_TARGET_BUILTIN (cmp_lt_ph, MIPS_VOID_FTYPE_V2HI_V2HI, MASK_DSP), + DIRECT_NO_TARGET_BUILTIN (cmp_le_ph, MIPS_VOID_FTYPE_V2HI_V2HI, MASK_DSP), + DIRECT_BUILTIN (pick_qb, MIPS_V4QI_FTYPE_V4QI_V4QI, MASK_DSP), + DIRECT_BUILTIN (pick_ph, MIPS_V2HI_FTYPE_V2HI_V2HI, MASK_DSP), + DIRECT_BUILTIN (packrl_ph, MIPS_V2HI_FTYPE_V2HI_V2HI, MASK_DSP), + DIRECT_BUILTIN (extr_w, MIPS_SI_FTYPE_DI_SI, MASK_DSP), + DIRECT_BUILTIN (extr_r_w, MIPS_SI_FTYPE_DI_SI, MASK_DSP), + DIRECT_BUILTIN (extr_rs_w, MIPS_SI_FTYPE_DI_SI, MASK_DSP), + DIRECT_BUILTIN (extr_s_h, MIPS_SI_FTYPE_DI_SI, MASK_DSP), + DIRECT_BUILTIN (extp, MIPS_SI_FTYPE_DI_SI, MASK_DSP), + DIRECT_BUILTIN (extpdp, MIPS_SI_FTYPE_DI_SI, MASK_DSP), + DIRECT_BUILTIN (shilo, MIPS_DI_FTYPE_DI_SI, MASK_DSP), + DIRECT_BUILTIN (mthlip, MIPS_DI_FTYPE_DI_SI, MASK_DSP), + DIRECT_NO_TARGET_BUILTIN (wrdsp, MIPS_VOID_FTYPE_SI_SI, MASK_DSP), + DIRECT_BUILTIN (rddsp, MIPS_SI_FTYPE_SI, MASK_DSP), + DIRECT_BUILTIN (lbux, MIPS_SI_FTYPE_PTR_SI, MASK_DSP), + DIRECT_BUILTIN (lhx, MIPS_SI_FTYPE_PTR_SI, MASK_DSP), + DIRECT_BUILTIN (lwx, MIPS_SI_FTYPE_PTR_SI, MASK_DSP), + BPOSGE_BUILTIN (32, MASK_DSP) +}; + /* This helps provide a mapping from builtin function codes to bdesc arrays. */ @@ -9741,14 +10163,15 @@ struct bdesc_map unsigned int size; /* The target processor that supports these builtin functions. - PROCESSOR_DEFAULT means we enable them for all processors. */ + PROCESSOR_MAX means we enable them for all processors. */ enum processor_type proc; }; static const struct bdesc_map bdesc_arrays[] = { - { mips_bdesc, ARRAY_SIZE (mips_bdesc), PROCESSOR_DEFAULT }, - { sb1_bdesc, ARRAY_SIZE (sb1_bdesc), PROCESSOR_SB1 } + { mips_bdesc, ARRAY_SIZE (mips_bdesc), PROCESSOR_MAX }, + { sb1_bdesc, ARRAY_SIZE (sb1_bdesc), PROCESSOR_SB1 }, + { dsp_bdesc, ARRAY_SIZE (dsp_bdesc), PROCESSOR_MAX } }; /* Take the head of argument list *ARGLIST and convert it into a form @@ -9762,10 +10185,18 @@ mips_prepare_builtin_arg (enum insn_code icode, rtx value; enum machine_mode mode; - value = expand_expr (TREE_VALUE (*arglist), NULL_RTX, VOIDmode, 0); + value = expand_normal (TREE_VALUE (*arglist)); mode = insn_data[icode].operand[op].mode; if (!insn_data[icode].operand[op].predicate (value, mode)) - value = copy_to_mode_reg (mode, value); + { + value = copy_to_mode_reg (mode, value); + /* Check the predicate again. */ + if (!insn_data[icode].operand[op].predicate (value, mode)) + { + error ("invalid argument to builtin function"); + return const0_rtx; + } + } *arglist = TREE_CHAIN (*arglist); return value; @@ -9822,7 +10253,10 @@ mips_expand_builtin (tree exp, rtx target, rtx subtarget ATTRIBUTE_UNUSED, switch (type) { case MIPS_BUILTIN_DIRECT: - return mips_expand_builtin_direct (icode, target, arglist); + return mips_expand_builtin_direct (icode, target, arglist, true); + + case MIPS_BUILTIN_DIRECT_NO_TARGET: + return mips_expand_builtin_direct (icode, target, arglist, false); case MIPS_BUILTIN_MOVT: case MIPS_BUILTIN_MOVF: @@ -9837,6 +10271,9 @@ mips_expand_builtin (tree exp, rtx target, rtx subtarget ATTRIBUTE_UNUSED, return mips_expand_builtin_compare (type, icode, bdesc[fcode].cond, target, arglist); + case MIPS_BUILTIN_BPOSGE32: + return mips_expand_builtin_bposge (type, target); + default: return 0; } @@ -9851,70 +10288,214 @@ mips_init_builtins (void) const struct bdesc_map *m; tree types[(int) MIPS_MAX_FTYPE_MAX]; tree V2SF_type_node; + tree V2HI_type_node; + tree V4QI_type_node; unsigned int offset; - /* We have only builtins for -mpaired-single and -mips3d. */ - if (!TARGET_PAIRED_SINGLE_FLOAT) + /* We have only builtins for -mpaired-single, -mips3d and -mdsp. */ + if (!TARGET_PAIRED_SINGLE_FLOAT && !TARGET_DSP) return; - V2SF_type_node = build_vector_type_for_mode (float_type_node, V2SFmode); - - types[MIPS_V2SF_FTYPE_V2SF] - = build_function_type_list (V2SF_type_node, V2SF_type_node, NULL_TREE); - - types[MIPS_V2SF_FTYPE_V2SF_V2SF] - = build_function_type_list (V2SF_type_node, - V2SF_type_node, V2SF_type_node, NULL_TREE); - - types[MIPS_V2SF_FTYPE_V2SF_V2SF_INT] - = build_function_type_list (V2SF_type_node, - V2SF_type_node, V2SF_type_node, - integer_type_node, NULL_TREE); - - types[MIPS_V2SF_FTYPE_V2SF_V2SF_V2SF_V2SF] - = build_function_type_list (V2SF_type_node, - V2SF_type_node, V2SF_type_node, - V2SF_type_node, V2SF_type_node, NULL_TREE); + if (TARGET_PAIRED_SINGLE_FLOAT) + { + V2SF_type_node = build_vector_type_for_mode (float_type_node, V2SFmode); - types[MIPS_V2SF_FTYPE_SF_SF] - = build_function_type_list (V2SF_type_node, - float_type_node, float_type_node, NULL_TREE); + types[MIPS_V2SF_FTYPE_V2SF] + = build_function_type_list (V2SF_type_node, V2SF_type_node, NULL_TREE); - types[MIPS_INT_FTYPE_V2SF_V2SF] - = build_function_type_list (integer_type_node, - V2SF_type_node, V2SF_type_node, NULL_TREE); + types[MIPS_V2SF_FTYPE_V2SF_V2SF] + = build_function_type_list (V2SF_type_node, + V2SF_type_node, V2SF_type_node, NULL_TREE); - types[MIPS_INT_FTYPE_V2SF_V2SF_V2SF_V2SF] - = build_function_type_list (integer_type_node, - V2SF_type_node, V2SF_type_node, - V2SF_type_node, V2SF_type_node, NULL_TREE); + types[MIPS_V2SF_FTYPE_V2SF_V2SF_INT] + = build_function_type_list (V2SF_type_node, + V2SF_type_node, V2SF_type_node, + integer_type_node, NULL_TREE); - types[MIPS_INT_FTYPE_SF_SF] - = build_function_type_list (integer_type_node, - float_type_node, float_type_node, NULL_TREE); + types[MIPS_V2SF_FTYPE_V2SF_V2SF_V2SF_V2SF] + = build_function_type_list (V2SF_type_node, + V2SF_type_node, V2SF_type_node, + V2SF_type_node, V2SF_type_node, NULL_TREE); - types[MIPS_INT_FTYPE_DF_DF] - = build_function_type_list (integer_type_node, - double_type_node, double_type_node, NULL_TREE); + types[MIPS_V2SF_FTYPE_SF_SF] + = build_function_type_list (V2SF_type_node, + float_type_node, float_type_node, NULL_TREE); - types[MIPS_SF_FTYPE_V2SF] - = build_function_type_list (float_type_node, V2SF_type_node, NULL_TREE); + types[MIPS_INT_FTYPE_V2SF_V2SF] + = build_function_type_list (integer_type_node, + V2SF_type_node, V2SF_type_node, NULL_TREE); - types[MIPS_SF_FTYPE_SF] - = build_function_type_list (float_type_node, - float_type_node, NULL_TREE); + types[MIPS_INT_FTYPE_V2SF_V2SF_V2SF_V2SF] + = build_function_type_list (integer_type_node, + V2SF_type_node, V2SF_type_node, + V2SF_type_node, V2SF_type_node, NULL_TREE); - types[MIPS_SF_FTYPE_SF_SF] - = build_function_type_list (float_type_node, - float_type_node, float_type_node, NULL_TREE); + types[MIPS_INT_FTYPE_SF_SF] + = build_function_type_list (integer_type_node, + float_type_node, float_type_node, NULL_TREE); - types[MIPS_DF_FTYPE_DF] - = build_function_type_list (double_type_node, - double_type_node, NULL_TREE); + types[MIPS_INT_FTYPE_DF_DF] + = build_function_type_list (integer_type_node, + double_type_node, double_type_node, NULL_TREE); - types[MIPS_DF_FTYPE_DF_DF] - = build_function_type_list (double_type_node, - double_type_node, double_type_node, NULL_TREE); + types[MIPS_SF_FTYPE_V2SF] + = build_function_type_list (float_type_node, V2SF_type_node, NULL_TREE); + + types[MIPS_SF_FTYPE_SF] + = build_function_type_list (float_type_node, + float_type_node, NULL_TREE); + + types[MIPS_SF_FTYPE_SF_SF] + = build_function_type_list (float_type_node, + float_type_node, float_type_node, NULL_TREE); + + types[MIPS_DF_FTYPE_DF] + = build_function_type_list (double_type_node, + double_type_node, NULL_TREE); + + types[MIPS_DF_FTYPE_DF_DF] + = build_function_type_list (double_type_node, + double_type_node, double_type_node, NULL_TREE); + } + + if (TARGET_DSP) + { + V2HI_type_node = build_vector_type_for_mode (intHI_type_node, V2HImode); + V4QI_type_node = build_vector_type_for_mode (intQI_type_node, V4QImode); + + types[MIPS_V2HI_FTYPE_V2HI_V2HI] + = build_function_type_list (V2HI_type_node, + V2HI_type_node, V2HI_type_node, + NULL_TREE); + + types[MIPS_SI_FTYPE_SI_SI] + = build_function_type_list (intSI_type_node, + intSI_type_node, intSI_type_node, + NULL_TREE); + + types[MIPS_V4QI_FTYPE_V4QI_V4QI] + = build_function_type_list (V4QI_type_node, + V4QI_type_node, V4QI_type_node, + NULL_TREE); + + types[MIPS_SI_FTYPE_V4QI] + = build_function_type_list (intSI_type_node, + V4QI_type_node, + NULL_TREE); + + types[MIPS_V2HI_FTYPE_V2HI] + = build_function_type_list (V2HI_type_node, + V2HI_type_node, + NULL_TREE); + + types[MIPS_SI_FTYPE_SI] + = build_function_type_list (intSI_type_node, + intSI_type_node, + NULL_TREE); + + types[MIPS_V4QI_FTYPE_V2HI_V2HI] + = build_function_type_list (V4QI_type_node, + V2HI_type_node, V2HI_type_node, + NULL_TREE); + + types[MIPS_V2HI_FTYPE_SI_SI] + = build_function_type_list (V2HI_type_node, + intSI_type_node, intSI_type_node, + NULL_TREE); + + types[MIPS_SI_FTYPE_V2HI] + = build_function_type_list (intSI_type_node, + V2HI_type_node, + NULL_TREE); + + types[MIPS_V2HI_FTYPE_V4QI] + = build_function_type_list (V2HI_type_node, + V4QI_type_node, + NULL_TREE); + + types[MIPS_V4QI_FTYPE_V4QI_SI] + = build_function_type_list (V4QI_type_node, + V4QI_type_node, intSI_type_node, + NULL_TREE); + + types[MIPS_V2HI_FTYPE_V2HI_SI] + = build_function_type_list (V2HI_type_node, + V2HI_type_node, intSI_type_node, + NULL_TREE); + + types[MIPS_V2HI_FTYPE_V4QI_V2HI] + = build_function_type_list (V2HI_type_node, + V4QI_type_node, V2HI_type_node, + NULL_TREE); + + types[MIPS_SI_FTYPE_V2HI_V2HI] + = build_function_type_list (intSI_type_node, + V2HI_type_node, V2HI_type_node, + NULL_TREE); + + types[MIPS_DI_FTYPE_DI_V4QI_V4QI] + = build_function_type_list (intDI_type_node, + intDI_type_node, V4QI_type_node, V4QI_type_node, + NULL_TREE); + + types[MIPS_DI_FTYPE_DI_V2HI_V2HI] + = build_function_type_list (intDI_type_node, + intDI_type_node, V2HI_type_node, V2HI_type_node, + NULL_TREE); + + types[MIPS_DI_FTYPE_DI_SI_SI] + = build_function_type_list (intDI_type_node, + intDI_type_node, intSI_type_node, intSI_type_node, + NULL_TREE); + + types[MIPS_V4QI_FTYPE_SI] + = build_function_type_list (V4QI_type_node, + intSI_type_node, + NULL_TREE); + + types[MIPS_V2HI_FTYPE_SI] + = build_function_type_list (V2HI_type_node, + intSI_type_node, + NULL_TREE); + + types[MIPS_VOID_FTYPE_V4QI_V4QI] + = build_function_type_list (void_type_node, + V4QI_type_node, V4QI_type_node, + NULL_TREE); + + types[MIPS_SI_FTYPE_V4QI_V4QI] + = build_function_type_list (intSI_type_node, + V4QI_type_node, V4QI_type_node, + NULL_TREE); + + types[MIPS_VOID_FTYPE_V2HI_V2HI] + = build_function_type_list (void_type_node, + V2HI_type_node, V2HI_type_node, + NULL_TREE); + + types[MIPS_SI_FTYPE_DI_SI] + = build_function_type_list (intSI_type_node, + intDI_type_node, intSI_type_node, + NULL_TREE); + + types[MIPS_DI_FTYPE_DI_SI] + = build_function_type_list (intDI_type_node, + intDI_type_node, intSI_type_node, + NULL_TREE); + + types[MIPS_VOID_FTYPE_SI_SI] + = build_function_type_list (void_type_node, + intSI_type_node, intSI_type_node, + NULL_TREE); + + types[MIPS_SI_FTYPE_PTR_SI] + = build_function_type_list (intSI_type_node, + ptr_type_node, intSI_type_node, + NULL_TREE); + + types[MIPS_SI_FTYPE_VOID] + = build_function_type (intSI_type_node, void_list_node); + } /* Iterate through all of the bdesc arrays, initializing all of the builtin functions. */ @@ -9922,7 +10503,7 @@ mips_init_builtins (void) offset = 0; for (m = bdesc_arrays; m < &bdesc_arrays[ARRAY_SIZE (bdesc_arrays)]; m++) { - if (m->proc == PROCESSOR_DEFAULT || (m->proc == mips_arch)) + if (m->proc == PROCESSOR_MAX || (m->proc == mips_arch)) for (d = m->bdesc; d < &m->bdesc[m->size]; d++) if ((d->target_flags & target_flags) == d->target_flags) lang_hooks.builtin_function (d->name, types[d->function_type], @@ -9934,30 +10515,40 @@ mips_init_builtins (void) /* Expand a MIPS_BUILTIN_DIRECT function. ICODE is the code of the .md pattern and ARGLIST is the list of function arguments. TARGET, - if nonnull, suggests a good place to put the result. */ + if nonnull, suggests a good place to put the result. + HAS_TARGET indicates the function must return something. */ static rtx -mips_expand_builtin_direct (enum insn_code icode, rtx target, tree arglist) +mips_expand_builtin_direct (enum insn_code icode, rtx target, tree arglist, + bool has_target) { rtx ops[MAX_RECOG_OPERANDS]; - int i; + int i = 0; - target = mips_prepare_builtin_target (icode, 0, target); - for (i = 1; i < insn_data[icode].n_operands; i++) + if (has_target) + { + /* We save target to ops[0]. */ + ops[0] = mips_prepare_builtin_target (icode, 0, target); + i = 1; + } + + /* We need to test if arglist is not zero. Some instructions have extra + clobber registers. */ + for (; i < insn_data[icode].n_operands && arglist != 0; i++) ops[i] = mips_prepare_builtin_arg (icode, i, &arglist); - switch (insn_data[icode].n_operands) + switch (i) { case 2: - emit_insn (GEN_FCN (icode) (target, ops[1])); + emit_insn (GEN_FCN (icode) (ops[0], ops[1])); break; case 3: - emit_insn (GEN_FCN (icode) (target, ops[1], ops[2])); + emit_insn (GEN_FCN (icode) (ops[0], ops[1], ops[2])); break; case 4: - emit_insn (GEN_FCN (icode) (target, ops[1], ops[2], ops[3])); + emit_insn (GEN_FCN (icode) (ops[0], ops[1], ops[2], ops[3])); break; default: @@ -10087,5 +10678,86 @@ mips_expand_builtin_compare (enum mips_builtin_type builtin_type, return target; } + +/* Expand a bposge builtin of type BUILTIN_TYPE. TARGET, if nonnull, + suggests a good place to put the boolean result. + + The sequence we want is + + li target, 0 + bposge* label1 + j label2 + label1: + li target, 1 + label2: */ + +static rtx +mips_expand_builtin_bposge (enum mips_builtin_type builtin_type, rtx target) +{ + rtx label1, label2, if_then_else; + rtx cmp_result; + int cmp_value; + + if (target == 0 || GET_MODE (target) != SImode) + target = gen_reg_rtx (SImode); + + cmp_result = gen_rtx_REG (CCDSPmode, CCDSP_PO_REGNUM); + + if (builtin_type == MIPS_BUILTIN_BPOSGE32) + cmp_value = 32; + else + gcc_assert (0); + + /* Move 0 to target */ + emit_move_insn (target, const0_rtx); + + /* Generate two labels */ + label1 = gen_label_rtx (); + label2 = gen_label_rtx (); + + /* Generate if_then_else */ + if_then_else + = gen_rtx_IF_THEN_ELSE (VOIDmode, + gen_rtx_fmt_ee (GE, CCDSPmode, + cmp_result, GEN_INT (cmp_value)), + gen_rtx_LABEL_REF (VOIDmode, label1), pc_rtx); + + emit_jump_insn (gen_rtx_SET (VOIDmode, pc_rtx, if_then_else)); + emit_jump_insn (gen_rtx_SET (VOIDmode, pc_rtx, + gen_rtx_LABEL_REF (VOIDmode, label2))); + emit_barrier (); + emit_label (label1); + emit_move_insn (target, const1_rtx); + emit_label (label2); + + return target; +} + +/* Set SYMBOL_REF_FLAGS for the SYMBOL_REF inside RTL, which belongs to DECL. + FIRST is true if this is the first time handling this decl. */ + +static void +mips_encode_section_info (tree decl, rtx rtl, int first) +{ + default_encode_section_info (decl, rtl, first); + + if (TREE_CODE (decl) == FUNCTION_DECL + && lookup_attribute ("long_call", TYPE_ATTRIBUTES (TREE_TYPE (decl)))) + { + rtx symbol = XEXP (rtl, 0); + SYMBOL_REF_FLAGS (symbol) |= SYMBOL_FLAG_LONG_CALL; + } +} + +/* Implement TARGET_EXTRA_LIVE_ON_ENTRY. TARGET_ABICALLS makes + PIC_FUNCTION_ADDR_REGNUM live on entry to a function. */ + +static void +mips_extra_live_on_entry (bitmap regs) +{ + if (!TARGET_ABICALLS) + bitmap_set_bit (regs, PIC_FUNCTION_ADDR_REGNUM); +} + #include "gt-mips.h"