/* Subroutines used for MIPS code generation.
Copyright (C) 1989, 1990, 1991, 1993, 1994, 1995, 1996, 1997, 1998,
- 1999, 2000, 2001, 2002, 2003, 2004 Free Software Foundation, Inc.
+ 1999, 2000, 2001, 2002, 2003, 2004, 2005 Free Software Foundation, Inc.
Contributed by A. Lichnewsky, lich@inria.inria.fr.
Changes by Michael Meissner, meissner@osf.org.
64 bit r4000 support by Ian Lance Taylor, ian@cygnus.com, and
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"
#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) \
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
};
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
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. */
static bool mips_symbolic_address_p (enum mips_symbol_type, enum machine_mode);
static bool mips_classify_address (struct mips_address_info *, rtx,
enum machine_mode, int);
+static bool mips_cannot_force_const_mem (rtx);
static int mips_symbol_insns (enum mips_symbol_type);
static bool mips16_unextended_reference_p (enum machine_mode mode, rtx, rtx);
static rtx mips_force_temporary (rtx, rtx);
static bool mips_get_unaligned_mem (rtx *, unsigned int, int, rtx *, rtx *);
static void mips_set_architecture (const struct mips_cpu_info *);
static void mips_set_tune (const struct mips_cpu_info *);
+static bool mips_handle_option (size_t, const char *, int);
static struct machine_function *mips_init_machine_status (void);
static void print_operand_reloc (FILE *, rtx, const char **);
#if TARGET_IRIX
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);
static void mips_reorg (void);
static bool mips_strict_matching_cpu_name_p (const char *, const char *);
static bool mips_matching_cpu_name_p (const char *, const char *);
-static const struct mips_cpu_info *mips_parse_cpu (const char *, const char *);
+static const struct mips_cpu_info *mips_parse_cpu (const char *);
static const struct mips_cpu_info *mips_cpu_info_from_isa (int);
static bool mips_return_in_memory (tree, tree);
static bool mips_strict_argument_naming (CUMULATIVE_ARGS *);
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. */
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;
int mips_isa;
/* Which ABI to use. */
-int mips_abi;
+int mips_abi = MIPS_ABI_DEFAULT;
-/* Strings to hold which cpu and instruction set architecture to use. */
-const char *mips_arch_string; /* for -march=<xxx> */
-const char *mips_tune_string; /* for -mtune=<xxx> */
-const char *mips_isa_string; /* for -mips{1,2,3,4} */
-const char *mips_abi_string; /* for -mabi={32,n32,64,eabi} */
+/* 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
should arrange to call mips32 hard floating point code. */
int mips16_hard_float;
-const char *mips_cache_flush_func = CACHE_FLUSH_FUNC;
+/* The architecture selected by -mipsN. */
+static const struct mips_cpu_info *mips_isa_info;
/* If TRUE, we split addresses into their high and low parts in the RTL. */
int mips_split_addresses;
/* Map hard register number to register class */
const enum reg_class mips_regno_to_class[] =
{
- LEA_REGS, LEA_REGS, M16_NA_REGS, M16_NA_REGS,
+ LEA_REGS, LEA_REGS, M16_NA_REGS, V1_REG,
M16_REGS, M16_REGS, M16_REGS, M16_REGS,
LEA_REGS, LEA_REGS, LEA_REGS, LEA_REGS,
LEA_REGS, LEA_REGS, LEA_REGS, LEA_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, 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 }
+};
\f
/* A table describing all the processors gcc knows about. Names are
matched in the order listed. The first mention of an ISA level is
/* 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 },
/* 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
+ },
+ };
+
\f
/* Nonzero if -march should decide the default value of MASK_SOFT_FLOAT. */
#ifndef MIPS_MARCH_CONTROLS_SOFT_FLOAT
#define TARGET_SCHED_FIRST_CYCLE_MULTIPASS_DFA_LOOKAHEAD \
mips_multipass_dfa_lookahead
+#undef TARGET_DEFAULT_TARGET_FLAGS
+#define TARGET_DEFAULT_TARGET_FLAGS \
+ (TARGET_DEFAULT \
+ | TARGET_CPU_DEFAULT \
+ | TARGET_ENDIAN_DEFAULT \
+ | TARGET_FP_EXCEPTIONS_DEFAULT \
+ | MASK_CHECK_ZERO_DIV \
+ | MASK_FUSED_MADD)
+#undef TARGET_HANDLE_OPTION
+#define TARGET_HANDLE_OPTION mips_handle_option
+
#undef TARGET_FUNCTION_OK_FOR_SIBCALL
#define TARGET_FUNCTION_OK_FOR_SIBCALL mips_function_ok_for_sibcall
#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
#define TARGET_EXPAND_BUILTIN mips_expand_builtin
+#undef TARGET_HAVE_TLS
+#define TARGET_HAVE_TLS HAVE_AS_TLS
+
+#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;
\f
/* Classify symbol X, which must be a SYMBOL_REF or a LABEL_REF. */
gcc_assert (GET_CODE (x) == SYMBOL_REF);
+ if (SYMBOL_REF_TLS_MODEL (x))
+ return SYMBOL_TLS;
+
if (CONSTANT_POOL_ADDRESS_P (x))
{
if (TARGET_MIPS16)
if (UNSPEC_ADDRESS_P (x))
*symbol_type = UNSPEC_ADDRESS_TYPE (x);
else if (GET_CODE (x) == SYMBOL_REF || GET_CODE (x) == LABEL_REF)
- *symbol_type = mips_classify_symbol (x);
+ {
+ *symbol_type = mips_classify_symbol (x);
+ if (*symbol_type == SYMBOL_TLS)
+ return false;
+ }
else
return false;
case SYMBOL_GOTOFF_GLOBAL:
case SYMBOL_GOTOFF_CALL:
case SYMBOL_GOTOFF_LOADGP:
+ case SYMBOL_TLSGD:
+ case SYMBOL_TLSLDM:
+ case SYMBOL_DTPREL:
+ case SYMBOL_TPREL:
+ case SYMBOL_GOTTPREL:
+ case SYMBOL_TLS:
return false;
}
gcc_unreachable ();
/* The address will have to be loaded from the GOT first. */
return false;
+ case SYMBOL_TLSGD:
+ case SYMBOL_TLSLDM:
+ case SYMBOL_DTPREL:
+ case SYMBOL_TPREL:
+ case SYMBOL_GOTTPREL:
+ case SYMBOL_TLS:
+ return false;
+
case SYMBOL_GOTOFF_PAGE:
case SYMBOL_GOTOFF_GLOBAL:
case SYMBOL_GOTOFF_CALL:
return false;
}
}
+
+/* Return true if X is a thread-local symbol. */
+
+static bool
+mips_tls_operand_p (rtx x)
+{
+ return GET_CODE (x) == SYMBOL_REF && SYMBOL_REF_TLS_MODEL (x) != 0;
+}
+
+/* Return true if X can not be forced into a constant pool. */
+
+static int
+mips_tls_symbol_ref_1 (rtx *x, void *data ATTRIBUTE_UNUSED)
+{
+ return mips_tls_operand_p (*x);
+}
+
+/* Return true if X can not be forced into a constant pool. */
+
+static bool
+mips_cannot_force_const_mem (rtx x)
+{
+ if (! TARGET_HAVE_TLS)
+ return false;
+
+ return for_each_rtx (&x, &mips_tls_symbol_ref_1, 0);
+}
\f
/* 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
case SYMBOL_64_HIGH:
case SYMBOL_64_MID:
case SYMBOL_64_LOW:
+ case SYMBOL_TLSGD:
+ case SYMBOL_TLSLDM:
+ case SYMBOL_DTPREL:
+ case SYMBOL_GOTTPREL:
+ case SYMBOL_TPREL:
/* Check whether the offset is a 16- or 32-bit value. */
return mips_split_p[type] ? 2 : 1;
+
+ case SYMBOL_TLS:
+ /* We don't treat a bare TLS symbol as a constant. */
+ return 0;
}
gcc_unreachable ();
}
return plus_constant (reg, offset);
}
+/* Emit a call to __tls_get_addr. SYM is the TLS symbol we are
+ referencing, and TYPE is the symbol type to use (either global
+ dynamic or local dynamic). V0 is an RTX for the return value
+ location. The entire insn sequence is returned. */
+
+static GTY(()) rtx mips_tls_symbol;
+
+static rtx
+mips_call_tls_get_addr (rtx sym, enum mips_symbol_type type, rtx v0)
+{
+ rtx insn, loc, tga, a0;
+
+ a0 = gen_rtx_REG (Pmode, GP_ARG_FIRST);
+
+ if (!mips_tls_symbol)
+ mips_tls_symbol = init_one_libfunc ("__tls_get_addr");
+
+ loc = mips_unspec_address (sym, type);
+
+ start_sequence ();
+
+ emit_insn (gen_rtx_SET (Pmode, a0,
+ gen_rtx_LO_SUM (Pmode, pic_offset_table_rtx, loc)));
+ tga = gen_rtx_MEM (Pmode, mips_tls_symbol);
+ insn = emit_call_insn (gen_call_value (v0, tga, const0_rtx, const0_rtx));
+ CONST_OR_PURE_CALL_P (insn) = 1;
+ use_reg (&CALL_INSN_FUNCTION_USAGE (insn), v0);
+ use_reg (&CALL_INSN_FUNCTION_USAGE (insn), a0);
+ insn = get_insns ();
+
+ end_sequence ();
+
+ return insn;
+}
+
+/* Generate the code to access LOC, a thread local SYMBOL_REF. The
+ return value will be a valid address and move_operand (either a REG
+ or a LO_SUM). */
+
+static rtx
+mips_legitimize_tls_address (rtx loc)
+{
+ rtx dest, insn, v0, v1, tmp1, tmp2, eqv;
+ enum tls_model model;
+
+ v0 = gen_rtx_REG (Pmode, GP_RETURN);
+ v1 = gen_rtx_REG (Pmode, GP_RETURN + 1);
+
+ model = SYMBOL_REF_TLS_MODEL (loc);
+
+ switch (model)
+ {
+ case TLS_MODEL_GLOBAL_DYNAMIC:
+ insn = mips_call_tls_get_addr (loc, SYMBOL_TLSGD, v0);
+ dest = gen_reg_rtx (Pmode);
+ emit_libcall_block (insn, dest, v0, loc);
+ break;
+
+ case TLS_MODEL_LOCAL_DYNAMIC:
+ insn = mips_call_tls_get_addr (loc, SYMBOL_TLSLDM, v0);
+ tmp1 = gen_reg_rtx (Pmode);
+
+ /* Attach a unique REG_EQUIV, to allow the RTL optimizers to
+ share the LDM result with other LD model accesses. */
+ eqv = gen_rtx_UNSPEC (Pmode, gen_rtvec (1, const0_rtx),
+ UNSPEC_TLS_LDM);
+ emit_libcall_block (insn, tmp1, v0, eqv);
+
+ tmp2 = mips_unspec_offset_high (NULL, tmp1, loc, SYMBOL_DTPREL);
+ dest = gen_rtx_LO_SUM (Pmode, tmp2,
+ mips_unspec_address (loc, SYMBOL_DTPREL));
+ break;
+
+ case TLS_MODEL_INITIAL_EXEC:
+ tmp1 = gen_reg_rtx (Pmode);
+ tmp2 = mips_unspec_address (loc, SYMBOL_GOTTPREL);
+ if (Pmode == DImode)
+ {
+ emit_insn (gen_tls_get_tp_di (v1));
+ emit_insn (gen_load_gotdi (tmp1, pic_offset_table_rtx, tmp2));
+ }
+ else
+ {
+ emit_insn (gen_tls_get_tp_si (v1));
+ emit_insn (gen_load_gotsi (tmp1, pic_offset_table_rtx, tmp2));
+ }
+ dest = gen_reg_rtx (Pmode);
+ emit_insn (gen_add3_insn (dest, tmp1, v1));
+ break;
+
+ case TLS_MODEL_LOCAL_EXEC:
+
+ if (Pmode == DImode)
+ emit_insn (gen_tls_get_tp_di (v1));
+ else
+ emit_insn (gen_tls_get_tp_si (v1));
+
+ tmp1 = mips_unspec_offset_high (NULL, v1, loc, SYMBOL_TPREL);
+ dest = gen_rtx_LO_SUM (Pmode, tmp1,
+ mips_unspec_address (loc, SYMBOL_TPREL));
+ break;
+
+ default:
+ gcc_unreachable ();
+ }
+
+ return dest;
+}
/* This function is used to implement LEGITIMIZE_ADDRESS. If *XLOC can
be legitimized in a way that the generic machinery might not expect,
{
enum mips_symbol_type symbol_type;
+ if (mips_tls_operand_p (*xloc))
+ {
+ *xloc = mips_legitimize_tls_address (*xloc);
+ return true;
+ }
+
/* See if the address can split into a high part and a LO_SUM. */
if (mips_symbolic_constant_p (*xloc, &symbol_type)
&& mips_symbolic_address_p (symbol_type, mode)
return;
}
+ if (mips_tls_operand_p (src))
+ {
+ emit_move_insn (dest, mips_legitimize_tls_address (src));
+ return;
+ }
+
/* See if the symbol can be split. For mips16, this is often worse than
forcing it in the constant pool since it needs the single-register form
of addiu or daddiu. */
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:
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:
return false;
case ABS:
- if (mode == SFmode || mode == DFmode)
+ if (float_mode_p)
*total = COSTS_N_INSNS (1);
else
*total = COSTS_N_INSNS (4);
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;
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:
*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;
}
{
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))
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");
{
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";
}
}
+/* 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
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);
switch (*code)
{
case NE:
- case UNGE:
- case UNGT:
case LTGT:
case ORDERED:
cmp_code = reverse_condition_maybe_unordered (*code);
\f
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;
{
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 ());
}
}
}
- 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.
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);
+ }
}
\f
/* Implement va_arg. */
[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
}
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 = lang_hooks.truthvalue_conversion (off);
- 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;
/* [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;
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;
}
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,
}
return true;
}
-\f
+
+/* 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. */
}
}
+/* Implement TARGET_HANDLE_OPTION. */
+
+static bool
+mips_handle_option (size_t code, const char *arg, int value ATTRIBUTE_UNUSED)
+{
+ switch (code)
+ {
+ case OPT_mabi_:
+ if (strcmp (arg, "32") == 0)
+ mips_abi = ABI_32;
+ else if (strcmp (arg, "o64") == 0)
+ mips_abi = ABI_O64;
+ else if (strcmp (arg, "n32") == 0)
+ mips_abi = ABI_N32;
+ else if (strcmp (arg, "64") == 0)
+ mips_abi = ABI_64;
+ else if (strcmp (arg, "eabi") == 0)
+ mips_abi = ABI_EABI;
+ else
+ return false;
+ return true;
+
+ case OPT_march_:
+ case OPT_mtune_:
+ 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_mno_flush_func:
+ mips_cache_flush_func = NULL;
+ return true;
+
+ default:
+ return true;
+ }
+}
/* Set up the threshold for data to go into the small data area, instead
of the normal data area, and detect any conflicts in the switches. */
mips_section_threshold = g_switch_set ? g_switch_value : MIPS_DEFAULT_GVALUE;
- /* Interpret -mabi. */
- mips_abi = MIPS_ABI_DEFAULT;
- if (mips_abi_string != 0)
- {
- if (strcmp (mips_abi_string, "32") == 0)
- mips_abi = ABI_32;
- else if (strcmp (mips_abi_string, "o64") == 0)
- mips_abi = ABI_O64;
- else if (strcmp (mips_abi_string, "n32") == 0)
- mips_abi = ABI_N32;
- else if (strcmp (mips_abi_string, "64") == 0)
- mips_abi = ABI_64;
- else if (strcmp (mips_abi_string, "eabi") == 0)
- mips_abi = ABI_EABI;
- else
- fatal_error ("bad value (%s) for -mabi= switch", mips_abi_string);
- }
-
/* The following code determines the architecture and register size.
Similar code was added to GAS 2.14 (see tc-mips.c:md_after_parse_args()).
The GAS and GCC code should be kept in sync as much as possible. */
if (mips_arch_string != 0)
- mips_set_architecture (mips_parse_cpu ("-march", mips_arch_string));
+ mips_set_architecture (mips_parse_cpu (mips_arch_string));
- if (mips_isa_string != 0)
+ if (mips_isa_info != 0)
{
- /* Handle -mipsN. */
- char *whole_isa_str = concat ("mips", mips_isa_string, NULL);
- const struct mips_cpu_info *isa_info;
-
- isa_info = mips_parse_cpu ("-mips option", whole_isa_str);
- free (whole_isa_str);
-
- /* -march takes precedence over -mipsN, since it is more descriptive.
- There's no harm in specifying both as long as the ISA levels
- are the same. */
- if (mips_arch_info != 0 && mips_isa != isa_info->isa)
- error ("-mips%s conflicts with the other architecture options, "
- "which specify a MIPS%d processor",
- mips_isa_string, mips_isa);
-
- /* Set architecture based on the given option. */
- mips_set_architecture (isa_info);
+ if (mips_arch_info == 0)
+ mips_set_architecture (mips_isa_info);
+ else if (mips_arch_info->isa != mips_isa_info->isa)
+ error ("-%s conflicts with the other architecture options, "
+ "which specify a %s processor",
+ mips_isa_info->name,
+ mips_cpu_info_from_isa (mips_arch_info->isa)->name);
}
if (mips_arch_info == 0)
{
#ifdef MIPS_CPU_STRING_DEFAULT
- mips_set_architecture (mips_parse_cpu ("default CPU",
- MIPS_CPU_STRING_DEFAULT));
+ mips_set_architecture (mips_parse_cpu (MIPS_CPU_STRING_DEFAULT));
#else
mips_set_architecture (mips_cpu_info_from_isa (MIPS_ISA_DEFAULT));
#endif
/* Optimize for mips_arch, unless -mtune selects a different processor. */
if (mips_tune_string != 0)
- mips_set_tune (mips_parse_cpu ("-mtune", mips_tune_string));
+ mips_set_tune (mips_parse_cpu (mips_tune_string));
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
if ((target_flags_explicit & MASK_LONG64) == 0)
{
- /* 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. */
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_flags_explicit & MASK_INT64) != 0)
- warning ("-mint64 is a deprecated option");
-
if (MIPS_MARCH_CONTROLS_SOFT_FLOAT
&& (target_flags_explicit & MASK_SOFT_FLOAT) == 0)
{
target_flags &= ~MASK_BRANCHLIKELY;
}
if (TARGET_BRANCHLIKELY && !ISA_HAS_BRANCHLIKELY)
- warning ("generation of Branch Likely instructions enabled, but not supported by architecture");
+ warning (0, "generation of Branch Likely instructions enabled, but not supported by architecture");
/* The effect of -mabicalls isn't defined for the EABI. */
if (mips_abi == ABI_EABI && TARGET_ABICALLS)
{
flag_pic = 1;
if (mips_section_threshold > 0)
- warning ("-G is incompatible with PIC code which is the default");
+ warning (0, "-G is incompatible with PIC code which is the default");
}
/* mips_split_addresses is a half-way house between explicit
/* Make sure that the user didn't turn off paired single support when
MIPS-3D support is requested. */
- if (TARGET_MIPS3D && (target_flags_explicit & MASK_PAIRED_SINGLE)
+ if (TARGET_MIPS3D && (target_flags_explicit & MASK_PAIRED_SINGLE_FLOAT)
&& !TARGET_PAIRED_SINGLE_FLOAT)
error ("-mips3d requires -mpaired-single");
- /* If TARGET_MIPS3D, enable MASK_PAIRED_SINGLE. */
+ /* If TARGET_MIPS3D, enable MASK_PAIRED_SINGLE_FLOAT. */
if (TARGET_MIPS3D)
- target_flags |= MASK_PAIRED_SINGLE;
+ target_flags |= MASK_PAIRED_SINGLE_FLOAT;
/* Make sure that when TARGET_PAIRED_SINGLE_FLOAT is true, TARGET_FLOAT64
and TARGET_HARD_FLOAT are both true. */
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;
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['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. */
&& 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))
mips_lo_relocs[SYMBOL_GOTOFF_LOADGP] = "%lo(%neg(%gp_rel(";
}
+ /* Thread-local relocation operators. */
+ mips_lo_relocs[SYMBOL_TLSGD] = "%tlsgd(";
+ mips_lo_relocs[SYMBOL_TLSLDM] = "%tlsldm(";
+ mips_split_p[SYMBOL_DTPREL] = 1;
+ mips_hi_relocs[SYMBOL_DTPREL] = "%dtprel_hi(";
+ mips_lo_relocs[SYMBOL_DTPREL] = "%dtprel_lo(";
+ mips_lo_relocs[SYMBOL_GOTTPREL] = "%gottprel(";
+ mips_split_p[SYMBOL_TPREL] = 1;
+ mips_hi_relocs[SYMBOL_TPREL] = "%tprel_hi(";
+ mips_lo_relocs[SYMBOL_TPREL] = "%tprel_lo(";
+
+ /* We don't have a thread pointer access instruction on MIPS16, or
+ appropriate TLS relocations. */
+ if (TARGET_MIPS16)
+ targetm.have_tls = false;
+
/* Default to working around R4000 errata only if the processor
was selected explicitly. */
if ((target_flags_explicit & MASK_FIX_R4000) == 0
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;
'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:
}
}
+ 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;
{
register int c = string[i];
- switch (c)
+ if (ISPRINT (c))
{
- case '\"':
- case '\\':
- putc ('\\', stream);
- putc (c, stream);
- cur_pos += 2;
- break;
-
- case TARGET_NEWLINE:
- fputs ("\\n", stream);
- if (i+1 < len
- && (((c = string[i+1]) >= '\040' && c <= '~')
- || c == TARGET_TAB))
- cur_pos = 32767; /* break right here */
- else
- cur_pos += 2;
- break;
-
- case TARGET_TAB:
- fputs ("\\t", stream);
- cur_pos += 2;
- break;
-
- case TARGET_FF:
- fputs ("\\f", stream);
- cur_pos += 2;
- break;
-
- case TARGET_BS:
- fputs ("\\b", stream);
- cur_pos += 2;
- break;
-
- case TARGET_CR:
- fputs ("\\r", stream);
- cur_pos += 2;
- break;
-
- default:
- if (c >= ' ' && c < 0177)
+ if (c == '\\' || c == '\"')
{
- putc (c, stream);
+ putc ('\\', stream);
cur_pos++;
}
- else
- {
- fprintf (stream, "\\%03o", c);
- cur_pos += 4;
- }
+ putc (c, stream);
+ cur_pos++;
+ }
+ else
+ {
+ fprintf (stream, "\\%03o", c);
+ cur_pos += 4;
}
if (cur_pos > 72 && i+1 < len)
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. */
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);
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",
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. */
/* 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
+-----------------------+ +-----------------------+
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;
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:
static rtx
mips_frame_set (rtx mem, rtx reg)
{
- rtx set = gen_rtx_SET (VOIDmode, mem, reg);
+ rtx set;
+
+ /* If we're saving the return address register and the dwarf return
+ address column differs from the hard register number, adjust the
+ note reg to refer to the former. */
+ if (REGNO (reg) == GP_REG_FIRST + 31
+ && DWARF_FRAME_RETURN_COLUMN != GP_REG_FIRST + 31)
+ reg = gen_rtx_REG (GET_MODE (reg), DWARF_FRAME_RETURN_COLUMN);
+
+ set = gen_rtx_SET (VOIDmode, mem, reg);
RTX_FRAME_RELATED_P (set) = 1;
+
return set;
}
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,
mips16_lay_out_constants ();
shorten_branches (insn);
final_start_function (insn, file, 1);
- final (insn, file, 1, 0);
+ final (insn, file, 1);
final_end_function ();
/* Clean up the vars set above. Note that final_end_function resets
/* 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)
{
/* 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
{
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);
}
}
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
/* 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;
}
}
}
/* 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)
{
}
return gp_reg_p ? NO_REGS : gr_regs;
}
- if (MD_REG_P (regno))
+ if (ACC_REG_P (regno))
{
if (TARGET_MIPS16 && ! in_p)
{
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;
-}
\f
/* If we can access small data directly (using gp-relative relocation
operators) return the small data pointer, otherwise return null.
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
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
emit_barrier_after (insn);
}
-/* Return the length of instruction INSN.
-
- ??? MIPS16 switch tables go in .text, but we don't define
- JUMP_TABLES_IN_TEXT_SECTION, so get_attr_length will not
- compute their lengths correctly. */
+/* Return the length of instruction INSN. */
static int
mips16_insn_length (rtx insn)
cfun->machine->ignore_hazard_length_p = true;
shorten_branches (get_insns ());
- /* The profiler code uses assembler macros. -mfix-vr4120 relies on
- assembler nop insertion. */
- cfun->machine->all_noreorder_p = (!current_function_profile
- && !TARGET_FIX_VR4120);
+ cfun->machine->all_noreorder_p = true;
+
+ /* Profiled functions can't be all noreorder because the profiler
+ support uses assembler macros. */
+ if (current_function_profile)
+ cfun->machine->all_noreorder_p = false;
+
+ /* Code compiled with -mfix-vr4120 can't be all noreorder because
+ we rely on the assembler to work around some errata. */
+ if (TARGET_FIX_VR4120)
+ cfun->machine->all_noreorder_p = false;
+
+ /* The same is true for -mfix-vr4130 if we might generate mflo or
+ mfhi instructions. Note that we avoid using mflo and mfhi if
+ the VR4130 macc and dmacc instructions are available instead;
+ see the *mfhilo_{si,di}_macc patterns. */
+ if (TARGET_FIX_VR4130 && !ISA_HAS_MACCHI)
+ cfun->machine->all_noreorder_p = false;
last_insn = 0;
hilo_delay = 2;
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 ();
}
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;
{
return 5;
}
- } /* GR_REG_CLASS_P (from) */
+ }
else if (from == FP_REGS)
{
if (GR_REG_CLASS_P (to))
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))
{
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;
}
/* Output delay slot instruction. */
rtx insn = final_sequence;
final_scan_insn (XVECEXP (insn, 0, 1), asm_out_file,
- optimize, 0, 1, NULL);
+ optimize, 1, NULL);
INSN_DELETED_P (XVECEXP (insn, 0, 1)) = 1;
}
else
/* Output delay slot instruction. */
rtx insn = final_sequence;
final_scan_insn (XVECEXP (insn, 0, 1), asm_out_file,
- optimize, 0, 1, NULL);
+ optimize, 1, NULL);
INSN_DELETED_P (XVECEXP (insn, 0, 1)) = 1;
}
else
}
-/* Parse an option that takes the name of a processor as its argument.
- OPTION is the name of the option and CPU_STRING is the argument.
- Return the corresponding processor enumeration if the CPU_STRING is
- recognized, otherwise report an error and return null.
+/* Return the mips_cpu_info entry for the processor or ISA given
+ by CPU_STRING. Return null if the string isn't recognized.
A similar function exists in GAS. */
static const struct mips_cpu_info *
-mips_parse_cpu (const char *option, const char *cpu_string)
+mips_parse_cpu (const char *cpu_string)
{
const struct mips_cpu_info *p;
const char *s;
for (s = cpu_string; *s != 0; s++)
if (ISUPPER (*s))
{
- warning ("the cpu name must be lower case");
+ warning (0, "the cpu name must be lower case");
break;
}
if (mips_matching_cpu_name_p (p->name, cpu_string))
return p;
- error ("bad value (%s) for %s", cpu_string, option);
return 0;
}
/* Define all the builtins related to c.cond.fmt condition COND. */
#define CMP_BUILTINS(COND) \
- MOVTF_BUILTINS (c, COND, MASK_PAIRED_SINGLE), \
+ MOVTF_BUILTINS (c, COND, MASK_PAIRED_SINGLE_FLOAT), \
MOVTF_BUILTINS (cabs, COND, MASK_MIPS3D), \
CMP_SCALAR_BUILTINS (cabs, COND, MASK_MIPS3D), \
- CMP_PS_BUILTINS (c, COND, MASK_PAIRED_SINGLE), \
+ CMP_PS_BUILTINS (c, COND, MASK_PAIRED_SINGLE_FLOAT), \
CMP_PS_BUILTINS (cabs, COND, MASK_MIPS3D), \
CMP_4S_BUILTINS (c, COND), \
CMP_4S_BUILTINS (cabs, COND)
static const struct builtin_description mips_bdesc[] =
{
- DIRECT_BUILTIN (pll_ps, MIPS_V2SF_FTYPE_V2SF_V2SF, MASK_PAIRED_SINGLE),
- DIRECT_BUILTIN (pul_ps, MIPS_V2SF_FTYPE_V2SF_V2SF, MASK_PAIRED_SINGLE),
- DIRECT_BUILTIN (plu_ps, MIPS_V2SF_FTYPE_V2SF_V2SF, MASK_PAIRED_SINGLE),
- DIRECT_BUILTIN (puu_ps, MIPS_V2SF_FTYPE_V2SF_V2SF, MASK_PAIRED_SINGLE),
- DIRECT_BUILTIN (cvt_ps_s, MIPS_V2SF_FTYPE_SF_SF, MASK_PAIRED_SINGLE),
- DIRECT_BUILTIN (cvt_s_pl, MIPS_SF_FTYPE_V2SF, MASK_PAIRED_SINGLE),
- DIRECT_BUILTIN (cvt_s_pu, MIPS_SF_FTYPE_V2SF, MASK_PAIRED_SINGLE),
- DIRECT_BUILTIN (abs_ps, MIPS_V2SF_FTYPE_V2SF, MASK_PAIRED_SINGLE),
-
- DIRECT_BUILTIN (alnv_ps, MIPS_V2SF_FTYPE_V2SF_V2SF_INT, MASK_PAIRED_SINGLE),
+ DIRECT_BUILTIN (pll_ps, MIPS_V2SF_FTYPE_V2SF_V2SF, MASK_PAIRED_SINGLE_FLOAT),
+ DIRECT_BUILTIN (pul_ps, MIPS_V2SF_FTYPE_V2SF_V2SF, MASK_PAIRED_SINGLE_FLOAT),
+ DIRECT_BUILTIN (plu_ps, MIPS_V2SF_FTYPE_V2SF_V2SF, MASK_PAIRED_SINGLE_FLOAT),
+ DIRECT_BUILTIN (puu_ps, MIPS_V2SF_FTYPE_V2SF_V2SF, MASK_PAIRED_SINGLE_FLOAT),
+ DIRECT_BUILTIN (cvt_ps_s, MIPS_V2SF_FTYPE_SF_SF, MASK_PAIRED_SINGLE_FLOAT),
+ DIRECT_BUILTIN (cvt_s_pl, MIPS_SF_FTYPE_V2SF, MASK_PAIRED_SINGLE_FLOAT),
+ DIRECT_BUILTIN (cvt_s_pu, MIPS_SF_FTYPE_V2SF, MASK_PAIRED_SINGLE_FLOAT),
+ DIRECT_BUILTIN (abs_ps, MIPS_V2SF_FTYPE_V2SF, MASK_PAIRED_SINGLE_FLOAT),
+
+ DIRECT_BUILTIN (alnv_ps, MIPS_V2SF_FTYPE_V2SF_V2SF_INT,
+ MASK_PAIRED_SINGLE_FLOAT),
DIRECT_BUILTIN (addr_ps, MIPS_V2SF_FTYPE_V2SF_V2SF, MASK_MIPS3D),
DIRECT_BUILTIN (mulr_ps, MIPS_V2SF_FTYPE_V2SF_V2SF, MASK_MIPS3D),
DIRECT_BUILTIN (cvt_pw_ps, MIPS_V2SF_FTYPE_V2SF, MASK_MIPS3D),
static const struct builtin_description sb1_bdesc[] =
{
- DIRECT_BUILTIN (sqrt_ps, MIPS_V2SF_FTYPE_V2SF, MASK_PAIRED_SINGLE)
+ 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_<INSN>. 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<VALUE>. <VALUE> 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
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
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;
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:
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;
}
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. */
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],
/* 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:
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;
+}
+\f
+/* 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);
+}
+
\f
#include "gt-mips.h"