aboutsummaryrefslogtreecommitdiffstats
path: root/gcc-4.9/gcc/config/mips/mips.c
diff options
context:
space:
mode:
Diffstat (limited to 'gcc-4.9/gcc/config/mips/mips.c')
-rw-r--r--gcc-4.9/gcc/config/mips/mips.c1907
1 files changed, 1184 insertions, 723 deletions
diff --git a/gcc-4.9/gcc/config/mips/mips.c b/gcc-4.9/gcc/config/mips/mips.c
index cf3894a8e..524c6d52d 100644
--- a/gcc-4.9/gcc/config/mips/mips.c
+++ b/gcc-4.9/gcc/config/mips/mips.c
@@ -74,36 +74,14 @@ along with GCC; see the file COPYING3. If not see
/* Definitions used in ready queue reordering for first scheduling pass. */
-/* Register types. */
-#define GPREG 0
-#define VECREG 1
-
-/* Information about GP and vector register weights
- indexed by instruction UID. */
-struct msched_weight_info {
- int reg_weight_gp;
- int reg_weight_vec;
-};
-
-static msched_weight_info *regtype_weight = NULL;
-
-/* Current vector and GP register weights of scheduled instructions. */
-static int curr_regtype_pressure[2];
-
-/* Return GP register weight for INSN. */
-#define INSN_GPREG_WEIGHT(INSN) \
- regtype_weight[INSN_UID ((INSN))].reg_weight_gp
-
-/* Return vector register weight for INSN. */
-#define INSN_VECREG_WEIGHT(INSN) \
- regtype_weight[INSN_UID ((INSN))].reg_weight_vec
+static int *level = NULL;
+static int *consumer_luid = NULL;
-/* Return current register pressure for REG_TYPE. */
-#define CURR_REGTYPE_PRESSURE(REG_TYPE) \
- curr_regtype_pressure[(REG_TYPE)]
+#define LEVEL(INSN) \
+ level[INSN_UID ((INSN))]
-#define PROMOTE_HIGH_PRIORITY_PRESSURE 25
-#define PROMOTE_MAX_DEP_PRESSURE 15
+#define CONSUMER_LUID(INSN) \
+ consumer_luid[INSN_UID ((INSN))]
/* True if X is an UNSPEC wrapper around a SYMBOL_REF or LABEL_REF. */
#define UNSPEC_ADDRESS_P(X) \
@@ -198,7 +176,8 @@ static int curr_regtype_pressure[2];
/* Return the opcode to jump to register DEST. When the JR opcode is not
available use JALR $0, DEST. */
#define MIPS_JR(DEST) \
- (((DEST) << 21) | (ISA_HAS_JR ? 0x8 : 0x9))
+ (TARGET_CB_ALWAYS ? ((0x1b << 27) | ((DEST) << 16)) \
+ : (((DEST) << 21) | (ISA_HAS_JR ? 0x8 : 0x9)))
/* Return the opcode for:
@@ -802,8 +781,8 @@ static const struct mips_rtx_cost_data mips_rtx_cost_optimize_size = {
COSTS_N_INSNS (1), /* int_mult_di */
COSTS_N_INSNS (1), /* int_div_si */
COSTS_N_INSNS (1), /* int_div_di */
- 2, /* branch_cost */
- 4 /* memory_latency */
+ 2, /* branch_cost */
+ 4 /* memory_latency */
};
/* Costs to use when optimizing for speed, indexed by processor. */
@@ -990,6 +969,20 @@ static const struct mips_rtx_cost_data
4, /* branch_cost */
4 /* memory_latency */
},
+ /* Octeon III */
+ {
+ COSTS_N_INSNS (6), /* fp_add */
+ COSTS_N_INSNS (6), /* fp_mult_sf */
+ COSTS_N_INSNS (7), /* fp_mult_df */
+ COSTS_N_INSNS (25), /* fp_div_sf */
+ COSTS_N_INSNS (48), /* fp_div_df */
+ COSTS_N_INSNS (6), /* int_mult_si */
+ COSTS_N_INSNS (6), /* int_mult_di */
+ COSTS_N_INSNS (18), /* int_div_si */
+ COSTS_N_INSNS (35), /* int_div_di */
+ 4, /* branch_cost */
+ 4 /* memory_latency */
+ },
{ /* R3900 */
COSTS_N_INSNS (2), /* fp_add */
COSTS_N_INSNS (4), /* fp_mult_sf */
@@ -1224,7 +1217,7 @@ static const struct mips_rtx_cost_data
COSTS_N_INSNS (8), /* int_div_si */
COSTS_N_INSNS (8), /* int_div_di */
2, /* branch_cost */
- 10 /* memory_latency */
+ 4 /* memory_latency */
},
{ /* W32 */
COSTS_N_INSNS (4), /* fp_add */
@@ -1251,14 +1244,27 @@ static const struct mips_rtx_cost_data
COSTS_N_INSNS (41), /* int_div_di */
1, /* branch_cost */
4 /* memory_latency */
+ },
+ { /* I6400 */
+ COSTS_N_INSNS (4), /* fp_add */
+ COSTS_N_INSNS (5), /* fp_mult_sf */
+ COSTS_N_INSNS (5), /* fp_mult_df */
+ COSTS_N_INSNS (32), /* 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 (36), /* int_div_si */
+ COSTS_N_INSNS (36), /* int_div_di */
+ 2, /* branch_cost */
+ 4 /* memory_latency */
}
};
static rtx mips_find_pic_call_symbol (rtx, rtx, bool);
-static int mips_register_move_cost (enum machine_mode, reg_class_t,
+static int mips_register_move_cost (machine_mode, reg_class_t,
reg_class_t);
-static unsigned int mips_function_arg_boundary (enum machine_mode, const_tree);
-static enum machine_mode mips_get_reg_raw_mode (int regno);
+static unsigned int mips_function_arg_boundary (machine_mode, const_tree);
+static machine_mode mips_get_reg_raw_mode (int regno);
/* This hash table keeps track of implicit "mips16" and "nomips16" attributes
for -mflip_mips16. It maps decl names onto a boolean mode setting. */
@@ -1686,7 +1692,7 @@ mips_build_integer (struct mips_integer_op *codes,
/* Implement TARGET_LEGITIMATE_CONSTANT_P. */
static bool
-mips_legitimate_constant_p (enum machine_mode mode ATTRIBUTE_UNUSED, rtx x)
+mips_legitimate_constant_p (machine_mode mode ATTRIBUTE_UNUSED, rtx x)
{
return mips_const_insns (x) > 0;
}
@@ -1857,7 +1863,7 @@ mips_symbol_binds_local_p (const_rtx x)
}
bool
-mips_const_vector_bitimm_set_p (rtx op, enum machine_mode mode)
+mips_const_vector_bitimm_set_p (rtx op, machine_mode mode)
{
if (GET_CODE (op) == CONST_VECTOR && op != const0_rtx)
{
@@ -1879,7 +1885,7 @@ mips_const_vector_bitimm_set_p (rtx op, enum machine_mode mode)
}
bool
-mips_const_vector_bitimm_clr_p (rtx op, enum machine_mode mode)
+mips_const_vector_bitimm_clr_p (rtx op, machine_mode mode)
{
if (GET_CODE (op) == CONST_VECTOR && op != constm1_rtx)
{
@@ -1901,10 +1907,10 @@ mips_const_vector_bitimm_clr_p (rtx op, enum machine_mode mode)
}
/* Return true if OP is a constant vector with the number of units in MODE,
- and each unit has the same value. */
+ and each unit has the same value. */
bool
-mips_const_vector_same_val_p (rtx op, enum machine_mode mode)
+mips_const_vector_same_val_p (rtx op, machine_mode mode)
{
int i, nunits = GET_MODE_NUNITS (mode);
rtx first;
@@ -1921,10 +1927,10 @@ mips_const_vector_same_val_p (rtx op, enum machine_mode mode)
}
/* Return true if OP is a constant vector with the number of units in MODE,
- and each unit has the same value. */
+ and each unit has the same value. */
bool
-mips_const_vector_same_byte_p (rtx op, enum machine_mode mode)
+mips_const_vector_same_byte_p (rtx op, machine_mode mode)
{
int i, nunits = GET_MODE_NUNITS (mode);
rtx first;
@@ -1939,7 +1945,7 @@ mips_const_vector_same_byte_p (rtx op, enum machine_mode mode)
if (!rtx_equal_p (first, CONST_VECTOR_ELT (op, i)))
return false;
- /* it's a 8-bit mode don't care if signed or unsigned */
+ /* It's an 8-bit mode don't care if signed or unsigned. */
return true;
}
@@ -1947,7 +1953,7 @@ mips_const_vector_same_byte_p (rtx op, enum machine_mode mode)
and each unit has the same integer value in the range [LOW, HIGH]. */
bool
-mips_const_vector_same_int_p (rtx op, enum machine_mode mode, HOST_WIDE_INT low,
+mips_const_vector_same_int_p (rtx op, machine_mode mode, HOST_WIDE_INT low,
HOST_WIDE_INT high)
{
HOST_WIDE_INT value;
@@ -1968,7 +1974,7 @@ mips_const_vector_same_int_p (rtx op, enum machine_mode mode, HOST_WIDE_INT low,
data section. */
static bool
-mips_rtx_constant_in_small_data_p (enum machine_mode mode)
+mips_rtx_constant_in_small_data_p (machine_mode mode)
{
return (!TARGET_EMBEDDED_DATA
&& TARGET_LOCAL_SDATA
@@ -2221,7 +2227,7 @@ mips_symbolic_constant_p (rtx x, enum mips_symbol_context context,
extended ones. */
static int
-mips_symbol_insns_1 (enum mips_symbol_type type, enum machine_mode mode)
+mips_symbol_insns_1 (enum mips_symbol_type type, machine_mode mode)
{
if (mips_use_pcrel_pool_p[(int) type])
{
@@ -2333,7 +2339,7 @@ mips_symbol_insns_1 (enum mips_symbol_type type, enum machine_mode mode)
In both cases, instruction counts are based off BASE_INSN_LENGTH. */
static int
-mips_symbol_insns (enum mips_symbol_type type, enum machine_mode mode)
+mips_symbol_insns (enum mips_symbol_type type, machine_mode mode)
{
/* MSA LD.* and ST.* cannot support loading symbols via an immediate
operand. */
@@ -2355,7 +2361,7 @@ mips_tls_symbol_ref_1 (rtx *x, void *data ATTRIBUTE_UNUSED)
/* Implement TARGET_CANNOT_FORCE_CONST_MEM. */
static bool
-mips_cannot_force_const_mem (enum machine_mode mode, rtx x)
+mips_cannot_force_const_mem (machine_mode mode, rtx x)
{
enum mips_symbol_type type;
rtx base, offset;
@@ -2405,7 +2411,7 @@ mips_cannot_force_const_mem (enum machine_mode mode, rtx x)
constants when we're using a per-function constant pool. */
static bool
-mips_use_blocks_for_constant_p (enum machine_mode mode ATTRIBUTE_UNUSED,
+mips_use_blocks_for_constant_p (machine_mode mode ATTRIBUTE_UNUSED,
const_rtx x ATTRIBUTE_UNUSED)
{
return !TARGET_MIPS16_PCREL_LOADS;
@@ -2415,7 +2421,7 @@ mips_use_blocks_for_constant_p (enum machine_mode mode ATTRIBUTE_UNUSED,
STRICT_P is true if REG_OK_STRICT is in effect. */
int
-mips_regno_mode_ok_for_base_p (int regno, enum machine_mode mode,
+mips_regno_mode_ok_for_base_p (int regno, machine_mode mode,
bool strict_p)
{
if (!HARD_REGISTER_NUM_P (regno))
@@ -2443,7 +2449,7 @@ mips_regno_mode_ok_for_base_p (int regno, enum machine_mode mode,
STRICT_P is true if REG_OK_STRICT is in effect. */
static bool
-mips_valid_base_register_p (rtx x, enum machine_mode mode, bool strict_p)
+mips_valid_base_register_p (rtx x, machine_mode mode, bool strict_p)
{
if (!strict_p && GET_CODE (x) == SUBREG)
x = SUBREG_REG (x);
@@ -2456,7 +2462,7 @@ mips_valid_base_register_p (rtx x, enum machine_mode mode, bool strict_p)
can address a value of mode MODE. */
static bool
-mips_valid_offset_p (rtx x, enum machine_mode mode)
+mips_valid_offset_p (rtx x, machine_mode mode)
{
/* Check that X is a signed 16-bit number. */
if (!const_arith_operand (x, Pmode))
@@ -2469,7 +2475,7 @@ mips_valid_offset_p (rtx x, enum machine_mode mode)
return false;
/* MSA LD.* and ST.* supports 10-bit signed offsets. */
- if (MSA_SUPPORTED_VECTOR_MODE_P (mode)
+ if (MSA_SUPPORTED_MODE_P (mode)
&& !mips_signed_immediate_p (INTVAL (x), 10,
mips_ldst_scaled_shift (mode)))
return false;
@@ -2481,7 +2487,7 @@ mips_valid_offset_p (rtx x, enum machine_mode mode)
LO_SUM symbol has type SYMBOL_TYPE. */
static bool
-mips_valid_lo_sum_p (enum mips_symbol_type symbol_type, enum machine_mode mode)
+mips_valid_lo_sum_p (enum mips_symbol_type symbol_type, machine_mode mode)
{
/* Check that symbols of type SYMBOL_TYPE can be used to access values
of mode MODE. */
@@ -2513,7 +2519,7 @@ mips_valid_lo_sum_p (enum mips_symbol_type symbol_type, enum machine_mode mode)
static bool
mips_classify_address (struct mips_address_info *info, rtx x,
- enum machine_mode mode, bool strict_p)
+ machine_mode mode, bool strict_p)
{
switch (GET_CODE (x))
{
@@ -2572,7 +2578,7 @@ mips_classify_address (struct mips_address_info *info, rtx x,
/* Implement TARGET_LEGITIMATE_ADDRESS_P. */
static bool
-mips_legitimate_address_p (enum machine_mode mode, rtx x, bool strict_p)
+mips_legitimate_address_p (machine_mode mode, rtx x, bool strict_p)
{
struct mips_address_info addr;
@@ -2582,7 +2588,7 @@ mips_legitimate_address_p (enum machine_mode mode, rtx x, bool strict_p)
/* Return true if X is a legitimate $sp-based address for mode MDOE. */
bool
-mips_stack_address_p (rtx x, enum machine_mode mode)
+mips_stack_address_p (rtx x, machine_mode mode)
{
struct mips_address_info addr;
@@ -2619,7 +2625,7 @@ mips_lwxs_address_p (rtx addr)
sense, because their use is so restricted. */
static bool
-mips_lx_address_p (rtx addr, enum machine_mode mode)
+mips_lx_address_p (rtx addr, machine_mode mode)
{
if (GET_CODE (addr) != PLUS
|| !REG_P (XEXP (addr, 0))
@@ -2633,7 +2639,7 @@ mips_lx_address_p (rtx addr, enum machine_mode mode)
return true;
if (ISA_HAS_LDX && mode == DImode)
return true;
- if (ISA_HAS_MSA && MSA_SUPPORTED_MODE_P (mode))
+ if (MSA_SUPPORTED_MODE_P (mode))
return true;
return false;
}
@@ -2648,7 +2654,7 @@ mips_lx_address_p (rtx addr, enum machine_mode mode)
an 8-bit immediate field that's shifted left twice. */
static bool
-mips16_unextended_reference_p (enum machine_mode mode, rtx base,
+mips16_unextended_reference_p (machine_mode mode, rtx base,
unsigned HOST_WIDE_INT offset)
{
if (mode != BLKmode && offset % GET_MODE_SIZE (mode) == 0)
@@ -2668,11 +2674,11 @@ mips16_unextended_reference_p (enum machine_mode mode, rtx base,
enough. */
int
-mips_address_insns (rtx x, enum machine_mode mode, bool might_split_p)
+mips_address_insns (rtx x, machine_mode mode, bool might_split_p)
{
struct mips_address_info addr;
int factor;
- bool msa_p = (TARGET_MSA && !might_split_p && MSA_SUPPORTED_MODE_P (mode));
+ bool msa_p = (!might_split_p && MSA_SUPPORTED_MODE_P (mode));
/* BLKmode is used for single unaligned loads and stores and should
not count as a multiword mode. (GET_MODE_SIZE (BLKmode) is pretty
@@ -2690,9 +2696,8 @@ mips_address_insns (rtx x, enum machine_mode mode, bool might_split_p)
if (msa_p)
{
/* MSA LD.* and ST.* supports 10-bit signed offsets. */
- if (MSA_SUPPORTED_VECTOR_MODE_P (mode)
- && mips_signed_immediate_p (INTVAL (addr.offset), 10,
- mips_ldst_scaled_shift (mode)))
+ if (mips_signed_immediate_p (INTVAL (addr.offset), 10,
+ mips_ldst_scaled_shift (mode)))
return 1;
else
return 0;
@@ -2734,10 +2739,10 @@ mips_signed_immediate_p (unsigned HOST_WIDE_INT x, int bits, int shift = 0)
return mips_unsigned_immediate_p (x, bits, shift);
}
-/* Return the scale shift that applied to MSA LD/ST address offset */
+/* Return the scale shift that applied to MSA LD/ST address offset. */
int
-mips_ldst_scaled_shift (enum machine_mode mode)
+mips_ldst_scaled_shift (machine_mode mode)
{
int shift = exact_log2 (GET_MODE_UNIT_SIZE (mode));
@@ -2752,7 +2757,7 @@ mips_ldst_scaled_shift (enum machine_mode mode)
OFFSET_PREDICATE. */
bool
-m16_based_address_p (rtx x, enum machine_mode mode,
+m16_based_address_p (rtx x, machine_mode mode,
insn_operand_predicate_fn offset_predicate)
{
struct mips_address_info addr;
@@ -2767,7 +2772,7 @@ m16_based_address_p (rtx x, enum machine_mode mode,
for a microMIPS LWSP or SWSP insn. */
bool
-lwsp_swsp_address_p (rtx x, enum machine_mode mode)
+lwsp_swsp_address_p (rtx x, machine_mode mode)
{
struct mips_address_info addr;
@@ -2781,7 +2786,7 @@ lwsp_swsp_address_p (rtx x, enum machine_mode mode)
MODE is the mode of the value being accessed. */
bool
-umips_12bit_offset_address_p (rtx x, enum machine_mode mode)
+umips_12bit_offset_address_p (rtx x, machine_mode mode)
{
struct mips_address_info addr;
@@ -2795,7 +2800,7 @@ umips_12bit_offset_address_p (rtx x, enum machine_mode mode)
MODE is the mode of the value being accessed. */
bool
-mips_9bit_offset_address_p (rtx x, enum machine_mode mode)
+mips_9bit_offset_address_p (rtx x, machine_mode mode)
{
struct mips_address_info addr;
@@ -2846,7 +2851,7 @@ mips_const_insns (rtx x)
if (TARGET_MSA
&& mips_const_vector_same_int_p (x, GET_MODE (x), -512, 511))
return 1;
- /* fall through. */
+ /* Fall through. */
case CONST_DOUBLE:
/* Allow zeros for normal mode, where we can use $0. */
return !TARGET_MIPS16 && x == CONST0_RTX (GET_MODE (x)) ? 1 : 0;
@@ -2907,23 +2912,24 @@ mips_split_const_insns (rtx x)
return low + high;
}
-/* X is a 128-bit constant that can be handled by splitting it into
- two or four words and loading each word separately. Return the number of
- instructions required to do this. */
+/* Return one word of 128-bit value OP, taking into account the fixed
+ endianness of certain registers. BYTE selects from the byte address. */
-int
-mips_split_128bit_const_insns (rtx x)
+rtx
+mips_subword_at_byte (rtx op, unsigned int byte)
{
- int byte;
- unsigned int elem, total = 0;
+ machine_mode mode;
- for (byte = 0; byte < GET_MODE_SIZE (TImode); byte += UNITS_PER_WORD)
- {
- elem = mips_const_insns (mips_subword_at_byte (x, byte));
- gcc_assert (elem > 0);
- total += elem;
- }
- return total;
+ mode = GET_MODE (op);
+ if (mode == VOIDmode)
+ mode = TImode;
+
+ gcc_assert (!FP_REG_RTX_P (op));
+
+ if (MEM_P (op))
+ return mips_rewrite_small_data (adjust_address (op, word_mode, byte));
+
+ return simplify_gen_subreg (word_mode, op, mode, byte);
}
/* Return the number of instructions needed to implement INSN,
@@ -2933,7 +2939,7 @@ mips_split_128bit_const_insns (rtx x)
int
mips_load_store_insns (rtx mem, rtx insn)
{
- enum machine_mode mode;
+ machine_mode mode;
bool might_split_p;
rtx set;
@@ -2948,12 +2954,6 @@ mips_load_store_insns (rtx mem, rtx insn)
if (set && !mips_split_move_insn_p (SET_DEST (set), SET_SRC (set), insn))
might_split_p = false;
}
- else if (GET_MODE_BITSIZE (mode) == 128)
- {
- set = single_set (insn);
- if (set && !mips_split_128bit_move_p (SET_DEST (set), SET_SRC (set)))
- might_split_p = false;
- }
return mips_address_insns (XEXP (mem, 0), mode, might_split_p);
}
@@ -3030,7 +3030,7 @@ mips_emit_unary (enum rtx_code code, rtx target, rtx op0)
Return that new register. */
static rtx
-mips_force_unary (enum machine_mode mode, enum rtx_code code, rtx op0)
+mips_force_unary (machine_mode mode, enum rtx_code code, rtx op0)
{
rtx reg;
@@ -3052,7 +3052,7 @@ mips_emit_binary (enum rtx_code code, rtx target, rtx op0, rtx op1)
of mode MODE. Return that new register. */
static rtx
-mips_force_binary (enum machine_mode mode, enum rtx_code code, rtx op0, rtx op1)
+mips_force_binary (machine_mode mode, enum rtx_code code, rtx op0, rtx op1)
{
rtx reg;
@@ -3300,7 +3300,7 @@ mips_got_load (rtx temp, rtx addr, enum mips_symbol_type type)
is guaranteed to be a legitimate address for mode MODE. */
bool
-mips_split_symbol (rtx temp, rtx addr, enum machine_mode mode, rtx *low_out)
+mips_split_symbol (rtx temp, rtx addr, machine_mode mode, rtx *low_out)
{
enum mips_symbol_context context;
enum mips_symbol_type symbol_type;
@@ -3560,7 +3560,7 @@ mips16_expand_set_fcsr (rtx newval)
/* If X is not a valid address for mode MODE, force it into a register. */
static rtx
-mips_force_address (rtx x, enum machine_mode mode)
+mips_force_address (rtx x, machine_mode mode)
{
if (!mips_legitimate_address_p (mode, x, false))
x = force_reg (Pmode, x);
@@ -3574,7 +3574,7 @@ mips_force_address (rtx x, enum machine_mode mode)
static rtx
mips_legitimize_address (rtx x, rtx oldx ATTRIBUTE_UNUSED,
- enum machine_mode mode)
+ machine_mode mode)
{
rtx base, addr;
HOST_WIDE_INT offset;
@@ -3605,7 +3605,7 @@ void
mips_move_integer (rtx temp, rtx dest, unsigned HOST_WIDE_INT value)
{
struct mips_integer_op codes[MIPS_MAX_INTEGER_OPS];
- enum machine_mode mode;
+ machine_mode mode;
unsigned int i, num_ops;
rtx x;
@@ -3635,7 +3635,7 @@ mips_move_integer (rtx temp, rtx dest, unsigned HOST_WIDE_INT value)
move_operand. */
static void
-mips_legitimize_const_move (enum machine_mode mode, rtx dest, rtx src)
+mips_legitimize_const_move (machine_mode mode, rtx dest, rtx src)
{
rtx base, offset;
@@ -3686,12 +3686,16 @@ mips_legitimize_const_move (enum machine_mode mode, rtx dest, rtx src)
sequence that is valid. */
bool
-mips_legitimize_move (enum machine_mode mode, rtx dest, rtx src)
+mips_legitimize_move (machine_mode mode, rtx dest, rtx src)
{
- if (!register_operand (dest, mode) && !reg_or_0_operand (src, mode))
+ if (!register_operand (dest, mode) && !register_operand (src, mode))
{
- mips_emit_move (dest, force_reg (mode, src));
- return true;
+ if (TARGET_MIPS16 || !const_0_operand (src, mode)
+ || MSA_SUPPORTED_MODE_P (mode))
+ {
+ mips_emit_move (dest, force_reg (mode, src));
+ return true;
+ }
}
/* We need to deal with constants that would be legitimate
@@ -3932,7 +3936,7 @@ mips_binary_cost (rtx x, int single_cost, int double_cost, bool speed)
/* Return the cost of floating-point multiplications of mode MODE. */
static int
-mips_fp_mult_cost (enum machine_mode mode)
+mips_fp_mult_cost (machine_mode mode)
{
return mode == DFmode ? mips_cost->fp_mult_df : mips_cost->fp_mult_sf;
}
@@ -3940,7 +3944,7 @@ mips_fp_mult_cost (enum machine_mode mode)
/* Return the cost of floating-point divisions of mode MODE. */
static int
-mips_fp_div_cost (enum machine_mode mode)
+mips_fp_div_cost (machine_mode mode)
{
return mode == DFmode ? mips_cost->fp_div_df : mips_cost->fp_div_sf;
}
@@ -3949,7 +3953,7 @@ mips_fp_div_cost (enum machine_mode mode)
cost of OP itself. */
static int
-mips_sign_extend_cost (enum machine_mode mode, rtx op)
+mips_sign_extend_cost (machine_mode mode, rtx op)
{
if (MEM_P (op))
/* Extended loads are as cheap as unextended ones. */
@@ -3971,7 +3975,7 @@ mips_sign_extend_cost (enum machine_mode mode, rtx op)
cost of OP itself. */
static int
-mips_zero_extend_cost (enum machine_mode mode, rtx op)
+mips_zero_extend_cost (machine_mode mode, rtx op)
{
if (MEM_P (op))
/* Extended loads are as cheap as unextended ones. */
@@ -3997,7 +4001,7 @@ mips_zero_extend_cost (enum machine_mode mode, rtx op)
assuming that the move will be in pieces of at most UNITS bytes. */
static int
-mips_set_reg_reg_piece_cost (enum machine_mode mode, unsigned int units)
+mips_set_reg_reg_piece_cost (machine_mode mode, unsigned int units)
{
return COSTS_N_INSNS ((GET_MODE_SIZE (mode) + units - 1) / units);
}
@@ -4005,7 +4009,7 @@ mips_set_reg_reg_piece_cost (enum machine_mode mode, unsigned int units)
/* Return the cost of moving between two registers of mode MODE. */
static int
-mips_set_reg_reg_cost (enum machine_mode mode)
+mips_set_reg_reg_cost (machine_mode mode)
{
switch (GET_MODE_CLASS (mode))
{
@@ -4030,7 +4034,7 @@ static bool
mips_rtx_costs (rtx x, int code, int outer_code, int opno ATTRIBUTE_UNUSED,
int *total, bool speed)
{
- enum machine_mode mode = GET_MODE (x);
+ machine_mode mode = GET_MODE (x);
bool float_mode_p = FLOAT_MODE_P (mode);
int cost;
rtx addr;
@@ -4309,17 +4313,18 @@ mips_rtx_costs (rtx x, int code, int outer_code, int opno ATTRIBUTE_UNUSED,
return false;
}
- /* If it's an add + mult (which is equivalent to shift left)
- * and it's immediate operand satisfies const_immlsa_operand
- * predicate. */
- if (ISA_HAS_LSA
- && mode == SImode
+ /* If it's an add + mult (which is equivalent to shift left) and
+ it's immediate operand satisfies const_immlsa_operand predicate. */
+ if (((ISA_HAS_LSA && mode == SImode)
+ || (ISA_HAS_DLSA && mode == DImode))
&& GET_CODE (XEXP (x, 0)) == MULT)
{
rtx op2 = XEXP (XEXP (x, 0), 1);
if (const_immlsa_operand (op2, mode))
{
- *total = 0;
+ *total = (COSTS_N_INSNS (1)
+ + set_src_cost (XEXP (XEXP (x, 0), 0), speed)
+ + set_src_cost (XEXP (x, 1), speed));
return true;
}
}
@@ -4359,11 +4364,15 @@ mips_rtx_costs (rtx x, int code, int outer_code, int opno ATTRIBUTE_UNUSED,
*total = COSTS_N_INSNS (GET_MODE_SIZE (mode) > UNITS_PER_WORD ? 4 : 1);
return false;
+ case FMA:
+ if (ISA_HAS_FP_MADDF_MSUBF)
+ *total = mips_fp_mult_cost (mode);
+ return false;
+
case MULT:
if (float_mode_p)
*total = mips_fp_mult_cost (mode);
else if (mode == DImode && !TARGET_64BIT)
- /* R6 impact ??? */
/* Synthesized from 2 mulsi3s, 1 mulsidi3 and two additions,
where the mulsidi3 always includes an MFHI and an MFLO. */
*total = (speed
@@ -4522,7 +4531,7 @@ mips_rtx_costs (rtx x, int code, int outer_code, int opno ATTRIBUTE_UNUSED,
/* Implement TARGET_ADDRESS_COST. */
static int
-mips_address_cost (rtx addr, enum machine_mode mode,
+mips_address_cost (rtx addr, machine_mode mode,
addr_space_t as ATTRIBUTE_UNUSED,
bool speed ATTRIBUTE_UNUSED)
{
@@ -4657,7 +4666,7 @@ rtx
mips_subword (rtx op, bool high_p)
{
unsigned int byte, offset;
- enum machine_mode mode;
+ machine_mode mode;
mode = GET_MODE (op);
if (mode == VOIDmode)
@@ -4681,26 +4690,6 @@ mips_subword (rtx op, bool high_p)
return simplify_gen_subreg (word_mode, op, mode, byte);
}
-/* Return one word of 128-bit value OP, taking into account the fixed
- endianness of certain registers. BYTE selects from the byte address. */
-
-rtx
-mips_subword_at_byte (rtx op, unsigned int byte)
-{
- enum machine_mode mode;
-
- mode = GET_MODE (op);
- if (mode == VOIDmode)
- mode = TImode;
-
- gcc_assert (!FP_REG_RTX_P (op));
-
- if (MEM_P (op))
- return mips_rewrite_small_data (adjust_address (op, word_mode, byte));
-
- return simplify_gen_subreg (word_mode, op, mode, byte);
-}
-
/* Return true if SRC should be moved into DEST using "MULT $0, $0".
SPLIT_TYPE is the condition under which moves should be split. */
@@ -4742,19 +4731,14 @@ mips_split_move_p (rtx dest, rtx src, enum mips_split_type split_type)
return false;
}
- /* Check if MSA moves need splitting. */
- if (MSA_SUPPORTED_MODE_P (GET_MODE (dest))
- || MSA_SUPPORTED_MODE_P (GET_MODE (src)))
+ /* Check if MSA moves need splitting. */
+ if (MSA_SUPPORTED_MODE_P (GET_MODE (dest)))
return mips_split_128bit_move_p (dest, src);
/* Otherwise split all multiword moves. */
return size > UNITS_PER_WORD;
}
-/* Determine if the DEST,SRC move insn applies to MSA. */
-#define MSA_SPLIT_P(DEST, SRC) \
- (MSA_SUPPORTED_MODE_P (GET_MODE (DEST)) && MSA_SUPPORTED_MODE_P (GET_MODE (SRC)))
-
/* Split a move from SRC to DEST, given that mips_split_move_p holds.
SPLIT_TYPE describes the split condition. */
@@ -4764,8 +4748,9 @@ mips_split_move (rtx dest, rtx src, enum mips_split_type split_type)
rtx low_dest;
gcc_checking_assert (mips_split_move_p (dest, src, split_type));
- if (!MSA_SPLIT_P (dest, src)
- && (FP_REG_RTX_P (dest)|| FP_REG_RTX_P (src)))
+ if (MSA_SUPPORTED_MODE_P (GET_MODE (dest)))
+ mips_split_128bit_move (dest, src);
+ else if (FP_REG_RTX_P (dest) || FP_REG_RTX_P (src))
{
if (!TARGET_64BIT && GET_MODE (dest) == DImode)
emit_insn (gen_move_doubleword_fprdi (dest, src));
@@ -4801,13 +4786,6 @@ mips_split_move (rtx dest, rtx src, enum mips_split_type split_type)
else
emit_insn (gen_mfhisi_di (mips_subword (dest, true), src));
}
- else if (MSA_SPLIT_P (dest, src))
- {
- /* Temporary sanity check should only get here if
- * a 128bit move needed spliting. */
- gcc_assert (mips_split_128bit_move_p (dest, src));
- mips_split_128bit_move (dest, src);
- }
else
{
/* The operation can be split into two normal moves. Decide in
@@ -4845,8 +4823,8 @@ mips_insn_split_type (rtx insn)
return SPLIT_IF_NECESSARY;
}
-/* Return true if a 128-bit move from SRC to DEST should be split into two
- or four. */
+/* Return true if a 128-bit move from SRC to DEST should be split. */
+
bool
mips_split_128bit_move_p (rtx dest, rtx src)
{
@@ -4860,7 +4838,8 @@ mips_split_128bit_move_p (rtx dest, rtx src)
if (FP_REG_RTX_P (src) && MEM_P (dest))
return false;
- /* Check for MSA set to an immediate const vector with valid replicated element. */
+ /* Check for MSA set to an immediate const vector with valid replicated
+ element. */
if (FP_REG_RTX_P (dest)
&& mips_const_vector_same_int_p (src, GET_MODE (src), -512, 511))
return false;
@@ -4874,7 +4853,7 @@ void
mips_split_128bit_move (rtx dest, rtx src)
{
int byte, index;
- rtx low_dest, low_src, d, s, last_d, last_s;
+ rtx low_dest, low_src, d, s;
if (FP_REG_RTX_P (dest))
{
@@ -4930,74 +4909,37 @@ mips_split_128bit_move (rtx dest, rtx src)
emit_insn (gen_msa_copy_s_d (d, new_src, GEN_INT (index)));
}
}
- else if (REG_P (dest) && REGNO (dest) == MD_REG_FIRST)
- {
- gcc_assert (TARGET_64BIT);
-
- low_dest = mips_subword (dest, false);
- mips_emit_move (low_dest, mips_subword (src, false));
- emit_insn (gen_mthidi_ti (dest, mips_subword (src, true), low_dest));
- }
- else if (REG_P (src) && REGNO (src) == MD_REG_FIRST)
- {
- gcc_assert (TARGET_64BIT);
-
- mips_emit_move (mips_subword (dest, false), mips_subword (src, false));
- emit_insn (gen_mfhidi_ti (mips_subword (dest, true), src));
- }
else
{
- low_dest = mips_subword_at_byte (dest, false);
- low_src = mips_subword_at_byte (src, false);
- last_d = NULL;
- last_s = NULL;
- if (REG_P (low_dest) && REG_P (low_src))
+ low_dest = mips_subword_at_byte (dest, 0);
+ low_src = mips_subword_at_byte (src, 0);
+ gcc_assert (REG_P (low_dest) && REG_P (low_src));
+ /* Make sure the source register is not written before reading. */
+ if (REGNO (low_dest) <= REGNO (low_src))
{
- /* Make sure the source register is not written before reading. */
- if (REGNO (low_dest) <= REGNO (low_src))
+ for (byte = 0; byte < GET_MODE_SIZE (TImode);
+ byte += UNITS_PER_WORD)
{
- for (byte = 0; byte < GET_MODE_SIZE (TImode);
- byte += UNITS_PER_WORD)
- {
- d = mips_subword_at_byte (dest, byte);
- s = mips_subword_at_byte (src, byte);
- mips_emit_move (d, s);
- }
- }
- else
- {
- for (byte = GET_MODE_SIZE (TImode) - UNITS_PER_WORD; byte >= 0;
- byte -= UNITS_PER_WORD)
- {
- d = mips_subword_at_byte (dest, byte);
- s = mips_subword_at_byte (src, byte);
- mips_emit_move (d, s);
- }
+ d = mips_subword_at_byte (dest, byte);
+ s = mips_subword_at_byte (src, byte);
+ mips_emit_move (d, s);
}
}
else
{
- for (byte = 0; byte < GET_MODE_SIZE (TImode); byte += UNITS_PER_WORD)
+ for (byte = GET_MODE_SIZE (TImode) - UNITS_PER_WORD; byte >= 0;
+ byte -= UNITS_PER_WORD)
{
d = mips_subword_at_byte (dest, byte);
s = mips_subword_at_byte (src, byte);
- if (REG_P (low_dest) && reg_overlap_mentioned_p (d, src))
- {
- gcc_assert (last_d == NULL && last_s == NULL);
- last_d = d;
- last_s = s;
- }
- else
- mips_emit_move (d, s);
+ mips_emit_move (d, s);
}
- if (last_d != NULL && last_s != NULL)
- mips_emit_move (last_d, last_s);
}
}
}
-/* Split a COPY_S.D with operands DEST, SRC and INDEX. GEN is a function
- * used to generate subregs. */
+/* Split a COPY_S.D with operands DEST, SRC and INDEX. GEN is a function
+ used to generate subregs. */
void
mips_split_msa_copy_d (rtx dest, rtx src, rtx index,
@@ -5016,11 +4958,12 @@ mips_split_msa_copy_d (rtx dest, rtx src, rtx index,
emit_insn (gen_fn (high, new_src, GEN_INT (INTVAL (index) * 2 + 1)));
}
-/* Split a INSERT.D with operand DEST, SRC1.INDEX and SRC2. */
+/* Split a INSERT.D with operand DEST, SRC1.INDEX and SRC2. */
void
mips_split_msa_insert_d (rtx dest, rtx src1, rtx index, rtx src2)
{
+ int i;
gcc_assert (GET_MODE (dest) == GET_MODE (src1));
gcc_assert ((GET_MODE (dest) == V2DImode
&& (GET_MODE (src2) == DImode || src2 == const0_rtx))
@@ -5032,10 +4975,13 @@ mips_split_msa_insert_d (rtx dest, rtx src1, rtx index, rtx src2)
rtx high = mips_subword (src2, true);
rtx new_dest = simplify_gen_subreg (V4SImode, dest, GET_MODE (dest), 0);
rtx new_src1 = simplify_gen_subreg (V4SImode, src1, GET_MODE (src1), 0);
+ i = exact_log2 (INTVAL (index));
+ gcc_assert (i != -1);
+
emit_insn (gen_msa_insert_w (new_dest, new_src1,
- GEN_INT (INTVAL (index) * 2), low));
+ GEN_INT (i * 2), low));
emit_insn (gen_msa_insert_w (new_dest, new_dest,
- GEN_INT (INTVAL (index) * 2 + 1), high));
+ GEN_INT (i * 2 + 1), high));
}
/* Split fill.d. */
@@ -5089,20 +5035,25 @@ mips_split_move_insn (rtx dest, rtx src, rtx insn)
const char *
mips_output_move (rtx dest, rtx src)
{
- enum rtx_code dest_code, src_code;
- enum machine_mode mode;
+ enum rtx_code dest_code = GET_CODE (dest);
+ enum rtx_code src_code = GET_CODE (src);
+ machine_mode mode = GET_MODE (dest);
+ bool dbl_p = (GET_MODE_SIZE (mode) == 8);
+ bool msa_p = MSA_SUPPORTED_MODE_P (mode);
enum mips_symbol_type symbol_type;
- bool dbl_p, msa_p;
-
- dest_code = GET_CODE (dest);
- src_code = GET_CODE (src);
- mode = GET_MODE (dest);
- dbl_p = (GET_MODE_SIZE (mode) == 8);
- msa_p = MSA_SUPPORTED_MODE_P (mode);
if (mips_split_move_p (dest, src, SPLIT_IF_NECESSARY))
return "#";
+ if (msa_p
+ && dest_code == REG && FP_REG_P (REGNO (dest))
+ && src_code == CONST_VECTOR
+ && CONST_INT_P (CONST_VECTOR_ELT (src, 0)))
+ {
+ gcc_assert (const_yi_operand (src, mode));
+ return "ldi.%v0\t%w0,%E1";
+ }
+
if ((src_code == REG && GP_REG_P (REGNO (src)))
|| (!TARGET_MIPS16 && src == CONST0_RTX (mode)))
{
@@ -5121,7 +5072,12 @@ mips_output_move (rtx dest, rtx src)
/* Moves to HI are handled by special .md insns. */
if (REGNO (dest) == LO_REGNUM)
- return "mtlo\t%z1";
+ {
+ if (ISA_HAS_MULT)
+ return "mtlo\t%z1";
+ else
+ return "mtlo\t%z1,$ac0";
+ }
if (DSP_ACC_REG_P (REGNO (dest)))
{
@@ -5136,17 +5092,8 @@ mips_output_move (rtx dest, rtx src)
{
if (msa_p)
{
- enum machine_mode dstmode = GET_MODE (dest);
-
gcc_assert (src == CONST0_RTX (GET_MODE (src)));
-
- if (MSA_SUPPORTED_MODE_P (dstmode))
- {
- if (dstmode == TImode)
- return "ldi.b\t%w0,0";
- else
- return "ldi.%v0\t%w0,0";
- }
+ return "ldi.%v0\t%w0,0";
}
return dbl_p ? "dmtc1\t%z1,%0" : "mtc1\t%z1,%0";
@@ -5183,7 +5130,10 @@ mips_output_move (rtx dest, rtx src)
-mfix-vr4130. */
if (ISA_HAS_MACCHI)
return dbl_p ? "dmacc\t%0,%.,%." : "macc\t%0,%.,%.";
- return "mflo\t%0";
+ if (ISA_HAS_MULT)
+ return "mflo\t%0";
+ else
+ return "mflo\t%0,$ac0";
}
if (DSP_ACC_REG_P (REGNO (src)))
@@ -5272,16 +5222,8 @@ mips_output_move (rtx dest, rtx src)
if (dest_code == MEM)
{
- if (MSA_SUPPORTED_MODE_P (mode))
- {
- if (mode == TImode)
- {
- /* Just use st.d/st.w to store. */
- return TARGET_64BIT ? "st.d\t%w1,%0" : "st.w\t%w1,%0";
- }
- else
- return "st.%v1\t%w1,%0";
- }
+ if (msa_p)
+ return "st.%v1\t%w1,%0";
return dbl_p ? "sdc1\t%1,%0" : "swc1\t%1,%0";
}
@@ -5290,16 +5232,8 @@ mips_output_move (rtx dest, rtx src)
{
if (src_code == MEM)
{
- if (MSA_SUPPORTED_MODE_P (mode))
- {
- if (mode == TImode)
- {
- /* Just use ld.d/ld.w to load. */
- return TARGET_64BIT ? "ld.d\t%w0,%1" : "ld.w\t%w0,%1";
- }
- else
- return "ld.%v0\t%w0,%1";
- }
+ if (msa_p)
+ return "ld.%v0\t%w0,%1";
return dbl_p ? "ldc1\t%0,%1" : "lwc1\t%0,%1";
}
@@ -5362,7 +5296,7 @@ mips_int_order_operand_ok_p (enum rtx_code code, rtx cmp1)
static bool
mips_canonicalize_int_order_test (enum rtx_code *code, rtx *cmp1,
- enum machine_mode mode)
+ machine_mode mode)
{
HOST_WIDE_INT plus_one;
@@ -5407,7 +5341,7 @@ static void
mips_emit_int_order_test (enum rtx_code code, bool *invert_ptr,
rtx target, rtx cmp0, rtx cmp1)
{
- enum machine_mode mode;
+ machine_mode mode;
/* First see if there is a MIPS instruction that can do this operation.
If not, try doing the same for the inverse operation. If that also
@@ -5511,7 +5445,7 @@ mips_reversed_fp_cond (enum rtx_code *code)
a simple round-robin allocation scheme. */
static rtx
-mips_allocate_fcc (enum machine_mode mode)
+mips_allocate_fcc (machine_mode mode)
{
unsigned int regno, count;
@@ -5544,7 +5478,8 @@ mips_allocate_fcc (enum machine_mode mode)
conditions are:
- EQ or NE between two registers.
- - any comparison between a register and zero. */
+ - any comparison between a register and zero.
+ - if mips R6 then any of the conditional branches are valid. */
static void
mips_emit_compare (enum rtx_code *code, rtx *op0, rtx *op1, bool need_eq_ne_p)
@@ -5566,6 +5501,44 @@ mips_emit_compare (enum rtx_code *code, rtx *op0, rtx *op1, bool need_eq_ne_p)
else
*op1 = force_reg (GET_MODE (cmp_op0), cmp_op1);
}
+ else if (!need_eq_ne_p && TARGET_CB_MAYBE)
+ {
+ bool swap = false;
+ switch (*code)
+ {
+ case LE:
+ swap = true;
+ *code = GE;
+ break;
+ case GT:
+ swap = true;
+ *code = LT;
+ break;
+ case LEU:
+ swap = true;
+ *code = GEU;
+ break;
+ case GTU:
+ swap = true;
+ *code = LTU;
+ break;
+ case GE:
+ case LT:
+ case GEU:
+ case LTU:
+ /* Do nothing. */
+ break;
+ default:
+ gcc_unreachable ();
+ }
+ *op1 = force_reg (GET_MODE (cmp_op0), cmp_op1);
+ if (swap)
+ {
+ rtx tmp = *op1;
+ *op1 = *op0;
+ *op0 = tmp;
+ }
+ }
else
{
/* The comparison needs a separate scc instruction. Store the
@@ -5596,7 +5569,7 @@ mips_emit_compare (enum rtx_code *code, rtx *op0, rtx *op1, bool need_eq_ne_p)
*CODE to the code that the branch or move should use. */
cmp_code = *code;
if (ISA_HAS_CCF)
- {
+ {
/* All FP conditions can be implemented directly with CMP.cond.fmt
or by reversing the operands. */
*code = NE;
@@ -5666,9 +5639,9 @@ mips_expand_conditional_branch (rtx *operands)
emit_jump_insn (gen_condjump (condition, operands[3]));
}
-/* Generate RTL to test OPERAND[1] the test is specified by GEN_FUN
- * then set OPERANDS[0] to 1 or 0 if test is true/false repectiveltyi
- * according to GEN_FN. */
+/* Generate RTL to test OPERAND[1]. The test is specified by GEN_FN,
+ then sets OPERANDS[0] to 1 or 0 if the test is true/false respectively
+ according to GEN_FN. */
void
mips_expand_msa_branch (rtx *operands, rtx (*gen_fn)(rtx, rtx, rtx))
@@ -5735,7 +5708,7 @@ mips_expand_conditional_move (rtx *operands)
&& register_operand (operands[2], VOIDmode)
&& register_operand (operands[3], VOIDmode))
{
- enum machine_mode mode = GET_MODE (operands[0]);
+ machine_mode mode = GET_MODE (operands[0]);
rtx temp = gen_reg_rtx (mode);
rtx temp2 = gen_reg_rtx (mode);
@@ -5774,7 +5747,7 @@ void
mips_expand_conditional_trap (rtx comparison)
{
rtx op0, op1;
- enum machine_mode mode;
+ machine_mode mode;
enum rtx_code code;
/* MIPS conditional trap instructions don't have GT or LE flavors,
@@ -5826,7 +5799,7 @@ mips_init_cumulative_args (CUMULATIVE_ARGS *cum, tree fntype)
static void
mips_get_arg_info (struct mips_arg_info *info, const CUMULATIVE_ARGS *cum,
- enum machine_mode mode, const_tree type, bool named)
+ machine_mode mode, const_tree type, bool named)
{
bool doubleword_aligned_p;
unsigned int num_bytes, num_words, max_regs;
@@ -5873,7 +5846,6 @@ mips_get_arg_info (struct mips_arg_info *info, const CUMULATIVE_ARGS *cum,
than a variable argument. */
gcc_assert (TARGET_PAIRED_SINGLE_FLOAT || mode != V2SFmode);
info->fpr_p = (named
- && named
&& (type == 0 || FLOAT_TYPE_P (type))
&& (GET_MODE_CLASS (mode) == MODE_FLOAT
|| GET_MODE_CLASS (mode) == MODE_COMPLEX_FLOAT
@@ -5966,7 +5938,7 @@ mips_strict_argument_naming (cumulative_args_t ca ATTRIBUTE_UNUSED)
/* Implement TARGET_FUNCTION_ARG. */
static rtx
-mips_function_arg (cumulative_args_t cum_v, enum machine_mode mode,
+mips_function_arg (cumulative_args_t cum_v, machine_mode mode,
const_tree type, bool named)
{
CUMULATIVE_ARGS *cum = get_cumulative_args (cum_v);
@@ -5979,7 +5951,7 @@ mips_function_arg (cumulative_args_t cum_v, enum machine_mode mode,
if (mode == VOIDmode)
{
if (TARGET_MIPS16 && cum->fp_code != 0)
- return gen_rtx_REG ((enum machine_mode) cum->fp_code, 0);
+ return gen_rtx_REG ((machine_mode) cum->fp_code, 0);
else
return NULL;
}
@@ -6062,7 +6034,7 @@ mips_function_arg (cumulative_args_t cum_v, enum machine_mode mode,
&& GET_MODE_CLASS (mode) == MODE_COMPLEX_FLOAT)
{
rtx real, imag;
- enum machine_mode inner;
+ machine_mode inner;
unsigned int regno;
inner = GET_MODE_INNER (mode);
@@ -6093,7 +6065,7 @@ mips_function_arg (cumulative_args_t cum_v, enum machine_mode mode,
/* Implement TARGET_FUNCTION_ARG_ADVANCE. */
static void
-mips_function_arg_advance (cumulative_args_t cum_v, enum machine_mode mode,
+mips_function_arg_advance (cumulative_args_t cum_v, machine_mode mode,
const_tree type, bool named)
{
CUMULATIVE_ARGS *cum = get_cumulative_args (cum_v);
@@ -6131,7 +6103,7 @@ mips_function_arg_advance (cumulative_args_t cum_v, enum machine_mode mode,
static int
mips_arg_partial_bytes (cumulative_args_t cum,
- enum machine_mode mode, tree type, bool named)
+ machine_mode mode, tree type, bool named)
{
struct mips_arg_info info;
@@ -6144,7 +6116,7 @@ mips_arg_partial_bytes (cumulative_args_t cum,
to STACK_BOUNDARY bits if the type requires it. */
static unsigned int
-mips_function_arg_boundary (enum machine_mode mode, const_tree type)
+mips_function_arg_boundary (machine_mode mode, const_tree type)
{
unsigned int alignment;
@@ -6156,15 +6128,14 @@ mips_function_arg_boundary (enum machine_mode mode, const_tree type)
return alignment;
}
-/* Implement TARGET_GET_RAW_*_MODE. */
+/* Implement TARGET_GET_RAW_RESULT_MODE and TARGET_GET_RAW_ARG_MODE. */
-static enum machine_mode
+static machine_mode
mips_get_reg_raw_mode (int regno)
{
- if ((mips_abi == ABI_32 && !TARGET_FLOAT32)
- && FP_REG_P (regno))
+ if (TARGET_FLOATXX && FP_REG_P (regno))
return DFmode;
- return default_get_reg_raw_mode(regno);
+ return default_get_reg_raw_mode (regno);
}
/* Return true if FUNCTION_ARG_PADDING (MODE, TYPE) should return
@@ -6173,7 +6144,7 @@ mips_get_reg_raw_mode (int regno)
byte does. */
bool
-mips_pad_arg_upward (enum machine_mode mode, const_tree type)
+mips_pad_arg_upward (machine_mode mode, const_tree type)
{
/* On little-endian targets, the first byte of every stack argument
is passed in the first byte of the stack slot. */
@@ -6211,7 +6182,7 @@ mips_pad_arg_upward (enum machine_mode mode, const_tree type)
the opposite if the most significant byte does. */
bool
-mips_pad_reg_upward (enum machine_mode mode, tree type)
+mips_pad_reg_upward (machine_mode mode, tree type)
{
/* No shifting is required for floating-point arguments. */
if (type != 0 ? FLOAT_TYPE_P (type) : GET_MODE_CLASS (mode) == MODE_FLOAT)
@@ -6226,7 +6197,7 @@ mips_pad_reg_upward (enum machine_mode mode, tree type)
static bool
mips_pass_by_reference (cumulative_args_t cum ATTRIBUTE_UNUSED,
- enum machine_mode mode, const_tree type,
+ machine_mode mode, const_tree type,
bool named ATTRIBUTE_UNUSED)
{
if (mips_abi == ABI_EABI)
@@ -6253,7 +6224,7 @@ mips_pass_by_reference (cumulative_args_t cum ATTRIBUTE_UNUSED,
static bool
mips_callee_copies (cumulative_args_t cum ATTRIBUTE_UNUSED,
- enum machine_mode mode ATTRIBUTE_UNUSED,
+ machine_mode mode ATTRIBUTE_UNUSED,
const_tree type ATTRIBUTE_UNUSED, bool named)
{
return mips_abi == ABI_EABI && named;
@@ -6322,7 +6293,7 @@ mips_return_in_msb (const_tree valtype)
floating-point register. */
static bool
-mips_return_mode_in_fpr_p (enum machine_mode mode)
+mips_return_mode_in_fpr_p (machine_mode mode)
{
gcc_assert (TARGET_PAIRED_SINGLE_FLOAT || mode != V2SFmode);
return ((GET_MODE_CLASS (mode) == MODE_FLOAT
@@ -6342,8 +6313,8 @@ mips_return_mode_in_fpr_p (enum machine_mode mode)
the structure itself has mode BLKmode. */
static rtx
-mips_return_fpr_single (enum machine_mode type_mode,
- enum machine_mode value_mode)
+mips_return_fpr_single (machine_mode type_mode,
+ machine_mode value_mode)
{
rtx x;
@@ -6365,9 +6336,9 @@ mips_return_fpr_single (enum machine_mode type_mode,
Otherwise the values are packed together as closely as possible. */
static rtx
-mips_return_fpr_pair (enum machine_mode mode,
- enum machine_mode mode1, HOST_WIDE_INT offset1,
- enum machine_mode mode2, HOST_WIDE_INT offset2)
+mips_return_fpr_pair (machine_mode mode,
+ machine_mode mode1, HOST_WIDE_INT offset1,
+ machine_mode mode2, HOST_WIDE_INT offset2)
{
int inc;
@@ -6390,7 +6361,7 @@ mips_return_fpr_pair (enum machine_mode mode,
static rtx
mips_function_value_1 (const_tree valtype, const_tree fn_decl_or_type,
- enum machine_mode mode)
+ machine_mode mode)
{
if (valtype)
{
@@ -6480,7 +6451,7 @@ mips_function_value (const_tree valtype, const_tree fn_decl_or_type,
/* Implement TARGET_LIBCALL_VALUE. */
static rtx
-mips_libcall_value (enum machine_mode mode, const_rtx fun ATTRIBUTE_UNUSED)
+mips_libcall_value (machine_mode mode, const_rtx fun ATTRIBUTE_UNUSED)
{
return mips_function_value_1 (NULL_TREE, NULL_TREE, mode);
}
@@ -6492,19 +6463,24 @@ mips_libcall_value (enum machine_mode mode, const_rtx fun ATTRIBUTE_UNUSED)
static bool
mips_function_value_regno_p (const unsigned int regno)
{
+ /* Most types only require one GPR or one FPR for return values but for
+ hard-float two FPRs can be used for _Complex types (for all ABIs)
+ and long doubles (for n64). */
if (regno == GP_RETURN
|| regno == FP_RETURN
- || regno == FP_RETURN + 2
- || (LONG_DOUBLE_TYPE_SIZE == 128
- && FP_RETURN != GP_RETURN
+ || (FP_RETURN != GP_RETURN
&& regno == FP_RETURN + 2))
return true;
- if ((regno == FP_RETURN + 1
- || regno == FP_RETURN + 3)
+ /* For o32 FP32, _Complex double will be returned in four 32-bit registers.
+ This does not apply to o32 FPXX as floating-point function argument and
+ return registers are described as 64-bit even though floating-point
+ registers are primarily described as 32-bit internally.
+ See: mips_get_reg_raw_mode. */
+ if ((mips_abi == ABI_32 && TARGET_FLOAT32)
&& FP_RETURN != GP_RETURN
- && (mips_abi == ABI_32 && TARGET_FLOAT32)
- && FP_REG_P (regno))
+ && (regno == FP_RETURN + 1
+ || regno == FP_RETURN + 3))
return true;
return false;
@@ -6527,7 +6503,7 @@ mips_return_in_memory (const_tree type, const_tree fndecl ATTRIBUTE_UNUSED)
/* Implement TARGET_SETUP_INCOMING_VARARGS. */
static void
-mips_setup_incoming_varargs (cumulative_args_t cum, enum machine_mode mode,
+mips_setup_incoming_varargs (cumulative_args_t cum, machine_mode mode,
tree type, int *pretend_size ATTRIBUTE_UNUSED,
int no_rtl)
{
@@ -6566,7 +6542,7 @@ mips_setup_incoming_varargs (cumulative_args_t cum, enum machine_mode mode,
{
/* We can't use move_block_from_reg, because it will use
the wrong mode. */
- enum machine_mode mode;
+ machine_mode mode;
int off, i;
/* Set OFF to the offset from virtual_incoming_args_rtx of
@@ -7215,7 +7191,7 @@ static struct mips16_stub *mips16_stubs;
return mode MODE in the name of a MIPS16 function stub. */
static const char *
-mips16_call_stub_mode_suffix (enum machine_mode mode)
+mips16_call_stub_mode_suffix (machine_mode mode)
{
if (mode == SFmode)
return "sf";
@@ -7303,7 +7279,7 @@ mips_output_args_xfer (int fp_code, char direction)
for (f = (unsigned int) fp_code; f != 0; f >>= 2)
{
- enum machine_mode mode;
+ machine_mode mode;
struct mips_arg_info info;
if ((f & 3) == 1)
@@ -7428,7 +7404,7 @@ mips16_copy_fpr_return_value (void)
{
rtx fn, insn, retval;
tree return_type;
- enum machine_mode return_mode;
+ machine_mode return_mode;
const char *name;
return_type = DECL_RESULT (current_function_decl);
@@ -7669,7 +7645,7 @@ mips16_build_call_stub (rtx retval, rtx *fn_ptr, rtx args_size, int fp_code)
$18 is usually a call-saved register. */
fprintf (asm_out_file, "\tmove\t%s,%s\n",
reg_names[GP_REG_FIRST + 18], reg_names[RETURN_ADDR_REGNUM]);
- output_asm_insn (MIPS_CALL ("jal", &fn, 0, -1), &fn);
+ output_asm_insn (mips_output_jump (&fn, 0, -1, true), &fn);
fprintf (asm_out_file, "\t.cfi_register 31,18\n");
/* Move the result from floating-point registers to
@@ -7982,7 +7958,7 @@ mips_store_by_pieces_p (unsigned HOST_WIDE_INT size, unsigned int align)
LW/SWL/SWR sequence. This is often better than the 4 LIs and
4 SBs that we would generate when storing by pieces. */
if (align <= BITS_PER_UNIT)
- return size < 4;
+ return size < 4 || !ISA_HAS_LWL_LWR;
/* If the data is 2-byte aligned, then:
@@ -8017,7 +7993,9 @@ mips_store_by_pieces_p (unsigned HOST_WIDE_INT size, unsigned int align)
(c4) A block move of 8 bytes can use two LW/SW sequences or a single
LD/SD sequence, and in these cases we've traditionally preferred
the memory copy over the more bulky constant moves. */
- return size < 8;
+ return (size < 8
+ || (align < 4 * BITS_PER_UNIT
+ && !ISA_HAS_LWL_LWR));
}
/* Emit straight-line code to move LENGTH bytes from SRC to DEST.
@@ -8029,7 +8007,7 @@ mips_block_move_straight (rtx dest, rtx src, HOST_WIDE_INT length)
HOST_WIDE_INT offset, delta;
unsigned HOST_WIDE_INT bits;
int i;
- enum machine_mode mode;
+ machine_mode mode;
rtx *regs;
/* Work out how many bits to move at a time. If both operands have
@@ -8159,8 +8137,9 @@ mips_block_move_loop (rtx dest, rtx src, HOST_WIDE_INT length,
bool
mips_expand_block_move (rtx dest, rtx src, rtx length)
{
- /* Disable entirely for R6 initially. */
- if (!ISA_HAS_LWL_LWR)
+ if (!ISA_HAS_LWL_LWR
+ && (MEM_ALIGN (src) < BITS_PER_WORD
+ || MEM_ALIGN (dest) < BITS_PER_WORD))
return false;
if (CONST_INT_P (length))
@@ -8253,7 +8232,7 @@ mips_expand_atomic_qihi (union mips_gen_fn_ptrs generator,
rtx orig_addr, memsi_addr, memsi, shift, shiftsi, unshifted_mask;
rtx unshifted_mask_reg, mask, inverted_mask, si_op;
rtx res = NULL;
- enum machine_mode mode;
+ machine_mode mode;
mode = GET_MODE (mem);
@@ -8438,7 +8417,7 @@ mips_expand_ins_as_unaligned_store (rtx dest, rtx src, HOST_WIDE_INT width,
HOST_WIDE_INT bitpos)
{
rtx left, right;
- enum machine_mode mode;
+ machine_mode mode;
if (!mips_get_unaligned_mem (dest, width, bitpos, &left, &right))
return false;
@@ -8461,7 +8440,7 @@ mips_expand_ins_as_unaligned_store (rtx dest, rtx src, HOST_WIDE_INT width,
/* Return true if X is a MEM with the same size as MODE. */
bool
-mips_mem_fits_mode_p (enum machine_mode mode, rtx x)
+mips_mem_fits_mode_p (machine_mode mode, rtx x)
{
return (MEM_P (x)
&& MEM_SIZE_KNOWN_P (x)
@@ -8503,7 +8482,7 @@ mips_use_ins_ext_p (rtx op, HOST_WIDE_INT width, HOST_WIDE_INT bitpos)
mask_low_and_shift_len for the actual definition. */
bool
-mask_low_and_shift_p (enum machine_mode mode, rtx mask, rtx shift, int maxlen)
+mask_low_and_shift_p (machine_mode mode, rtx mask, rtx shift, int maxlen)
{
return IN_RANGE (mask_low_and_shift_len (mode, mask, shift), 1, maxlen);
}
@@ -8513,7 +8492,7 @@ mask_low_and_shift_p (enum machine_mode mode, rtx mask, rtx shift, int maxlen)
see the table in the comment before the pattern. */
bool
-and_operands_ok (enum machine_mode mode, rtx op1, rtx op2)
+and_operands_ok (machine_mode mode, rtx op1, rtx op2)
{
return (memory_operand (op1, mode)
? and_load_operand (op2, mode)
@@ -8527,7 +8506,7 @@ and_operands_ok (enum machine_mode mode, rtx op1, rtx op2)
return the length of the mask, otherwise return -1. */
int
-mask_low_and_shift_len (enum machine_mode mode, rtx mask, rtx shift)
+mask_low_and_shift_len (machine_mode mode, rtx mask, rtx shift)
{
HOST_WIDE_INT shval;
@@ -8772,7 +8751,7 @@ mips_pop_asm_switch (struct mips_asm_switch *asm_switch)
'!' Print "s" to use the short version if the delay slot contains a
16-bit instruction.
- See also mips_init_print_operand_pucnt. */
+ See also mips_init_print_operand_punct. */
static void
mips_print_operand_punctuation (FILE *file, int ch)
@@ -8856,7 +8835,8 @@ mips_print_operand_punctuation (FILE *file, int ch)
case ':':
/* When final_sequence is 0, the delay slot will be a nop. We can
- use the compact version for microMIPS. */
+ use the compact version where available. The %: formatter will
+ only be present if a compact form of the branch is available. */
if (final_sequence == 0)
putc ('c', file);
break;
@@ -8864,8 +8844,9 @@ mips_print_operand_punctuation (FILE *file, int ch)
case '!':
/* If the delay slot instruction is short, then use the
compact version. */
- if (final_sequence == 0
- || get_attr_length (XVECEXP (final_sequence, 0, 1)) == 2)
+ if (TARGET_MICROMIPS && !TARGET_INTERLINK_COMPRESSED && mips_isa_rev <= 5
+ && (final_sequence == 0
+ || get_attr_length (XVECEXP (final_sequence, 0, 1)) == 2))
putc ('s', file);
break;
@@ -8953,11 +8934,13 @@ mips_print_operand_punct_valid_p (unsigned char code)
/* Implement TARGET_PRINT_OPERAND. The MIPS-specific operand codes are:
+ 'E' Print CONST_INT_OP element 0 of a replicated CONST_VECTOR in decimal.
'X' Print CONST_INT OP in hexadecimal format.
'x' Print the low 16 bits of CONST_INT OP in hexadecimal format.
'd' Print CONST_INT OP in decimal.
'B' Print CONST_INT as an unsigned byte [0..255].
'm' Print one less than CONST_INT OP in decimal.
+ 'y' Print exact log2 of CONST_INT OP in decimal.
'h' Print the high-part relocation associated with OP, after stripping
any outermost HIGH.
'R' Print the low-part relocation associated with OP.
@@ -8976,7 +8959,6 @@ mips_print_operand_punct_valid_p (unsigned char code)
'L' Print the low-order register in a double-word register operand.
'M' Print high-order register in a double-word register operand.
'z' Print $0 if OP is zero, otherwise print OP normally.
- 'y' Print exact log2 of CONST_INT OP in decimal.
'b' Print the address of a memory operand, without offset.
'v' Print the insn size suffix b,h,w,d,f or d for vector modes V16QI,V8HI,V4SI,
V2SI,V4DF and V2DF. */
@@ -8997,6 +8979,18 @@ mips_print_operand (FILE *file, rtx op, int letter)
switch (letter)
{
+ case 'E':
+ if (GET_CODE (op) == CONST_VECTOR)
+ {
+ gcc_assert (mips_const_vector_same_val_p (op, GET_MODE (op)));
+ op = CONST_VECTOR_ELT (op, 0);
+ gcc_assert (CONST_INT_P (op));
+ fprintf (file, HOST_WIDE_INT_PRINT_DEC, INTVAL (op));
+ }
+ else
+ output_operand_lossage ("invalid use of '%%%c'", letter);
+ break;
+
case 'X':
if (CONST_INT_P (op))
fprintf (file, HOST_WIDE_INT_PRINT_HEX, INTVAL (op));
@@ -9038,6 +9032,26 @@ mips_print_operand (FILE *file, rtx op, int letter)
output_operand_lossage ("invalid use of '%%%c'", letter);
break;
+ case 'K':
+ if (CONST_INT_P (op))
+ {
+ int val = INTVAL (op);
+ int i;
+ for (i = 0; i < 16; i++)
+ {
+ if ((val & (1 << i)) == val)
+ {
+ fprintf (file, "%d", i);
+ break;
+ }
+ }
+ if (i == 16)
+ output_operand_lossage ("invalid use of '%%%c' - Mask inappropriate", letter);
+ }
+ else
+ output_operand_lossage ("invalid use of '%%%c'", letter);
+ break;
+
case 'm':
if (CONST_INT_P (op))
fprintf (file, HOST_WIDE_INT_PRINT_DEC, INTVAL (op) - 1);
@@ -9254,7 +9268,7 @@ mips_encode_section_info (tree decl, rtx rtl, int first)
/* Implement TARGET_SELECT_RTX_SECTION. */
static section *
-mips_select_rtx_section (enum machine_mode mode, rtx x,
+mips_select_rtx_section (machine_mode mode, rtx x,
unsigned HOST_WIDE_INT align)
{
/* ??? Consider using mergeable small data sections. */
@@ -9502,17 +9516,16 @@ static rtx
mips_dwarf_register_span (rtx reg)
{
rtx high, low;
- enum machine_mode mode;
+ machine_mode mode;
/* TARGET_FLOATXX is implemented as 32-bit floating-point registers but
- ensures that double precision registers are treated as if they were
+ ensures that double-precision registers are treated as if they were
64-bit physical registers. The code will run correctly with 32-bit or
- 64-bit registers which means that dwarf information cannot be precisely
- correct for all scenarios. We choose to state that the 64-bit values
- are stored in a single 64-bit 'piece'. This slightly unusual
- construct can then be interpreted as either a pair of registers if the
- registers are 32-bit or a single 64-bit register depending on
- hardware. */
+ 64-bit registers which means that dwarf information cannot be precise
+ for all scenarios. We choose to state that the 64-bit values are stored
+ in a single 64-bit 'piece'. This slightly unusual construct can then be
+ interpreted as either a pair of registers if the registers are 32-bit or
+ a single 64-bit register depending on hardware. */
mode = GET_MODE (reg);
if (FP_REG_P (REGNO (reg))
&& TARGET_FLOATXX
@@ -9537,6 +9550,19 @@ mips_dwarf_register_span (rtx reg)
return NULL_RTX;
}
+/* Implement TARGET_DWARF_FRAME_REG_MODE. */
+
+static machine_mode
+mips_dwarf_frame_reg_mode (int regno)
+{
+ machine_mode mode = default_dwarf_frame_reg_mode (regno);
+
+ if (FP_REG_P (regno) && mips_abi == ABI_32 && TARGET_FLOAT64)
+ mode = SImode;
+
+ return mode;
+}
+
/* DSP ALU can bypass data with no delays for the following pairs. */
enum insn_code dspalu_bypass_table[][2] =
{
@@ -9816,7 +9842,7 @@ mips_file_start (void)
fprintf (asm_out_file, "\t.nan\t%s\n",
mips_nan == MIPS_IEEE_754_2008 ? "2008" : "legacy");
-#ifdef HAVE_AS_MODULE
+#ifdef HAVE_AS_DOT_MODULE
/* Record the FP ABI. See below for comments. */
if (TARGET_NO_FLOAT)
#ifdef HAVE_AS_GNU_ATTRIBUTE
@@ -9856,7 +9882,7 @@ mips_file_start (void)
attr = 2;
/* 64-bit FP registers on a 32-bit target, -mips32r2 -mfp64.
Reserved attr=4.
- This case used 12 callee save double precision registers
+ This case used 12 callee-saved double-precision registers
and is deprecated. */
/* 64-bit or 32-bit FP registers on a 32-bit target, -mfpxx. */
else if (TARGET_FLOATXX)
@@ -11323,7 +11349,7 @@ typedef void (*mips_save_restore_fn) (rtx, rtx);
stack pointer. */
static void
-mips_save_restore_reg (enum machine_mode mode, int regno,
+mips_save_restore_reg (machine_mode mode, int regno,
HOST_WIDE_INT offset, mips_save_restore_fn fn)
{
rtx mem;
@@ -11491,7 +11517,7 @@ static void
mips_for_each_saved_gpr_and_fpr (HOST_WIDE_INT sp_offset,
mips_save_restore_fn fn)
{
- enum machine_mode fpr_mode;
+ machine_mode fpr_mode;
int regno;
const struct mips_frame_info *frame = &cfun->machine->frame;
HOST_WIDE_INT offset;
@@ -11526,7 +11552,16 @@ mips_for_each_saved_gpr_and_fpr (HOST_WIDE_INT sp_offset,
regno -= MAX_FPRS_PER_FMT)
if (BITSET_P (cfun->machine->frame.fmask, regno - FP_REG_FIRST))
{
- mips_save_restore_reg (fpr_mode, regno, offset, fn);
+ if (!TARGET_FLOAT64 && TARGET_DOUBLE_FLOAT
+ && (fixed_regs[regno] || fixed_regs[regno + 1]))
+ {
+ if (fixed_regs[regno])
+ mips_save_restore_reg (SFmode, regno + 1, offset, fn);
+ else
+ mips_save_restore_reg (SFmode, regno, offset, fn);
+ }
+ else
+ mips_save_restore_reg (fpr_mode, regno, offset, fn);
offset -= GET_MODE_SIZE (fpr_mode);
}
}
@@ -12624,7 +12659,7 @@ mips_can_use_return_insn (void)
The result of this function is cached in mips_hard_regno_mode_ok. */
static bool
-mips_hard_regno_mode_ok_p (unsigned int regno, enum machine_mode mode)
+mips_hard_regno_mode_ok_p (unsigned int regno, machine_mode mode)
{
unsigned int size;
enum mode_class mclass;
@@ -12645,7 +12680,7 @@ mips_hard_regno_mode_ok_p (unsigned int regno, enum machine_mode mode)
size = GET_MODE_SIZE (mode);
mclass = GET_MODE_CLASS (mode);
- if (GP_REG_P (regno) && mode != CCFmode)
+ if (GP_REG_P (regno) && mode != CCFmode && !MSA_SUPPORTED_MODE_P (mode))
return ((regno - GP_REG_FIRST) & 1) == 0 || size <= UNITS_PER_WORD;
/* For MSA, allow TImode and 128-bit vector modes in all FPR. */
@@ -12657,13 +12692,12 @@ mips_hard_regno_mode_ok_p (unsigned int regno, enum machine_mode mode)
|| (MIN_FPRS_PER_FMT == 1 && size <= UNITS_PER_FPREG)))
{
/* Deny use of odd-numbered registers for 32-bit data for
- the O32 FP64A ABI. */
- if (mips_abi == ABI_32 && TARGET_FLOAT64 && !TARGET_ODD_SPREG
- && size <= 4 && (regno & 1) != 0)
+ the o32 FP64A ABI. */
+ if (TARGET_O32_FP64A_ABI && size <= 4 && (regno & 1) != 0)
return false;
/* Prevent the use of odd-numbered registers for CCFmode with the
- O32-FPXX ABI, otherwise allow them.
+ o32 FPXX ABI, otherwise allow them.
The FPXX ABI does not permit double-precision data to be placed
in odd-numbered registers and double-precision compares write
them as 64-bit values. Without this restriction the R6 FPXX
@@ -12694,7 +12728,7 @@ mips_hard_regno_mode_ok_p (unsigned int regno, enum machine_mode mode)
/* Don't allow MSA vector modes in accumulators. */
if (ACC_REG_P (regno)
- && !MSA_SUPPORTED_VECTOR_MODE_P (mode)
+ && !MSA_SUPPORTED_MODE_P (mode)
&& (INTEGRAL_MODE_P (mode) || ALL_FIXED_POINT_MODE_P (mode)))
{
if (MD_REG_P (regno))
@@ -12735,7 +12769,7 @@ mips_hard_regno_mode_ok_p (unsigned int regno, enum machine_mode mode)
/* Implement HARD_REGNO_NREGS. */
unsigned int
-mips_hard_regno_nregs (int regno, enum machine_mode mode)
+mips_hard_regno_nregs (int regno, machine_mode mode)
{
if (ST_REG_P (regno))
/* The size of FP status registers is always 4, because they only hold
@@ -12758,7 +12792,7 @@ mips_hard_regno_nregs (int regno, enum machine_mode mode)
in mips_hard_regno_nregs. */
int
-mips_class_max_nregs (enum reg_class rclass, enum machine_mode mode)
+mips_class_max_nregs (enum reg_class rclass, machine_mode mode)
{
int size;
HARD_REG_SET left;
@@ -12797,8 +12831,8 @@ mips_class_max_nregs (enum reg_class rclass, enum machine_mode mode)
/* Implement CANNOT_CHANGE_MODE_CLASS. */
bool
-mips_cannot_change_mode_class (enum machine_mode from,
- enum machine_mode to,
+mips_cannot_change_mode_class (machine_mode from,
+ machine_mode to,
enum reg_class rclass)
{
/* Allow conversions between different Loongson integer vectors,
@@ -12840,7 +12874,7 @@ mips_cannot_change_mode_class (enum machine_mode from,
/* Implement target hook small_register_classes_for_mode_p. */
static bool
-mips_small_register_classes_for_mode_p (enum machine_mode mode
+mips_small_register_classes_for_mode_p (machine_mode mode
ATTRIBUTE_UNUSED)
{
return TARGET_MIPS16;
@@ -12850,7 +12884,7 @@ mips_small_register_classes_for_mode_p (enum machine_mode mode
or use the MSA's move.v instruction. */
static bool
-mips_mode_ok_for_mov_fmt_p (enum machine_mode mode)
+mips_mode_ok_for_mov_fmt_p (machine_mode mode)
{
switch (mode)
{
@@ -12862,7 +12896,7 @@ mips_mode_ok_for_mov_fmt_p (enum machine_mode mode)
return TARGET_HARD_FLOAT && TARGET_DOUBLE_FLOAT;
case V2SFmode:
- return TARGET_HARD_FLOAT;
+ return TARGET_HARD_FLOAT && TARGET_PAIRED_SINGLE_FLOAT;
default:
return MSA_SUPPORTED_MODE_P (mode);
@@ -12872,7 +12906,7 @@ mips_mode_ok_for_mov_fmt_p (enum machine_mode mode)
/* Implement MODES_TIEABLE_P. */
bool
-mips_modes_tieable_p (enum machine_mode mode1, enum machine_mode mode2)
+mips_modes_tieable_p (machine_mode mode1, machine_mode mode2)
{
/* FPRs allow no mode punning, so it's not worth tying modes if we'd
prefer to put one of them in FPRs. */
@@ -12922,21 +12956,17 @@ mips_canonicalize_move_class (reg_class_t rclass)
return rclass;
}
-/* Return the cost of moving a value of mode MODE from a register of
- class FROM to a GPR. Return 0 for classes that are unions of other
- classes handled by this function. */
+/* Return the cost of moving a value from a register of class FROM to a GPR.
+ Return 0 for classes that are unions of other classes handled by this
+ function. */
static int
-mips_move_to_gpr_cost (enum machine_mode mode, reg_class_t from)
+mips_move_to_gpr_cost (machine_mode mode, reg_class_t from)
{
switch (from)
{
case M16_REGS:
case GENERAL_REGS:
- /* Two or four move. */
- if (MSA_SUPPORTED_MODE_P (mode))
- return TARGET_64BIT ? 4 : 8;
-
/* A MIPS16 MOVE instruction, or a non-MIPS16 MOVE macro. */
return 2;
@@ -12945,17 +12975,9 @@ mips_move_to_gpr_cost (enum machine_mode mode, reg_class_t from)
return 6;
case FP_REGS:
- /* Two or four copy_s.*. */
- if (MSA_SUPPORTED_MODE_P (mode))
- return TARGET_64BIT ? 8 : 16;
-
/* MFC1, etc. */
return 4;
- case ST_REGS:
- /* Not possible. ST_REGS are never moved. */
- return 0;
-
case COP0_REGS:
case COP2_REGS:
case COP3_REGS:
@@ -12967,21 +12989,17 @@ mips_move_to_gpr_cost (enum machine_mode mode, reg_class_t from)
}
}
-/* Return the cost of moving a value of mode MODE from a GPR to a
- register of class TO. Return 0 for classes that are unions of
- other classes handled by this function. */
+/* Return the cost of moving a value from a GPR to a register of class TO.
+ Return 0 for classes that are unions of other classes handled by this
+ function. */
static int
-mips_move_from_gpr_cost (enum machine_mode mode, reg_class_t to)
+mips_move_from_gpr_cost (machine_mode mode, reg_class_t to)
{
switch (to)
{
case M16_REGS:
case GENERAL_REGS:
- /* Two or four move. */
- if (MSA_SUPPORTED_MODE_P (mode))
- return TARGET_64BIT ? 4: 8;
-
/* A MIPS16 MOVE instruction, or a non-MIPS16 MOVE macro. */
return 2;
@@ -12990,17 +13008,9 @@ mips_move_from_gpr_cost (enum machine_mode mode, reg_class_t to)
return 6;
case FP_REGS:
- /* Two or four insv.*. */
- if (MSA_SUPPORTED_MODE_P (mode))
- return TARGET_64BIT ? 8: 16;
-
/* MTC1, etc. */
return 4;
- case ST_REGS:
- /* Not possible. ST_REGS are never moved. */
- return 0;
-
case COP0_REGS:
case COP2_REGS:
case COP3_REGS:
@@ -13017,7 +13027,7 @@ mips_move_from_gpr_cost (enum machine_mode mode, reg_class_t to)
the maximum for us. */
static int
-mips_register_move_cost (enum machine_mode mode,
+mips_register_move_cost (machine_mode mode,
reg_class_t from, reg_class_t to)
{
reg_class_t dregs;
@@ -13068,15 +13078,9 @@ mips_register_priority (int hard_regno)
/* Implement TARGET_MEMORY_MOVE_COST. */
static int
-mips_memory_move_cost (enum machine_mode mode, reg_class_t rclass, bool in)
+mips_memory_move_cost (machine_mode mode, reg_class_t rclass, bool in)
{
- int multiplier = 1;
- /* Acount for the numder of losds md nd stores that are needed to
- * handle MSA type in GPRs. */
- if (MSA_SUPPORTED_MODE_P (mode) && rclass != FP_REGS)
- multiplier = GET_MODE_SIZE (mode) / UNITS_PER_WORD;
-
- return (mips_cost->memory_latency * multiplier
+ return (mips_cost->memory_latency
+ memory_move_secondary_cost (mode, rclass, in));
}
@@ -13084,7 +13088,7 @@ mips_memory_move_cost (enum machine_mode mode, reg_class_t rclass, bool in)
bool
mips_secondary_memory_needed (enum reg_class class1, enum reg_class class2,
- enum machine_mode mode)
+ machine_mode mode)
{
/* Ignore spilled pseudos. */
if (lra_in_progress && (class1 == NO_REGS || class2 == NO_REGS))
@@ -13092,7 +13096,7 @@ mips_secondary_memory_needed (enum reg_class class1, enum reg_class class2,
if (((class1 == FP_REGS) != (class2 == FP_REGS))
&& ((TARGET_FLOATXX && !ISA_HAS_MXHC1)
- || (mips_abi == ABI_32 && TARGET_FLOAT64 && !TARGET_ODD_SPREG))
+ || TARGET_O32_FP64A_ABI)
&& GET_MODE_SIZE (mode) >= 8)
return true;
@@ -13107,7 +13111,7 @@ mips_secondary_memory_needed (enum reg_class class1, enum reg_class class2,
enum reg_class
mips_secondary_reload_class (enum reg_class rclass,
- enum machine_mode mode, rtx x, bool in_p)
+ machine_mode mode, rtx x, bool)
{
int regno;
@@ -13133,28 +13137,11 @@ mips_secondary_reload_class (enum reg_class rclass,
if (ACC_REG_P (regno))
return reg_class_subset_p (rclass, GR_REGS) ? NO_REGS : GR_REGS;
- /* We can only copy a value to a condition code register from a
- floating-point register, and even then we require a scratch
- floating-point register. We can only copy a value out of a
- condition-code register into a general register. */
- if (reg_class_subset_p (rclass, ST_REGS))
- {
- if (in_p)
- return FP_REGS;
- return GP_REG_P (regno) ? NO_REGS : GR_REGS;
- }
- if (ST_REG_P (regno))
- {
- if (!in_p)
- return FP_REGS;
- return reg_class_subset_p (rclass, GR_REGS) ? NO_REGS : GR_REGS;
- }
-
if (reg_class_subset_p (rclass, FP_REGS))
{
- /* We don't need a reload if the pseudo is in memory. */
- if ((MEM_P (x) || regno == -1)
- && (GET_MODE_SIZE (mode) == 4 || GET_MODE_SIZE (mode) == 8))
+ if (regno < 0
+ || (MEM_P (x)
+ && (GET_MODE_SIZE (mode) == 4 || GET_MODE_SIZE (mode) == 8)))
/* In this case we can use lwc1, swc1, ldc1 or sdc1. We'll use
pairs of lwc1s and swc1s if ldc1 and sdc1 are not supported. */
return NO_REGS;
@@ -13178,8 +13165,7 @@ mips_secondary_reload_class (enum reg_class rclass,
return NO_REGS;
/* Otherwise, we need to reload through an integer register. */
- if (regno >= 0)
- return GR_REGS;
+ return GR_REGS;
}
if (FP_REG_P (regno))
return reg_class_subset_p (rclass, GR_REGS) ? NO_REGS : GR_REGS;
@@ -13190,7 +13176,7 @@ mips_secondary_reload_class (enum reg_class rclass,
/* Implement TARGET_MODE_REP_EXTENDED. */
static int
-mips_mode_rep_extended (enum machine_mode mode, enum machine_mode mode_rep)
+mips_mode_rep_extended (machine_mode mode, machine_mode mode_rep)
{
/* On 64-bit targets, SImode register values are sign-extended to DImode. */
if (TARGET_64BIT && mode == SImode && mode_rep == DImode)
@@ -13202,7 +13188,7 @@ mips_mode_rep_extended (enum machine_mode mode, enum machine_mode mode_rep)
/* Implement TARGET_VALID_POINTER_MODE. */
static bool
-mips_valid_pointer_mode (enum machine_mode mode)
+mips_valid_pointer_mode (machine_mode mode)
{
return mode == SImode || (TARGET_64BIT && mode == DImode);
}
@@ -13210,7 +13196,7 @@ mips_valid_pointer_mode (enum machine_mode mode)
/* Implement TARGET_VECTOR_MODE_SUPPORTED_P. */
static bool
-mips_vector_mode_supported_p (enum machine_mode mode)
+mips_vector_mode_supported_p (machine_mode mode)
{
switch (mode)
{
@@ -13233,14 +13219,14 @@ mips_vector_mode_supported_p (enum machine_mode mode)
return TARGET_LOONGSON_VECTORS;
default:
- return TARGET_MSA && MSA_SUPPORTED_VECTOR_MODE_P (mode);
+ return MSA_SUPPORTED_MODE_P (mode);
}
}
/* Implement TARGET_SCALAR_MODE_SUPPORTED_P. */
static bool
-mips_scalar_mode_supported_p (enum machine_mode mode)
+mips_scalar_mode_supported_p (machine_mode mode)
{
if (ALL_FIXED_POINT_MODE_P (mode)
&& GET_MODE_PRECISION (mode) <= 2 * BITS_PER_WORD)
@@ -13251,8 +13237,8 @@ mips_scalar_mode_supported_p (enum machine_mode mode)
/* Implement TARGET_VECTORIZE_PREFERRED_SIMD_MODE. */
-static enum machine_mode
-mips_preferred_simd_mode (enum machine_mode mode)
+static machine_mode
+mips_preferred_simd_mode (machine_mode mode)
{
if (TARGET_PAIRED_SINGLE_FLOAT
&& mode == SFmode)
@@ -13486,6 +13472,7 @@ mips_adjust_insn_length (rtx insn, int length)
break;
case HAZARD_DELAY:
+ case HAZARD_FORBIDDEN_SLOT:
length += NOP_INSN_LENGTH;
break;
@@ -13497,6 +13484,78 @@ mips_adjust_insn_length (rtx insn, int length)
return length;
}
+/* Return the asm template for a call. OPERANDS are the operands, TARGET_OPNO
+ is the operand number of the target. SIZE_OPNO is the operand number of
+ the argument size operand that can optionally hold the call attributes. If
+ SIZE_OPNO is not -1 and the call is indirect, use the function symbol from
+ the call attributes to attach a R_MIPS_JALR relocation to the call.
+
+ When generating GOT code without explicit relocation operators, all calls
+ should use assembly macros. Otherwise, all indirect calls should use "jr"
+ or "jalr"; we will arrange to restore $gp afterwards if necessary. Finally,
+ we can only generate direct calls for -mabicalls by temporarily switching
+ to non-PIC mode.
+
+ For microMIPS jal(r), we try to generate jal(r)s when a 16-bit
+ instruction is in the delay slot of jal(r).
+
+ Where compact branches are available, we try to use them if the delay slot
+ has a NOP (or equivalently delay slots were not enabled for the instruction
+ anyway). */
+
+const char *
+mips_output_jump (rtx *operands, int target_opno, int size_opno, bool link_p)
+{
+ static char buffer[300];
+ char *s = buffer;
+ bool reg_p = REG_P (operands[target_opno]);
+
+ const char *and_link = link_p ? "al" : "";
+ const char *reg = reg_p ? "r" : "";
+ const char *compact = "";
+ const char *nop = "%/";
+ const char *short_delay = link_p ? "%!" : "";
+ const char *insn_name = TARGET_CB_NEVER || reg_p ? "j" : "b";
+
+ /* Compact branches can only be described when the ISA has support for them
+ as both the compact formatter '%:' and the delay slot NOP formatter '%/'
+ work as a mutually exclusive pair. I.e. a NOP is never required if a
+ compact form is available. */
+ if (!final_sequence
+ && (TARGET_CB_MAYBE
+ || (ISA_HAS_JRC && !link_p && reg_p)))
+ {
+ compact = "c";
+ nop = "";
+ }
+
+
+ if (TARGET_USE_GOT && !TARGET_EXPLICIT_RELOCS)
+ sprintf (s, "%%*%s%s\t%%%d%%/", insn_name, link_p ? "al" : "", target_opno);
+ else
+ {
+ if (!reg_p && TARGET_ABICALLS_PIC2)
+ s += sprintf (s, ".option\tpic0\n\t");
+
+ if (reg_p && mips_get_pic_call_symbol (operands, size_opno))
+ {
+ s += sprintf (s, "%%*.reloc\t1f,R_MIPS_JALR,%%%d\n1:\t", size_opno);
+ /* Not sure why this shouldn't permit a short delay but it did not
+ allow it before so we still don't allow it. */
+ short_delay = "";
+ }
+ else
+ s += sprintf (s, "%%*");
+
+ s += sprintf (s, "%s%s%s%s%s\t%%%d%s", insn_name, and_link, reg, compact, short_delay,
+ target_opno, nop);
+
+ if (!reg_p && TARGET_ABICALLS_PIC2)
+ s += sprintf (s, "\n\t.option\tpic2");
+ }
+ return buffer;
+}
+
/* Return the assembly code for INSN, which has the operands given by
OPERANDS, and which branches to OPERANDS[0] if some condition is true.
BRANCH_IF_TRUE is the asm template that should be used if OPERANDS[0]
@@ -13517,7 +13576,7 @@ mips_output_conditional_branch (rtx insn, rtx *operands,
if (length <= 8)
{
/* Just a simple conditional branch. */
- mips_branch_likely = (final_sequence && INSN_ANNULLED_BRANCH_P (insn));
+ mips_branch_likely = final_sequence && INSN_ANNULLED_BRANCH_P (insn);
return branch_if_true;
}
@@ -13550,12 +13609,25 @@ mips_output_conditional_branch (rtx insn, rtx *operands,
}
/* Output the unconditional branch to TAKEN. */
- if (TARGET_ABSOLUTE_JUMPS)
+ if (TARGET_ABSOLUTE_JUMPS && TARGET_CB_MAYBE)
+ {
+ /* Add a hazard nop. */
+ if (!final_sequence)
+ {
+ output_asm_insn ("nop\t\t# hazard nop", 0);
+ fprintf (asm_out_file, "\n");
+ }
+ output_asm_insn (MIPS_ABSOLUTE_JUMP ("bc\t%0"), &taken);
+ }
+ else if (TARGET_ABSOLUTE_JUMPS)
output_asm_insn (MIPS_ABSOLUTE_JUMP ("j\t%0%/"), &taken);
else
{
mips_output_load_label (taken);
- output_asm_insn ("jr\t%@%]%/", 0);
+ if (TARGET_CB_MAYBE)
+ output_asm_insn ("jrc\t%@%]", 0);
+ else
+ output_asm_insn ("jr\t%@%]%/", 0);
}
/* Now deal with its delay slot; see above. */
@@ -13569,7 +13641,7 @@ mips_output_conditional_branch (rtx insn, rtx *operands,
asm_out_file, optimize, 1, NULL);
INSN_DELETED_P (XVECEXP (final_sequence, 0, 1)) = 1;
}
- else
+ else if (TARGET_CB_NEVER)
output_asm_insn ("nop", 0);
fprintf (asm_out_file, "\n");
}
@@ -13580,6 +13652,58 @@ mips_output_conditional_branch (rtx insn, rtx *operands,
return "";
}
+const char *
+mips_output_equal_conditional_branch (rtx insn, rtx *operands, bool inverted_p)
+{
+ const char *branch[2];
+ /* For a simple BNEZ or BEQZ microMIPSr3 branch. */
+ if (TARGET_MICROMIPS
+ && mips_isa_rev <= 5
+ && operands[3] == const0_rtx
+ && get_attr_length (insn) <= 8)
+ {
+ if (mips_cb == MIPS_CB_OPTIMAL)
+ {
+ branch[!inverted_p] = "%*b%C1z%:\t%2,%0";
+ branch[inverted_p] = "%*b%N1z%:\t%2,%0";
+ }
+ else
+ {
+ branch[!inverted_p] = "%*b%C1z\t%2,%0%/";
+ branch[inverted_p] = "%*b%N1z\t%2,%0%/";
+ }
+ }
+ else if (TARGET_CB_MAYBE)
+ {
+ if (operands[3] == const0_rtx)
+ {
+ branch[!inverted_p] = MIPS_BRANCH_C ("b%C1z", "%2,%0");
+ branch[inverted_p] = MIPS_BRANCH_C ("b%N1z", "%2,%0");
+ }
+ else if (REGNO (operands[2]) != REGNO (operands[3]))
+ {
+ branch[!inverted_p] = MIPS_BRANCH_C ("b%C1", "%2,%3,%0");
+ branch[inverted_p] = MIPS_BRANCH_C ("b%N1", "%2,%3,%0");
+ }
+ else
+ {
+ /* This case is stupid. Fix me. */
+ if (GET_CODE (operands[1]) == NE)
+ inverted_p = !inverted_p;
+
+ branch[!inverted_p] = MIPS_BRANCH_C ("b", "%0");
+ branch[inverted_p] = "%*\t\t# branch never";
+ }
+ }
+ else
+ {
+ branch[!inverted_p] = MIPS_BRANCH ("b%C1", "%2,%z3,%0");
+ branch[inverted_p] = MIPS_BRANCH ("b%N1", "%2,%z3,%0");
+ }
+
+ return mips_output_conditional_branch (insn, operands, branch[1], branch[0]);
+}
+
/* Return the assembly code for INSN, which branches to OPERANDS[0]
if some ordering condition is true. The condition is given by
OPERANDS[1] if !INVERTED_P, otherwise it is the inverse of
@@ -13591,32 +13715,84 @@ mips_output_order_conditional_branch (rtx insn, rtx *operands, bool inverted_p)
{
const char *branch[2];
- /* Make BRANCH[1] branch to OPERANDS[0] when the condition is true.
- Make BRANCH[0] branch on the inverse condition. */
- switch (GET_CODE (operands[1]))
+ if (operands[3] != const0_rtx)
{
- /* These cases are equivalent to comparisons against zero. */
- case LEU:
- inverted_p = !inverted_p;
- /* Fall through. */
- case GTU:
- branch[!inverted_p] = MIPS_BRANCH ("bne", "%2,%.,%0");
- branch[inverted_p] = MIPS_BRANCH ("beq", "%2,%.,%0");
- break;
+ if (REGNO (operands[2]) == REGNO (operands[3]))
+ {
+ switch (GET_CODE (operands[1]))
+ {
+ case LT:
+ case LTU:
+ inverted_p = !inverted_p;
+ /* Fall through. */
+ case GE:
+ case GEU:
+ branch[!inverted_p] = MIPS_BRANCH_C ("b", "%0");
+ branch[inverted_p] = "%*\t\t# branch never";
+ break;
+ default:
+ gcc_unreachable ();
+ }
+ }
+ else
+ {
+ branch[!inverted_p] = MIPS_BRANCH_C ("b%C1", "%2,%3,%0");
+ branch[inverted_p] = MIPS_BRANCH_C ("b%N1", "%2,%3,%0");
+ }
+ }
+ else
+ {
+ /* Make BRANCH[1] branch to OPERANDS[0] when the condition is true.
+ Make BRANCH[0] branch on the inverse condition. */
+ switch (GET_CODE (operands[1]))
+ {
+ /* These cases are equivalent to comparisons against zero. */
+ case LEU:
+ inverted_p = !inverted_p;
+ /* Fall through. */
+ case GTU:
+ if (TARGET_CB_MAYBE)
+ {
+ branch[!inverted_p] = MIPS_BRANCH_C ("bnez", "%2,%0");
+ branch[inverted_p] = MIPS_BRANCH_C ("beqz", "%2,%0");
+ }
+ else
+ {
+ branch[!inverted_p] = MIPS_BRANCH ("bne", "%2,%.,%0");
+ branch[inverted_p] = MIPS_BRANCH ("beq", "%2,%.,%0");
+ }
+ break;
- /* These cases are always true or always false. */
- case LTU:
- inverted_p = !inverted_p;
- /* Fall through. */
- case GEU:
- branch[!inverted_p] = MIPS_BRANCH ("beq", "%.,%.,%0");
- branch[inverted_p] = MIPS_BRANCH ("bne", "%.,%.,%0");
- break;
+ /* These cases are always true or always false. */
+ case LTU:
+ inverted_p = !inverted_p;
+ /* Fall through. */
+ case GEU:
+ if (TARGET_CB_MAYBE)
+ {
+ branch[!inverted_p] = MIPS_BRANCH_C ("b", "%0");
+ branch[inverted_p] = "%*\t\t# branch never";
+ }
+ else
+ {
+ branch[!inverted_p] = MIPS_BRANCH ("beq", "%.,%.,%0");
+ branch[inverted_p] = MIPS_BRANCH ("bne", "%.,%.,%0");
+ }
+ break;
- default:
- branch[!inverted_p] = MIPS_BRANCH ("b%C1z", "%2,%0");
- branch[inverted_p] = MIPS_BRANCH ("b%N1z", "%2,%0");
- break;
+ default:
+ if (TARGET_CB_MAYBE)
+ {
+ branch[!inverted_p] = MIPS_BRANCH_C ("b%C1z", "%2,%0");
+ branch[inverted_p] = MIPS_BRANCH_C ("b%N1z", "%2,%0");
+ }
+ else
+ {
+ branch[!inverted_p] = MIPS_BRANCH ("b%C1z", "%2,%0");
+ branch[inverted_p] = MIPS_BRANCH ("b%N1z", "%2,%0");
+ }
+ break;
+ }
}
return mips_output_conditional_branch (insn, operands, branch[1], branch[0]);
}
@@ -13819,11 +13995,18 @@ mips_process_sync_loop (rtx insn, rtx *operands)
at, oldval, inclusive_mask, NULL);
tmp1 = at;
}
- mips_multi_add_insn ("bne\t%0,%z1,2f", tmp1, required_oldval, NULL);
+ if (TARGET_CB_NEVER)
+ mips_multi_add_insn ("bne\t%0,%z1,2f", tmp1, required_oldval, NULL);
/* CMP = 0 [delay slot]. */
if (cmp)
mips_multi_add_insn ("li\t%0,0", cmp, NULL);
+
+ if (TARGET_CB_MAYBE && required_oldval == const0_rtx)
+ mips_multi_add_insn ("bnezc\t%0,2f", tmp1, NULL);
+ else if (TARGET_CB_MAYBE)
+ mips_multi_add_insn ("bnec\t%0,%1,2f", tmp1, required_oldval, NULL);
+
}
/* $TMP1 = OLDVAL & EXCLUSIVE_MASK. */
@@ -13879,7 +14062,17 @@ mips_process_sync_loop (rtx insn, rtx *operands)
This will sometimes be a delayed branch; see the write code below
for details. */
mips_multi_add_insn (is_64bit_p ? "scd\t%0,%1" : "sc\t%0,%1", at, mem, NULL);
- mips_multi_add_insn ("beq%?\t%0,%.,1b", at, NULL);
+
+ /* When using branch likely (-mfix-r10000), the delay slot instruction
+ will be annulled on false. The normal delay slot instructions
+ calculate the overall result of the atomic operation and must not
+ be annulled. To ensure this behaviour unconditionally use a NOP
+ in the delay slot for the branch likely case. */
+
+ if (TARGET_CB_MAYBE)
+ mips_multi_add_insn ("beqzc\t%0,1b", at, NULL);
+ else
+ mips_multi_add_insn ("beq%?\t%0,%.,1b%~", at, NULL);
/* if (INSN1 != MOVE && INSN1 != LI) NEWVAL = $TMP3 [delay slot]. */
if (insn1 != SYNC_INSN1_MOVE && insn1 != SYNC_INSN1_LI && tmp3 != newval)
@@ -13887,7 +14080,7 @@ mips_process_sync_loop (rtx insn, rtx *operands)
mips_multi_copy_insn (tmp3_insn);
mips_multi_set_operand (mips_multi_last_index (), 0, newval);
}
- else if (!(required_oldval && cmp))
+ else if (!(required_oldval && cmp) && !mips_branch_likely)
mips_multi_add_insn ("nop", NULL);
/* CMP = 1 -- either standalone or in a delay slot. */
@@ -13911,12 +14104,12 @@ mips_process_sync_loop (rtx insn, rtx *operands)
const char *
mips_output_sync_loop (rtx insn, rtx *operands)
{
- mips_process_sync_loop (insn, operands);
-
/* Use branch-likely instructions to work around the LL/SC R10000
errata. */
mips_branch_likely = TARGET_FIX_R10000;
+ mips_process_sync_loop (insn, operands);
+
mips_push_asm_switch (&mips_noreorder);
mips_push_asm_switch (&mips_nomacro);
mips_push_asm_switch (&mips_noat);
@@ -13938,6 +14131,9 @@ mips_output_sync_loop (rtx insn, rtx *operands)
unsigned int
mips_sync_loop_insns (rtx insn, rtx *operands)
{
+ /* Use branch-likely instructions to work around the LL/SC R10000
+ errata. */
+ mips_branch_likely = TARGET_FIX_R10000;
mips_process_sync_loop (insn, operands);
return mips_multi_num_insns;
}
@@ -14062,11 +14258,11 @@ mips_output_division (const char *division, rtx *operands)
}
}
else
- {
+ {
output_asm_insn ("%(bne\t%2,%.,1f", operands);
output_asm_insn (s, operands);
s = "break\t7%)\n1:";
- }
+ }
}
return s;
}
@@ -14095,7 +14291,7 @@ bool
mips_fmadd_bypass (rtx out_insn, rtx in_insn)
{
int dst_reg, src_reg;
-
+
gcc_assert (get_attr_type (in_insn) == TYPE_FMADD);
gcc_assert (get_attr_type (out_insn) == TYPE_FMADD);
@@ -14233,6 +14429,8 @@ mips_issue_rate (void)
case PROCESSOR_R9000:
case PROCESSOR_OCTEON:
case PROCESSOR_OCTEON2:
+ case PROCESSOR_OCTEON3:
+ case PROCESSOR_I6400:
return 2;
case PROCESSOR_SB1:
@@ -14382,7 +14580,7 @@ mips_multipass_dfa_lookahead (void)
if (TUNE_OCTEON)
return 2;
- if (TUNE_P5600)
+ if (TUNE_P5600 || TUNE_I6400)
return 4;
return 0;
@@ -14636,82 +14834,68 @@ mips_74k_agen_reorder (rtx *ready, int nready)
}
}
-/* These functions are called when -msched-weight is set.
- They calculate register weight for given register type. */
+/* These functions are called when -msched-weight is set. */
-/* Find GP and vector register weight for given X. */
+/* Find register born in given X if any. */
-static void
-find_regtype_weight (rtx x, int insn_uid)
+static int
+find_reg_born (rtx x)
{
if (GET_CODE (x) == CLOBBER)
- {
- if (GET_MODE_SIZE (GET_MODE (SET_DEST (x))) <= GET_MODE_SIZE (DImode))
- regtype_weight[insn_uid].reg_weight_gp++;
- else
- regtype_weight[insn_uid].reg_weight_vec++;
- }
+ return 1;
if (GET_CODE (x) == SET)
{
if (REG_P (SET_DEST (x)) && reg_mentioned_p (SET_DEST (x), SET_SRC (x)))
- return;
-
- if (GET_MODE_SIZE (GET_MODE (SET_DEST (x))) <= GET_MODE_SIZE (DImode))
- regtype_weight[insn_uid].reg_weight_gp++;
- else
- regtype_weight[insn_uid].reg_weight_vec++;
+ return 0;
+ return 1;
}
+ return 0;
}
-/* Calculate register weights for all instructions and modes
- of all basic blocks. */
+/* Calculate register weight for given INSN. */
-static void
-mips_weight_init_global (int old_max_uid)
+static int
+get_weight (rtx insn)
{
- rtx x, insn;
- basic_block b;
+ int weight = 0;
+ rtx x;
- regtype_weight = XCNEWVEC (struct msched_weight_info, old_max_uid);
+ /* Increment weight for each register born here. */
+ x = PATTERN (insn);
+ weight = find_reg_born (x);
- FOR_EACH_BB_REVERSE_FN (b, cfun)
- FOR_BB_INSNS (b, insn)
- if (NONDEBUG_INSN_P (insn))
+ if (GET_CODE (x) == PARALLEL)
+ {
+ int i;
+ for (i = XVECLEN (x, 0) - 1; i >= 0; i--)
{
- /* Increment weight for each register born here. */
- x = PATTERN (insn);
- find_regtype_weight (x, INSN_UID (insn));
-
- if (GET_CODE (x) == PARALLEL)
- {
- int i;
- for (i = XVECLEN (x, 0) - 1; i >= 0; i--)
- {
- x = XVECEXP (PATTERN (insn), 0, i);
- find_regtype_weight (x, INSN_UID (insn));
- }
- }
+ x = XVECEXP (PATTERN (insn), 0, i);
+ weight += find_reg_born (x);
+ }
+ }
- /* Decrement weight for each register that dies here. */
- for (x = REG_NOTES (insn); x; x = XEXP (x, 1))
- if (REG_NOTE_KIND (x) == REG_DEAD
- || REG_NOTE_KIND (x) == REG_UNUSED)
- {
- rtx note = XEXP (x, 0);
- if (REG_P (note))
- {
- if (GET_MODE_SIZE (GET_MODE (note))
- <= GET_MODE_SIZE (DImode))
- regtype_weight[INSN_UID (insn)].reg_weight_gp--;
- else
- regtype_weight[INSN_UID (insn)].reg_weight_vec--;
- }
- }
+ /* Decrement weight for each register that dies here. */
+ for (x = REG_NOTES (insn); x; x = XEXP (x, 1))
+ {
+ if (REG_NOTE_KIND (x) == REG_DEAD || REG_NOTE_KIND (x) == REG_UNUSED)
+ {
+ rtx note = XEXP (x, 0);
+ if (REG_P (note))
+ weight--;
}
+ }
+ return weight;
+}
- CURR_REGTYPE_PRESSURE (GPREG) = 0;
- CURR_REGTYPE_PRESSURE (VECREG) = 0;
+/* TARGET_SCHED_WEIGHT helper function.
+ Allocate and initialize global data. */
+
+static void
+mips_weight_init_global (int old_max_uid)
+{
+ level = (int *) xcalloc (old_max_uid, sizeof (int));
+ consumer_luid = (int *) xcalloc (old_max_uid, sizeof (int));
}
/* Implement TARGET_SCHED_INIT_GLOBAL. */
@@ -14721,15 +14905,72 @@ mips_sched_init_global (FILE *dump ATTRIBUTE_UNUSED,
int verbose ATTRIBUTE_UNUSED,
int old_max_uid)
{
- if (TARGET_SCHED_WEIGHT)
+ if (!reload_completed && TARGET_SCHED_WEIGHT)
mips_weight_init_global (old_max_uid);
}
+/* TARGET_SCHED_WEIGHT helper function. Called for each basic block
+ with dependency chain information in HEAD and TAIL.
+ Calculates LEVEL for each INSN from its forward dependencies
+ and finds out UID of first consumer instruction (CONSUMER_LUID) of INSN. */
+
+static void
+mips_weight_evaluation (rtx head, rtx tail)
+{
+ sd_iterator_def sd_it;
+ dep_t dep;
+ rtx prev_head, insn, x;
+ prev_head = PREV_INSN (head);
+
+ for (insn = tail; insn != prev_head; insn = PREV_INSN (insn))
+ if (INSN_P (insn))
+ {
+ FOR_EACH_DEP (insn, SD_LIST_FORW, sd_it, dep)
+ {
+ x = DEP_CON (dep);
+ if (! DEBUG_INSN_P (x))
+ {
+ if (LEVEL (x) > LEVEL (insn))
+ LEVEL (insn) = LEVEL (x);
+ CONSUMER_LUID (insn) = INSN_LUID (x);
+ }
+ }
+ LEVEL (insn)++;
+ }
+}
+
+/* Implement TARGET_SCHED_DEPENDENCIES_EVALUATION_HOOK. */
+
+static void
+mips_evaluation_hook (rtx head, rtx tail)
+{
+ if (!reload_completed && TARGET_SCHED_WEIGHT)
+ mips_weight_evaluation (head, tail);
+}
+
+/* Implement TARGET_SCHED_SET_SCHED_FLAGS.
+ Enables DONT_BREAK_DEPENDENCIES for the first scheduling pass.
+ It prevents breaking of dependencies on mem/inc pair in the first pass
+ which would otherwise increase stalls. */
+
+static void
+mips_set_sched_flags (spec_info_t spec_info ATTRIBUTE_UNUSED)
+{
+ if (!reload_completed && TARGET_SCHED_WEIGHT)
+ {
+ unsigned int *flags = &(current_sched_info->flags);
+ *flags |= DONT_BREAK_DEPENDENCIES;
+ }
+}
+
static void
mips_weight_finish_global ()
{
- if (regtype_weight != NULL)
- XDELETEVEC (regtype_weight);
+ if (level != NULL)
+ free (level);
+
+ if (consumer_luid != NULL)
+ free (consumer_luid);
}
/* Implement TARGET_SCHED_FINISH_GLOBAL. */
@@ -14738,80 +14979,61 @@ static void
mips_sched_finish_global (FILE *dump ATTRIBUTE_UNUSED,
int verbose ATTRIBUTE_UNUSED)
{
- if (TARGET_SCHED_WEIGHT)
+ if (!reload_completed && TARGET_SCHED_WEIGHT)
mips_weight_finish_global ();
}
-/* This is a TARGET_SCHED_WEIGHT (option -msched-weight) helper
- function which is called during reordering of instructions in
- the first pass of the scheduler. The function swaps the instruction
- at the bottom (NREADY - 1) of the READY list with another instruction
- in READY list as per following algorithm. The scheduler then picks the
- instruction at READY[NREADY - 1] and schedules it.
- When an instruction is scheduled its register weight is accumulated
- in CURR_REGTYPE_PRESSURE (mode). Which is number of live registers
- at that instruction.
+/* This is a TARGET_SCHED_WEIGHT (option -msched-weight) helper function
+ which is called during reordering of instructions in the first pass
+ of the scheduler. The function swaps the instruction at (NREADY - 1)
+ of the READY list with another instruction in READY list as per
+ the following algorithm. The scheduler then picks the instruction
+ at READY[NREADY - 1] and schedules it.
- If the current register pressure (CURR_REGTYPE_PRESSURE) is
- more than PROMOTE_HIGH_PRIORITY_PRESSURE (25 registers) and if the
- priority of the consumer of the instruction in question (INSN) is
- more than the priority of READY[NREADY - 1] then INSN is swapped
- with READY[NREADY - 1].
+ Every instruction is assigned with a value LEVEL.
+ [See: mips_weight_evaluation().]
- If the current register pressure (CURR_REGTYPE_PRESSURE) is
- more than PROMOTE_MAX_DEP_PRESSURE (15 registers) then INSN
- with maximum forward dependencies is swapped with the
- READY[NREADY - 1]. */
+ 1. INSN with highest LEVEL is chosen to be scheduled next, ties broken by
+ 1a. Choosing INSN that is used early in the flow or
+ 1b. Choosing INSN with greater INSN_TICK.
+
+ 2. Choose INSN having less LEVEL number iff,
+ 2a. It is used early and
+ 2b. Has greater INSN_TICK and
+ 2c. Contributes less to the register pressure. */
static void
mips_sched_weight (rtx *ready, int nready)
{
- int mode, toswap, i;
- int max_forw_dependency = 0;
-
- toswap = nready - 1;
-
+ int max_level = LEVEL (ready[nready-1]), toswap = nready-1;
+ int i;
#define INSN_TICK(INSN) (HID (INSN)->tick)
- mode = CURR_REGTYPE_PRESSURE (GPREG) > CURR_REGTYPE_PRESSURE (VECREG)
- ? GPREG : VECREG;
-
- for (i = nready - 1; i >= 0; i--)
+ for (i = nready - 2; i >= 0; i--)
{
- rtx insn = ready[i], consumer_insn = NULL_RTX;
- sd_iterator_def sd_it;
- dep_t dep;
- int forw_dependency_count = 0;
-
- FOR_EACH_DEP (insn, SD_LIST_FORW, sd_it, dep)
- {
- if (! DEBUG_INSN_P (DEP_CON (dep)))
- forw_dependency_count++;
- consumer_insn = DEP_CON (dep);
- }
-
- if (CURR_REGTYPE_PRESSURE (mode) > PROMOTE_HIGH_PRIORITY_PRESSURE)
+ rtx insn = ready[i];
+ if (LEVEL (insn) == max_level)
{
- if (consumer_insn != NULL_RTX
- && INSN_PRIORITY_KNOWN (consumer_insn)
- && (INSN_PRIORITY (consumer_insn)
- > INSN_PRIORITY (ready[toswap])))
+ if (INSN_PRIORITY (insn) >= INSN_PRIORITY (ready[toswap]))
{
- max_forw_dependency = forw_dependency_count;
- toswap = i;
+ if (CONSUMER_LUID (insn) < CONSUMER_LUID (ready[toswap]))
+ toswap = i;
}
+ else if (INSN_TICK (insn) > INSN_TICK(ready[toswap]))
+ toswap = i;
}
- else if (CURR_REGTYPE_PRESSURE (mode) > PROMOTE_MAX_DEP_PRESSURE)
+ if (LEVEL (insn) > max_level)
{
- if (forw_dependency_count > max_forw_dependency
- || ((forw_dependency_count == max_forw_dependency)
- && (INSN_TICK (insn) >= INSN_TICK (ready[toswap]))
- && (INSN_UID (insn) < INSN_UID (ready[toswap]))))
- {
- max_forw_dependency = forw_dependency_count;
- toswap = i;
- }
+ max_level = LEVEL (insn);
+ toswap = i;
+ }
+ if (LEVEL (insn) < max_level)
+ {
+ if (CONSUMER_LUID (insn) < CONSUMER_LUID (ready[toswap])
+ && INSN_TICK (insn) > INSN_TICK(ready[toswap])
+ && get_weight (insn) < get_weight (ready[toswap]))
+ toswap = i;
}
}
@@ -14823,6 +15045,7 @@ mips_sched_weight (rtx *ready, int nready)
}
#undef INSN_TICK
}
+
/* Implement TARGET_SCHED_INIT. */
@@ -14839,12 +15062,6 @@ mips_sched_init (FILE *file ATTRIBUTE_UNUSED, int verbose ATTRIBUTE_UNUSED,
pointed to ALU2. */
mips_ls2.alu1_turn_p = false;
mips_ls2.falu1_turn_p = true;
-
- if (TARGET_SCHED_WEIGHT)
- {
- CURR_REGTYPE_PRESSURE (GPREG) = 0;
- CURR_REGTYPE_PRESSURE (VECREG) = 0;
- }
}
/* Subroutine used by TARGET_SCHED_REORDER and TARGET_SCHED_REORDER2. */
@@ -14942,16 +15159,6 @@ mips_variable_issue (FILE *file ATTRIBUTE_UNUSED, int verbose ATTRIBUTE_UNUSED,
mips_74k_agen_init (insn);
else if (TUNE_LOONGSON_2EF)
mips_ls2_variable_issue (insn);
- else if (TARGET_SCHED_WEIGHT)
- {
- if (regtype_weight != NULL)
- {
- CURR_REGTYPE_PRESSURE (GPREG)
- += INSN_GPREG_WEIGHT (insn);
- CURR_REGTYPE_PRESSURE (VECREG)
- += INSN_VECREG_WEIGHT (insn);
- }
- }
}
/* Instructions of type 'multi' should all be split before
@@ -15246,10 +15453,10 @@ AVAIL_NON_MIPS16 (msa, TARGET_MSA)
#define CODE_FOR_msa_div_u_d CODE_FOR_udivv2di3
#define CODE_FOR_msa_fadd_w CODE_FOR_addv4sf3
#define CODE_FOR_msa_fadd_d CODE_FOR_addv2df3
-#define CODE_FOR_msa_ffint_s_w CODE_FOR_floatv4sfv4si2
-#define CODE_FOR_msa_ffint_s_d CODE_FOR_floatv2dfv2di2
-#define CODE_FOR_msa_ffint_u_w CODE_FOR_floatunsv4sfv4si2
-#define CODE_FOR_msa_ffint_u_d CODE_FOR_floatunsv2dfv2di2
+#define CODE_FOR_msa_ffint_s_w CODE_FOR_floatv4siv4sf2
+#define CODE_FOR_msa_ffint_s_d CODE_FOR_floatv2div2df2
+#define CODE_FOR_msa_ffint_u_w CODE_FOR_floatunsv4siv4sf2
+#define CODE_FOR_msa_ffint_u_d CODE_FOR_floatunsv2div2df2
#define CODE_FOR_msa_fsub_w CODE_FOR_subv4sf3
#define CODE_FOR_msa_fsub_d CODE_FOR_subv2df3
#define CODE_FOR_msa_fmul_w CODE_FOR_mulv4sf3
@@ -15258,14 +15465,30 @@ AVAIL_NON_MIPS16 (msa, TARGET_MSA)
#define CODE_FOR_msa_fdiv_d CODE_FOR_divv2df3
#define CODE_FOR_msa_fmax_w CODE_FOR_smaxv4sf3
#define CODE_FOR_msa_fmax_d CODE_FOR_smaxv2df3
-#define CODE_FOR_msa_fmax_a_w CODE_FOR_smaxv4sf3
-#define CODE_FOR_msa_fmax_a_d CODE_FOR_smaxv2sf3
+#define CODE_FOR_msa_fmax_a_w CODE_FOR_umaxv4sf3
+#define CODE_FOR_msa_fmax_a_d CODE_FOR_umaxv2df3
#define CODE_FOR_msa_fmin_w CODE_FOR_sminv4sf3
#define CODE_FOR_msa_fmin_d CODE_FOR_sminv2df3
-#define CODE_FOR_msa_fmin_a_w CODE_FOR_sminv4sf3
-#define CODE_FOR_msa_fmin_a_d CODE_FOR_sminv2df3
+#define CODE_FOR_msa_fmin_a_w CODE_FOR_uminv4sf3
+#define CODE_FOR_msa_fmin_a_d CODE_FOR_uminv2df3
#define CODE_FOR_msa_fsqrt_w CODE_FOR_sqrtv4sf2
#define CODE_FOR_msa_fsqrt_d CODE_FOR_sqrtv2df2
+#define CODE_FOR_msa_max_s_b CODE_FOR_smaxv16qi3
+#define CODE_FOR_msa_max_s_h CODE_FOR_smaxv8hi3
+#define CODE_FOR_msa_max_s_w CODE_FOR_smaxv4si3
+#define CODE_FOR_msa_max_s_d CODE_FOR_smaxv2di3
+#define CODE_FOR_msa_max_u_b CODE_FOR_umaxv16qi3
+#define CODE_FOR_msa_max_u_h CODE_FOR_umaxv8hi3
+#define CODE_FOR_msa_max_u_w CODE_FOR_umaxv4si3
+#define CODE_FOR_msa_max_u_d CODE_FOR_umaxv2di3
+#define CODE_FOR_msa_min_s_b CODE_FOR_sminv16qi3
+#define CODE_FOR_msa_min_s_h CODE_FOR_sminv8hi3
+#define CODE_FOR_msa_min_s_w CODE_FOR_sminv4si3
+#define CODE_FOR_msa_min_s_d CODE_FOR_sminv2di3
+#define CODE_FOR_msa_min_u_b CODE_FOR_uminv16qi3
+#define CODE_FOR_msa_min_u_h CODE_FOR_uminv8hi3
+#define CODE_FOR_msa_min_u_w CODE_FOR_uminv4si3
+#define CODE_FOR_msa_min_u_d CODE_FOR_uminv2di3
#define CODE_FOR_msa_mod_s_b CODE_FOR_modv16qi3
#define CODE_FOR_msa_mod_s_h CODE_FOR_modv8hi3
#define CODE_FOR_msa_mod_s_w CODE_FOR_modv4si3
@@ -15321,6 +15544,9 @@ AVAIL_NON_MIPS16 (msa, TARGET_MSA)
#define CODE_FOR_msa_vshf_w CODE_FOR_msa_vshfv4si
#define CODE_FOR_msa_vshf_d CODE_FOR_msa_vshfv2di
+#define CODE_FOR_msa_ilvod_d CODE_FOR_msa_ilvl_d
+#define CODE_FOR_msa_ilvev_d CODE_FOR_msa_ilvr_d
+
#define CODE_FOR_msa_ldi_b CODE_FOR_msa_ldiv16qi
#define CODE_FOR_msa_ldi_h CODE_FOR_msa_ldiv8hi
#define CODE_FOR_msa_ldi_w CODE_FOR_msa_ldiv4si
@@ -16161,12 +16387,15 @@ static const struct mips_builtin_description mips_builtins[] = {
/* Index I is the function declaration for mips_builtins[I], or null if the
function isn't defined on this target. */
static GTY(()) tree mips_builtin_decls[ARRAY_SIZE (mips_builtins)];
+/* Get the index I of the function declaration for mips_builtin_decls[I]
+ using the instruction code or return null if not defined for the target. */
+static GTY(()) int mips_get_builtin_decl_index[LAST_INSN_CODE];
/* MODE is a vector mode whose elements have type TYPE. Return the type
of the vector itself. */
static tree
-mips_builtin_vector_type (tree type, enum machine_mode mode)
+mips_builtin_vector_type (tree type, machine_mode mode)
{
static tree types[2 * (int) MAX_MACHINE_MODE];
int mode_index;
@@ -16292,10 +16521,13 @@ mips_init_builtins (void)
{
d = &mips_builtins[i];
if (d->avail ())
- mips_builtin_decls[i]
- = add_builtin_function (d->name,
- mips_build_function_type (d->function_type),
- i, BUILT_IN_MD, NULL, NULL);
+ {
+ mips_builtin_decls[i]
+ = add_builtin_function (d->name,
+ mips_build_function_type (d->function_type),
+ i, BUILT_IN_MD, NULL, NULL);
+ mips_get_builtin_decl_index[d->icode] = i;
+ }
}
}
@@ -16309,6 +16541,51 @@ mips_builtin_decl (unsigned int code, bool initialize_p ATTRIBUTE_UNUSED)
return mips_builtin_decls[code];
}
+/* Implement TARGET_VECTORIZE_BUILTIN_VECTORIZED_FUNCTION. */
+
+static tree
+mips_builtin_vectorized_function (tree fndecl, tree type_out,
+ tree type_in)
+{
+ machine_mode in_mode, out_mode;
+ enum built_in_function fn = DECL_FUNCTION_CODE (fndecl);
+ int in_n, out_n;
+
+ if (TREE_CODE (type_out) != VECTOR_TYPE
+ || TREE_CODE (type_in) != VECTOR_TYPE
+ || DECL_BUILT_IN_CLASS (fndecl) != BUILT_IN_NORMAL
+ || !ISA_HAS_MSA)
+ return NULL_TREE;
+
+ out_mode = TYPE_MODE (TREE_TYPE (type_out));
+ out_n = TYPE_VECTOR_SUBPARTS (type_out);
+ in_mode = TYPE_MODE (TREE_TYPE (type_in));
+ in_n = TYPE_VECTOR_SUBPARTS (type_in);
+
+ /* INSN is the name of the associated instruction pattern, without
+ the leading CODE_FOR_. */
+#define MIPS_GET_BUILTIN(INSN) \
+ mips_builtin_decls[mips_get_builtin_decl_index[CODE_FOR_##INSN]]
+
+ switch (fn)
+ {
+ case BUILT_IN_SQRT:
+ if (out_mode == DFmode && out_n == 2
+ && in_mode == DFmode && in_n == 2)
+ return MIPS_GET_BUILTIN (msa_fsqrt_d);
+ break;
+ case BUILT_IN_SQRTF:
+ if (out_mode == SFmode && out_n == 4
+ && in_mode == SFmode && in_n == 4)
+ return MIPS_GET_BUILTIN (msa_fsqrt_w);
+ break;
+ default:
+ break;
+ }
+
+ return NULL_TREE;
+}
+
/* Take argument ARGNO from EXP's argument list and convert it into
an expand operand. Store the operand in *OP. */
@@ -16524,7 +16801,7 @@ mips_expand_builtin_bposge (enum mips_builtin_type builtin_type, rtx target)
static rtx
mips_expand_builtin (tree exp, rtx target, rtx subtarget ATTRIBUTE_UNUSED,
- enum machine_mode mode, int ignore)
+ machine_mode mode, int ignore)
{
tree fndecl;
unsigned int fcode, avail;
@@ -16575,7 +16852,7 @@ struct mips16_constant {
struct mips16_constant *next;
rtx value;
rtx label;
- enum machine_mode mode;
+ machine_mode mode;
};
/* Information about an incomplete MIPS16 constant pool. FIRST is the
@@ -16593,7 +16870,7 @@ struct mips16_constant_pool {
static rtx
mips16_add_constant (struct mips16_constant_pool *pool,
- rtx value, enum machine_mode mode)
+ rtx value, machine_mode mode)
{
struct mips16_constant **p, *c;
bool first_of_size_p;
@@ -16649,7 +16926,7 @@ mips16_add_constant (struct mips16_constant_pool *pool,
instruction emitted. MODE is the mode of the constant. */
static rtx
-mips16_emit_constants_1 (enum machine_mode mode, rtx value, rtx insn)
+mips16_emit_constants_1 (machine_mode mode, rtx value, rtx insn)
{
if (SCALAR_INT_MODE_P (mode) || ALL_SCALAR_FIXED_POINT_MODE_P (mode))
{
@@ -17019,7 +17296,7 @@ r10k_safe_mem_expr_p (tree expr, unsigned HOST_WIDE_INT offset)
{
HOST_WIDE_INT bitoffset, bitsize;
tree inner, var_offset;
- enum machine_mode mode;
+ machine_mode mode;
int unsigned_p, volatile_p;
inner = get_inner_reference (expr, &bitsize, &bitoffset, &var_offset, &mode,
@@ -17687,7 +17964,7 @@ mips_mult_zero_zero_cost (struct mips_sim *state, bool setting)
mips_tuning_info.fast_mult_zero_zero_p = setting;
start_sequence ();
- enum machine_mode dword_mode = TARGET_64BIT ? TImode : DImode;
+ machine_mode dword_mode = TARGET_64BIT ? TImode : DImode;
rtx hilo = gen_rtx_REG (dword_mode, MD_REG_FIRST);
mips_emit_move_or_split (hilo, const0_rtx, SPLIT_FOR_SPEED);
@@ -17711,7 +17988,7 @@ mips_mult_zero_zero_cost (struct mips_sim *state, bool setting)
static void
mips_set_fast_mult_zero_zero_p (struct mips_sim *state)
{
- if (TARGET_MIPS16 || !ISA_HAS_HILO)
+ if (TARGET_MIPS16 || (!ISA_HAS_HILO && !TARGET_DSP))
/* No MTLO or MTHI available for MIPS16. Also, when there are no HI or LO
registers then there is no reason to zero them, arbitrarily choose to
say that "MULT $0,$0" would be faster. */
@@ -18071,7 +18348,7 @@ mips_orphaned_high_part_p (mips_offset_table htab, rtx insn)
static void
mips_avoid_hazard (rtx after, rtx insn, int *hilo_delay,
- rtx *delayed_reg, rtx lo_reg)
+ rtx *delayed_reg, rtx lo_reg, bool *fs_delay)
{
rtx pattern, set;
int nops, ninsns;
@@ -18097,6 +18374,15 @@ mips_avoid_hazard (rtx after, rtx insn, int *hilo_delay,
nops = 2 - *hilo_delay;
else if (*delayed_reg != 0 && reg_referenced_p (*delayed_reg, pattern))
nops = 1;
+ /* If processing a forbidden slot hazard then a NOP is required if the
+ branch instruction was not in a sequence (as the sequence would
+ imply it is not actually a compact branch anyway) and the current
+ insn is not an inline asm, and can't go in a delay slot. */
+ else if (*fs_delay && get_attr_can_delay (insn) == CAN_DELAY_NO
+ && GET_CODE (PATTERN (after)) != SEQUENCE
+ && GET_CODE (pattern) != ASM_INPUT
+ && asm_noperands (pattern) < 0)
+ nops = 1;
else
nops = 0;
@@ -18109,12 +18395,18 @@ mips_avoid_hazard (rtx after, rtx insn, int *hilo_delay,
/* Set up the state for the next instruction. */
*hilo_delay += ninsns;
*delayed_reg = 0;
+ *fs_delay = false;
if (INSN_CODE (insn) >= 0)
switch (get_attr_hazard (insn))
{
case HAZARD_NONE:
break;
+ case HAZARD_FORBIDDEN_SLOT:
+ if (TARGET_CB_MAYBE)
+ *fs_delay = true;
+ break;
+
case HAZARD_HILO:
*hilo_delay = 0;
break;
@@ -18138,6 +18430,7 @@ mips_reorg_process_insns (void)
rtx insn, last_insn, subinsn, next_insn, lo_reg, delayed_reg;
int hilo_delay;
mips_offset_table htab;
+ bool fs_delay;
/* Force all instructions to be split into their final form. */
split_all_insns_noflow ();
@@ -18206,6 +18499,7 @@ mips_reorg_process_insns (void)
hilo_delay = 2;
delayed_reg = 0;
lo_reg = gen_rtx_REG (SImode, LO_REGNUM);
+ fs_delay = false;
/* Make a second pass over the instructions. Delete orphaned
high-part relocations or turn them into NOPs. Avoid hazards
@@ -18229,7 +18523,7 @@ mips_reorg_process_insns (void)
INSN_CODE (subinsn) = CODE_FOR_nop;
}
mips_avoid_hazard (last_insn, subinsn, &hilo_delay,
- &delayed_reg, lo_reg);
+ &delayed_reg, lo_reg, &fs_delay);
}
last_insn = insn;
}
@@ -18250,7 +18544,7 @@ mips_reorg_process_insns (void)
else
{
mips_avoid_hazard (last_insn, insn, &hilo_delay,
- &delayed_reg, lo_reg);
+ &delayed_reg, lo_reg, &fs_delay);
last_insn = insn;
}
}
@@ -18983,7 +19277,7 @@ mips_option_override (void)
else
{
/* -msingle-float selects 32-bit float registers. On r6 and later,
- -mdouble-float selects 64-bit float registers, since the old paired
+ -mdouble-float selects 64-bit float registers, since the old paired
register model is not supported. -mmsa selects 64-bit registers for
O32. In other cases the float registers should be the same size as
the integer ones. */
@@ -19094,15 +19388,11 @@ mips_option_override (void)
" instructions", mips_arch_info->name);
/* If neither -modd-spreg nor -mno-odd-spreg was given on the command
- line, set MASK_ODD_SPREG based on the ISA. */
+ line, set MASK_ODD_SPREG based on the ISA and ABI. */
if ((target_flags_explicit & MASK_ODD_SPREG) == 0)
{
- /* Disable TARGET_ODD_SPREG for generic architectures when using the
- O32 FPXX ABI to make them compatible with those implementations
- which are !ISA_HAS_ODD_SPREG. */
- if (!ISA_HAS_ODD_SPREG
- || (TARGET_FLOATXX
- && (strncmp (mips_arch_info->name, "mips", 4) == 0)))
+ /* Disable TARGET_ODD_SPREG when using the o32 FPXX ABI. */
+ if (!ISA_HAS_ODD_SPREG || TARGET_FLOATXX)
target_flags &= ~MASK_ODD_SPREG;
else
target_flags |= MASK_ODD_SPREG;
@@ -19111,6 +19401,35 @@ mips_option_override (void)
warning (0, "the %qs architecture does not support odd single-precision"
" registers", mips_arch_info->name);
+ if (!TARGET_ODD_SPREG && TARGET_64BIT)
+ {
+ error ("unsupported combination: %s", "-mgp64 -mno-odd-spreg");
+ /* Allow compilation to continue further even though invalid output
+ will be produced. */
+ target_flags |= MASK_ODD_SPREG;
+ }
+
+ if (!ISA_HAS_COMPACT_BRANCHES && mips_cb == MIPS_CB_ALWAYS)
+ {
+ error ("unsupported combination: %qs%s %s",
+ mips_arch_info->name, TARGET_MICROMIPS ? " -mmicromips" : "",
+ "-mcompact-branches=always");
+ }
+ else if (!ISA_HAS_DELAY_SLOTS && mips_cb == MIPS_CB_NEVER)
+ {
+ error ("unsupported combination: %qs%s %s",
+ mips_arch_info->name, TARGET_MICROMIPS ? " -mmicromips" : "",
+ "-mcompact-branches=never");
+ }
+
+ /* Require explicit relocs for MIPS R6 onwards. This enables simplification
+ of the compact branch and jump support through the backend. */
+ if (!TARGET_EXPLICIT_RELOCS && mips_isa_rev >= 6)
+ {
+ error ("unsupported combination: %qs %s",
+ mips_arch_info->name, "-mno-explicit-relocs");
+ }
+
/* The effect of -mabicalls isn't defined for the EABI. */
if (mips_abi == ABI_EABI && TARGET_ABICALLS)
{
@@ -19254,14 +19573,14 @@ mips_option_override (void)
if (TARGET_DSPR2)
TARGET_DSP = true;
- if (TARGET_DSP && mips_isa_rev >= 6)
+ if (TARGET_DSPR3)
{
- error ("the %qs architecture does not support DSP instructions",
- mips_arch_info->name);
- TARGET_DSP = false;
- TARGET_DSPR2 = false;
+ TARGET_DSP = true;
+ TARGET_DSPR2 = true;
}
+
+
/* .eh_frame addresses should be the same width as a C pointer.
Most MIPS ABIs support only one pointer size, so the assembler
will usually know exactly how big an .eh_frame address is.
@@ -19325,7 +19644,7 @@ mips_option_override (void)
for (mode = 0; mode < MAX_MACHINE_MODE; mode++)
for (regno = 0; regno < FIRST_PSEUDO_REGISTER; regno++)
mips_hard_regno_mode_ok[mode][regno]
- = mips_hard_regno_mode_ok_p (regno, (enum machine_mode) mode);
+ = mips_hard_regno_mode_ok_p (regno, (machine_mode) mode);
/* Function to allocate machine-dependent function status. */
init_machine_status = &mips_init_machine_status;
@@ -19442,7 +19761,7 @@ mips_conditional_register_usage (void)
AND_COMPL_HARD_REG_SET (accessible_reg_set,
reg_class_contents[(int) DSP_ACC_REGS]);
- if (!ISA_HAS_HILO)
+ if (!ISA_HAS_HILO && !ISA_HAS_DSP)
AND_COMPL_HARD_REG_SET (accessible_reg_set,
reg_class_contents[(int) MD_REGS]);
@@ -19533,28 +19852,6 @@ mips_conditional_register_usage (void)
}
}
-/* When generating MIPS16 code, we want to allocate $24 (T_REG) before
- other registers for instructions for which it is possible. This
- encourages the compiler to use CMP in cases where an XOR would
- require some register shuffling. */
-
-void
-mips_order_regs_for_local_alloc (void)
-{
- int i;
-
- for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
- reg_alloc_order[i] = i;
-
- if (TARGET_MIPS16)
- {
- /* It really doesn't matter where we put register 0, since it is
- a fixed register anyhow. */
- reg_alloc_order[0] = 24;
- reg_alloc_order[24] = 0;
- }
-}
-
/* Implement EH_USES. */
bool
@@ -19845,6 +20142,64 @@ umips_load_store_pair_p_1 (bool load_p, bool swap_p,
return true;
}
+bool
+mips_load_store_bonding_p (rtx *operands, machine_mode mode, bool load_p)
+{
+ rtx reg1, reg2, mem1, mem2, base1, base2;
+ enum reg_class rc1, rc2;
+ HOST_WIDE_INT offset1, offset2;
+
+ if (load_p)
+ {
+ reg1 = operands[0];
+ reg2 = operands[2];
+ mem1 = operands[1];
+ mem2 = operands[3];
+ }
+ else
+ {
+ reg1 = operands[1];
+ reg2 = operands[3];
+ mem1 = operands[0];
+ mem2 = operands[2];
+ }
+
+ if (!mips_address_insns (XEXP (mem1, 0), mode, false)
+ || !mips_address_insns (XEXP (mem2, 0), mode, false))
+ return false;
+
+ mips_split_plus (XEXP (mem1, 0), &base1, &offset1);
+ mips_split_plus (XEXP (mem2, 0), &base2, &offset2);
+
+ /* Base regs do not match. */
+ if (!REG_P (base1) || !rtx_equal_p (base1, base2))
+ return false;
+
+ /* Either of the loads is clobbering base register. */
+ if (load_p
+ && (REGNO (reg1) == REGNO (base1)
+ || (REGNO (reg2) == REGNO (base1))))
+ return false;
+
+ /* Loading in same registers. */
+ if (load_p
+ && REGNO (reg1) == REGNO (reg2))
+ return false;
+
+ /* The loads/stores are not of same type. */
+ rc1 = REGNO_REG_CLASS (REGNO (reg1));
+ rc2 = REGNO_REG_CLASS (REGNO (reg2));
+ if (rc1 != rc2
+ && !reg_class_subset_p (rc1, rc2)
+ && !reg_class_subset_p (rc2, rc1))
+ return false;
+
+ if (abs(offset1 - offset2) != GET_MODE_SIZE (mode))
+ return false;
+
+ return true;
+}
+
/* OPERANDS describes the operands to a pair of SETs, in the order
dest1, src1, dest2, src2. Return true if the operands can be used
in an LWP or SWP instruction; LOAD_P says which. */
@@ -20103,6 +20458,18 @@ mips_trampoline_init (rtx m_tramp, tree fndecl, rtx chain_value)
#undef OP
+ /* If we are using compact branches we don't have delay slots so
+ place the instruction that was in the delay slot before the JRC
+ instruction. */
+
+ if (TARGET_CB_ALWAYS)
+ {
+ rtx temp;
+ temp = trampoline[i-2];
+ trampoline[i-2] = trampoline[i-1];
+ trampoline[i-1] = temp;
+ }
+
/* Copy the trampoline code. Leave any padding uninitialized. */
for (j = 0; j < i; j++)
{
@@ -20181,7 +20548,7 @@ void mips_function_profiler (FILE *file)
when TARGET_LOONGSON_VECTORS is true. */
static unsigned HOST_WIDE_INT
-mips_shift_truncation_mask (enum machine_mode mode)
+mips_shift_truncation_mask (machine_mode mode)
{
if (TARGET_LOONGSON_VECTORS && VECTOR_MODE_P (mode))
return 0;
@@ -20220,13 +20587,13 @@ mips_prepare_pch_save (void)
/* Generate or test for an insn that supports a constant permutation. */
-#define MAX_VECT_LEN 8
+#define MAX_VECT_LEN 16
struct expand_vec_perm_d
{
rtx target, op0, op1;
unsigned char perm[MAX_VECT_LEN];
- enum machine_mode vmode;
+ machine_mode vmode;
unsigned char nelt;
bool one_vector_p;
bool testing_p;
@@ -20264,7 +20631,7 @@ static bool
mips_expand_vselect_vconcat (rtx target, rtx op0, rtx op1,
const unsigned char *perm, unsigned nelt)
{
- enum machine_mode v2mode;
+ machine_mode v2mode;
rtx x;
v2mode = GET_MODE_2XWIDER_MODE (GET_MODE (op0));
@@ -20535,10 +20902,21 @@ mips_expand_vec_perm_const (rtx operands[4])
return ok;
}
+/* Implement TARGET_SCHED_REASSOCIATION_WIDTH. */
+
+static int
+mips_sched_reassociation_width (unsigned int opc ATTRIBUTE_UNUSED,
+ machine_mode mode)
+{
+ if (MSA_SUPPORTED_MODE_P (mode))
+ return 2;
+ return 1;
+}
+
/* Implement TARGET_VECTORIZE_VEC_PERM_CONST_OK. */
static bool
-mips_vectorize_vec_perm_const_ok (enum machine_mode vmode,
+mips_vectorize_vec_perm_const_ok (machine_mode vmode,
const unsigned char *sel)
{
struct expand_vec_perm_d d;
@@ -20583,11 +20961,66 @@ mips_vectorize_vec_perm_const_ok (enum machine_mode vmode,
void
mips_expand_vec_unpack (rtx operands[2], bool unsigned_p, bool high_p)
{
- enum machine_mode imode = GET_MODE (operands[1]);
+ machine_mode imode = GET_MODE (operands[1]);
rtx (*unpack) (rtx, rtx, rtx);
- rtx (*cmpgt) (rtx, rtx, rtx);
+ rtx (*cmpFunc) (rtx, rtx, rtx);
rtx tmp, dest, zero;
+ if (ISA_HAS_MSA)
+ {
+ switch (imode)
+ {
+ case V4SImode:
+ if (BYTES_BIG_ENDIAN != high_p)
+ unpack = gen_msa_ilvl_w;
+ else
+ unpack = gen_msa_ilvr_w;
+
+ cmpFunc = gen_msa_clti_si_w;
+ break;
+
+ case V8HImode:
+ if (BYTES_BIG_ENDIAN != high_p)
+ unpack = gen_msa_ilvl_h;
+ else
+ unpack = gen_msa_ilvr_h;
+
+ cmpFunc = gen_msa_clti_si_h;
+ break;
+
+ case V16QImode:
+ if (BYTES_BIG_ENDIAN != high_p)
+ unpack = gen_msa_ilvl_b;
+ else
+ unpack = gen_msa_ilvr_b;
+
+ cmpFunc = gen_msa_clti_si_b;
+ break;
+
+ default:
+ gcc_unreachable ();
+ break;
+ }
+
+ if (!unsigned_p)
+ {
+ /* Extract sign extention for each element comparing each element with
+ immediate zero. */
+ tmp = gen_reg_rtx (imode);
+ emit_insn (cmpFunc (tmp, operands[1], CONST0_RTX (imode)));
+ }
+ else
+ {
+ tmp = force_reg (imode, CONST0_RTX (imode));
+ }
+
+ dest = gen_reg_rtx (imode);
+
+ emit_insn (unpack (dest, tmp, operands[1]));
+ emit_move_insn (operands[0], gen_lowpart (GET_MODE (operands[0]), dest));
+ return;
+ }
+
switch (imode)
{
case V8QImode:
@@ -20595,14 +21028,14 @@ mips_expand_vec_unpack (rtx operands[2], bool unsigned_p, bool high_p)
unpack = gen_loongson_punpckhbh;
else
unpack = gen_loongson_punpcklbh;
- cmpgt = gen_loongson_pcmpgtb;
+ cmpFunc = gen_loongson_pcmpgtb;
break;
case V4HImode:
if (high_p)
unpack = gen_loongson_punpckhhw;
else
unpack = gen_loongson_punpcklhw;
- cmpgt = gen_loongson_pcmpgth;
+ cmpFunc = gen_loongson_pcmpgth;
break;
default:
gcc_unreachable ();
@@ -20614,7 +21047,7 @@ mips_expand_vec_unpack (rtx operands[2], bool unsigned_p, bool high_p)
else
{
tmp = gen_reg_rtx (imode);
- emit_insn (cmpgt (tmp, zero, operands[1]));
+ emit_insn (cmpFunc (tmp, zero, operands[1]));
}
dest = gen_reg_rtx (imode);
@@ -20634,7 +21067,7 @@ mips_constant_elt_p (rtx x)
/* A subroutine of mips_expand_vec_init, expand via broadcast. */
static void
-mips_expand_vi_broadcast (enum machine_mode vmode, rtx target, rtx elt)
+mips_expand_vi_broadcast (machine_mode vmode, rtx target, rtx elt)
{
struct expand_vec_perm_d d;
rtx t1;
@@ -20674,7 +21107,7 @@ mips_expand_vi_broadcast (enum machine_mode vmode, rtx target, rtx elt)
elements of VALS with zeros, copy the constant vector to TARGET. */
static void
-mips_expand_vi_constant (enum machine_mode vmode, unsigned nelt,
+mips_expand_vi_constant (machine_mode vmode, unsigned nelt,
rtx target, rtx vals)
{
rtvec vec = shallow_copy_rtvec (XVEC (vals, 0));
@@ -20705,7 +21138,7 @@ mips_expand_vi_loongson_one_pinsrh (rtx target, rtx vals, unsigned one_var)
/* A subroutine of mips_expand_vec_init, expand anything via memory. */
static void
-mips_expand_vi_general (enum machine_mode vmode, enum machine_mode imode,
+mips_expand_vi_general (machine_mode vmode, machine_mode imode,
unsigned nelt, unsigned nvar, rtx target, rtx vals)
{
rtx mem = assign_stack_temp (vmode, GET_MODE_SIZE (vmode));
@@ -20729,8 +21162,8 @@ mips_expand_vi_general (enum machine_mode vmode, enum machine_mode imode,
void
mips_expand_vector_init (rtx target, rtx vals)
{
- enum machine_mode vmode = GET_MODE (target);
- enum machine_mode imode = GET_MODE_INNER (vmode);
+ machine_mode vmode = GET_MODE (target);
+ machine_mode imode = GET_MODE_INNER (vmode);
unsigned i, nelt = GET_MODE_NUNITS (vmode);
unsigned nvar = 0, one_var = -1u;
bool all_same = true;
@@ -20750,8 +21183,7 @@ mips_expand_vector_init (rtx target, rtx vals)
if (all_same)
{
rtx same = XVECEXP (vals, 0, 0);
- rtx temp;
- rtx temp2;
+ rtx temp, temp2;
if (CONST_INT_P (same) && nvar == 0 && mips_signed_immediate_p (INTVAL (same), 10, 0))
{
@@ -20779,19 +21211,27 @@ mips_expand_vector_init (rtx target, rtx vals)
}
temp = gen_reg_rtx (imode);
if (imode == GET_MODE (same))
- emit_move_insn (temp, same);
+ temp2 = same;
+ else if (GET_MODE_SIZE (imode) >= UNITS_PER_WORD)
+ temp2 = simplify_gen_subreg (imode, same, GET_MODE (same), 0);
else
- emit_move_insn (temp, simplify_gen_subreg (imode, same, GET_MODE (same), 0));
+ {
+ unsigned offset = 0;
+
+ if (TARGET_BIG_ENDIAN)
+ offset = GET_MODE_SIZE (GET_MODE (same)) - GET_MODE_SIZE (imode);
+ temp2 = simplify_gen_subreg (imode, same, GET_MODE (same), offset);
+ }
+ emit_move_insn (temp, temp2);
+
switch (vmode)
{
case V16QImode:
- temp2 = simplify_gen_subreg (SImode, temp, imode, 0);
- emit_insn (gen_msa_fill_b (target, temp2));
+ emit_insn (gen_msa_fill_b_insn (target, temp));
break;
case V8HImode:
- temp2 = simplify_gen_subreg (SImode, temp, imode, 0);
- emit_insn (gen_msa_fill_h (target, temp2));
+ emit_insn (gen_msa_fill_h_insn (target, temp));
break;
case V4SImode:
@@ -20816,7 +21256,6 @@ mips_expand_vector_init (rtx target, rtx vals)
return;
}
-
rtvec vec = shallow_copy_rtvec (XVEC (vals, 0));
for (i = 0; i < nelt; ++i)
@@ -20904,7 +21343,7 @@ mips_expand_vector_init (rtx target, rtx vals)
void
mips_expand_vec_reduc (rtx target, rtx in, rtx (*gen)(rtx, rtx, rtx))
{
- enum machine_mode vmode = GET_MODE (in);
+ machine_mode vmode = GET_MODE (in);
unsigned char perm2[2];
rtx last, next, fold, x;
bool ok;
@@ -20976,7 +21415,7 @@ void
mips_expand_vec_minmax (rtx target, rtx op0, rtx op1,
rtx (*cmp) (rtx, rtx, rtx), bool min_p)
{
- enum machine_mode vmode = GET_MODE (target);
+ machine_mode vmode = GET_MODE (target);
rtx tc, t0, t1, x;
tc = gen_reg_rtx (vmode);
@@ -20997,10 +21436,25 @@ mips_expand_vec_minmax (rtx target, rtx op0, rtx op1,
emit_insn (gen_rtx_SET (VOIDmode, target, x));
}
+/* Implement HARD_REGNO_CALLER_SAVE_MODE. */
+
+machine_mode
+mips_hard_regno_caller_save_mode (unsigned int regno,
+ unsigned int nregs,
+ machine_mode mode)
+{
+ /* For performance, avoid saving/restoring upper parts of a register
+ by returning MODE as save mode when the mode is known. */
+ if (mode == VOIDmode)
+ return choose_hard_reg_mode (regno, nregs, false);
+ else
+ return mode;
+}
+
static void
mips_expand_msa_one_cmpl (rtx dest, rtx src)
{
- enum machine_mode mode = GET_MODE (dest);
+ machine_mode mode = GET_MODE (dest);
switch (mode)
{
case V16QImode:
@@ -21023,7 +21477,7 @@ mips_expand_msa_one_cmpl (rtx dest, rtx src)
static void
mips_expand_msa_cmp (rtx dest, enum rtx_code cond, rtx op0, rtx op1)
{
- enum machine_mode cmp_mode = GET_MODE (op0);
+ machine_mode cmp_mode = GET_MODE (op0);
switch (cmp_mode)
{
@@ -21046,13 +21500,13 @@ mips_expand_msa_cmp (rtx dest, enum rtx_code cond, rtx op0, rtx op1)
emit_insn (gen_msa_cle_u_b (dest, op0, op1));
break;
case GE: // swap
- emit_insn (gen_msa_clt_s_b (dest, op1, op0));
+ emit_insn (gen_msa_cle_s_b (dest, op1, op0));
break;
case GT: // swap
emit_insn (gen_msa_clt_s_b (dest, op1, op0));
break;
case GEU: // swap
- emit_insn (gen_msa_clt_u_b (dest, op1, op0));
+ emit_insn (gen_msa_cle_u_b (dest, op1, op0));
break;
case GTU: // swap
emit_insn (gen_msa_clt_u_b (dest, op1, op0));
@@ -21081,13 +21535,13 @@ mips_expand_msa_cmp (rtx dest, enum rtx_code cond, rtx op0, rtx op1)
emit_insn (gen_msa_cle_u_h (dest, op0, op1));
break;
case GE: // swap
- emit_insn (gen_msa_clt_s_h (dest, op1, op0));
+ emit_insn (gen_msa_cle_s_h (dest, op1, op0));
break;
case GT: // swap
emit_insn (gen_msa_clt_s_h (dest, op1, op0));
break;
case GEU: // swap
- emit_insn (gen_msa_clt_u_h (dest, op1, op0));
+ emit_insn (gen_msa_cle_u_h (dest, op1, op0));
break;
case GTU: // swap
emit_insn (gen_msa_clt_u_h (dest, op1, op0));
@@ -21116,13 +21570,13 @@ mips_expand_msa_cmp (rtx dest, enum rtx_code cond, rtx op0, rtx op1)
emit_insn (gen_msa_cle_u_w (dest, op0, op1));
break;
case GE: // swap
- emit_insn (gen_msa_clt_s_w (dest, op1, op0));
+ emit_insn (gen_msa_cle_s_w (dest, op1, op0));
break;
case GT: // swap
emit_insn (gen_msa_clt_s_w (dest, op1, op0));
break;
case GEU: // swap
- emit_insn (gen_msa_clt_u_w (dest, op1, op0));
+ emit_insn (gen_msa_cle_u_w (dest, op1, op0));
break;
case GTU: // swap
emit_insn (gen_msa_clt_u_w (dest, op1, op0));
@@ -21151,13 +21605,13 @@ mips_expand_msa_cmp (rtx dest, enum rtx_code cond, rtx op0, rtx op1)
emit_insn (gen_msa_cle_u_d (dest, op0, op1));
break;
case GE: // swap
- emit_insn (gen_msa_clt_s_d (dest, op1, op0));
+ emit_insn (gen_msa_cle_s_d (dest, op1, op0));
break;
case GT: // swap
emit_insn (gen_msa_clt_s_d (dest, op1, op0));
break;
case GEU: // swap
- emit_insn (gen_msa_clt_u_d (dest, op1, op0));
+ emit_insn (gen_msa_cle_u_d (dest, op1, op0));
break;
case GTU: // swap
emit_insn (gen_msa_clt_u_d (dest, op1, op0));
@@ -21176,6 +21630,9 @@ mips_expand_msa_cmp (rtx dest, enum rtx_code cond, rtx op0, rtx op1)
case EQ:
emit_insn (gen_msa_fceq_w (dest, op0, op1));
break;
+ case NE:
+ emit_insn (gen_msa_fcne_w (dest, op0, op1));
+ break;
case LTGT:
emit_insn (gen_msa_fcne_w (dest, op0, op1));
break;
@@ -21217,6 +21674,9 @@ mips_expand_msa_cmp (rtx dest, enum rtx_code cond, rtx op0, rtx op1)
case EQ:
emit_insn (gen_msa_fceq_d (dest, op0, op1));
break;
+ case NE:
+ emit_insn (gen_msa_fcne_d (dest, op0, op1));
+ break;
case LTGT:
emit_insn (gen_msa_fcne_d (dest, op0, op1));
break;
@@ -21274,7 +21734,6 @@ mips_msa_reversed_fp_cond (enum rtx_code *code)
{
switch (*code)
{
- case NE:
case ORDERED:
case UNEQ:
*code = reverse_condition_maybe_unordered (*code);
@@ -21285,12 +21744,16 @@ mips_msa_reversed_fp_cond (enum rtx_code *code)
}
}
+/* Generate RTL for comparing CMP_OP0, CMP_ OP1 using condition COND
+ and store the result -1 or 0 in DEST TRUE_SRC and DEST_SRC
+ must be -1 and 0 respectively. */
+
static void
mips_expand_msa_vcond (rtx dest, rtx true_src, rtx false_src,
enum rtx_code cond, rtx cmp_op0, rtx cmp_op1)
{
- enum machine_mode dest_mode = GET_MODE (dest);
- enum machine_mode cmp_mode = GET_MODE (cmp_op0);
+ machine_mode dest_mode = GET_MODE (dest);
+ machine_mode cmp_mode = GET_MODE (cmp_op0);
bool reversed_p;
if (FLOAT_MODE_P (cmp_mode))
@@ -21307,18 +21770,17 @@ mips_expand_msa_vcond (rtx dest, rtx true_src, rtx false_src,
&& (false_src == CONST0_RTX (dest_mode)));
}
-/* Expand VEC_COND_EXPR
- * MODE of result
- * VIMODE equivalent integer mode
- * OPERANDS operands of VEC_COND_EXPR
- * gen_msa_and_fn used to generate a VIMODE vector msa AND
- * gen_msa_nor_fn used to generate a VIMODE vector msa NOR
- * gen_msa_ior_fn used to generate a VIMODE vector msa AND.
- */
+/* Expand VEC_COND_EXPR, where:
+ MODE is mode of the result
+ VIMODE equivalent integer mode
+ OPERANDS operands of VEC_COND_EXPR
+ gen_msa_and_fn used to generate a VIMODE vector msa AND
+ gen_msa_nor_fn used to generate a VIMODE vector msa NOR
+ gen_msa_ior_fn used to generate a VIMODE vector msa AND. */
void
-mips_expand_vec_cond_expr (enum machine_mode mode,
- enum machine_mode vimode,
+mips_expand_vec_cond_expr (machine_mode mode,
+ machine_mode vimode,
rtx *operands,
rtx (*gen_msa_and_fn)(rtx, rtx, rtx),
rtx (*gen_msa_nor_fn)(rtx, rtx, rtx),
@@ -21340,15 +21802,15 @@ mips_expand_vec_cond_expr (enum machine_mode mode,
mips_expand_msa_vcond (res, true_val, false_val,
GET_CODE (operands[3]), operands[4], operands[5]);
- // This results in a vector result with whose T/F elements having
- // the value -1 or 0 for (T/F repectively). This result may need
- // adjusting if needed results operands[]/operands[1] are different.
+ /* This results in a vector result with whose T/F elements having
+ the value -1 or 0 for (T/F repectively). This result may need
+ adjusting if needed results operands[]/operands[1] are different. */
- // Adjust True elements to be operand[1].
+ /* Adjust True elements to be operand[1]. */
emit_move_insn (xres, res);
if (operands[1] != true_val)
{
- rtx xop1 = operands[1]; /* Assume we can use operands[1] */
+ rtx xop1 = operands[1]; /* Assume we can use operands[1]. */
if (mode != vimode)
{
@@ -21375,11 +21837,11 @@ mips_expand_vec_cond_expr (enum machine_mode mode,
else
emit_move_insn (temp1, xres);
- // Adjust False elements to be operand[0].
+ /* Adjust False elements to be operand[0]. */
emit_insn (gen_msa_nor_fn (temp2, xres, xres));
if (operands[2] != false_val)
{
- rtx xop2 = operands[2]; ; /* Assume we can use operands[2] */
+ rtx xop2 = operands[2]; ; /* Assume we can use operands[2]. */
if (mode != vimode)
{
@@ -21406,28 +21868,13 @@ mips_expand_vec_cond_expr (enum machine_mode mode,
else
emit_insn (gen_msa_and_fn (temp2, temp2, xres));
- // Combine together into result.
+ /* Combine together into result. */
emit_insn (gen_msa_ior_fn (xres, temp1, temp2));
emit_move_insn (operands[0],
gen_rtx_SUBREG (mode, xres, 0));
}
}
-/* Implement HARD_REGNO_CALLER_SAVE_MODE. */
-
-enum machine_mode
-mips_hard_regno_caller_save_mode (unsigned int regno,
- unsigned int nregs,
- enum machine_mode mode)
-{
- /* For performance, to avoid saving/restoring upper parts of a register,
- we return MODE as save mode when MODE is not VOIDmode. */
- if (mode == VOIDmode)
- return choose_hard_reg_mode (regno, nregs, false);
- else
- return mode;
-}
-
/* Implement TARGET_CASE_VALUES_THRESHOLD. */
unsigned int
@@ -21487,7 +21934,7 @@ mips_atomic_assign_expand_fenv (tree *hold, tree *clear, tree *update)
static reg_class_t
mips_spill_class (reg_class_t rclass ATTRIBUTE_UNUSED,
- enum machine_mode mode ATTRIBUTE_UNUSED)
+ machine_mode mode ATTRIBUTE_UNUSED)
{
if (TARGET_MIPS16)
return SPILL_REGS;
@@ -21655,6 +22102,9 @@ mips_lra_p (void)
#undef TARGET_MODE_REP_EXTENDED
#define TARGET_MODE_REP_EXTENDED mips_mode_rep_extended
+#undef TARGET_VECTORIZE_BUILTIN_VECTORIZED_FUNCTION
+#define TARGET_VECTORIZE_BUILTIN_VECTORIZED_FUNCTION \
+ mips_builtin_vectorized_function
#undef TARGET_VECTOR_MODE_SUPPORTED_P
#define TARGET_VECTOR_MODE_SUPPORTED_P mips_vector_mode_supported_p
@@ -21710,6 +22160,8 @@ mips_lra_p (void)
#endif
#undef TARGET_DWARF_REGISTER_SPAN
#define TARGET_DWARF_REGISTER_SPAN mips_dwarf_register_span
+#undef TARGET_DWARF_FRAME_REG_MODE
+#define TARGET_DWARF_FRAME_REG_MODE mips_dwarf_frame_reg_mode
#undef TARGET_ASM_FINAL_POSTSCAN_INSN
#define TARGET_ASM_FINAL_POSTSCAN_INSN mips_final_postscan_insn
@@ -21741,6 +22193,9 @@ mips_lra_p (void)
#undef TARGET_VECTORIZE_VEC_PERM_CONST_OK
#define TARGET_VECTORIZE_VEC_PERM_CONST_OK mips_vectorize_vec_perm_const_ok
+#undef TARGET_SCHED_REASSOCIATION_WIDTH
+#define TARGET_SCHED_REASSOCIATION_WIDTH mips_sched_reassociation_width
+
#undef TARGET_CASE_VALUES_THRESHOLD
#define TARGET_CASE_VALUES_THRESHOLD mips_case_values_threshold
@@ -21758,6 +22213,12 @@ mips_lra_p (void)
#undef TARGET_SCHED_FINISH_GLOBAL
#define TARGET_SCHED_FINISH_GLOBAL mips_sched_finish_global
+#undef TARGET_SCHED_DEPENDENCIES_EVALUATION_HOOK
+#define TARGET_SCHED_DEPENDENCIES_EVALUATION_HOOK mips_evaluation_hook
+
+#undef TARGET_SCHED_SET_SCHED_FLAGS
+#define TARGET_SCHED_SET_SCHED_FLAGS mips_set_sched_flags
+
struct gcc_target targetm = TARGET_INITIALIZER;
#include "gt-mips.h"