Sorry for the slow review.
Matthew Fortune <[email protected]> writes:
> The initial support for MIP64r6 is intentionally minimal to make review
> easier. Performance enhancements and use of new MIPS64r6 features will
> be introduced separately. The current patch makes no attempt to
> get the testsuite appropriately configured for MIPS64r6 as the existing
> structure relies on each MIPS revision being a superset of the previous.
> Recommendations on how to rework the mips.exp logic to cope with this
> would be appreciated.
Could you give an example of the kind of thing you mean?
If tests really do need r5 or earlier, we should enforce that in the
dg-options. E.g. for conditional moves we should add an isa_rev
limit to the existing tests and add new ones with isa_rev>=6.
I suppose we'll need a way of specifying an isa_rev range, say
"isa_rev=2-5". That should be a fairly localised change though.
The:
# Handle dependencies between the pre-arch options and the arch option.
# This should mirror the arch and post-arch code below.
if { !$arch_test_option_p } {
block should start with something like:
if (isa_rev >= 6
&& ...tests for things r6 doesn't support..) {
if { $gp_size == 32 } {
mips_make_test_option options "-mips32r2"
} else {
mips_make_test_option options "-mips64r2"
}
And:
if { $arch_test_option_p } {
should have a corresponding:
if { $isa_rev > 5 } {
...force options that r6 doesn't support to off...
}
before the unsets.
> diff --git a/gcc/config/mips/constraints.md b/gcc/config/mips/constraints.md
> index f6834fd..f93ae1c 100644
> --- a/gcc/config/mips/constraints.md
> +++ b/gcc/config/mips/constraints.md
> @@ -324,10 +324,14 @@ (define_address_constraint "ZD"
> "When compiling microMIPS code, this constraint matches an address operand
> that is formed from a base register and a 12-bit offset. These operands
> can be used for microMIPS instructions such as @code{prefetch}. When
> - not compiling for microMIPS code, @code{ZD} is equivalent to @code{p}."
> + not compiling for microMIPS code, @code{ZD} is either equivalent to
> + @code{p} or matches an address operand that is formed from a base register
> + and a 9-bit offset, depending on ISA support."
Maybe just change the comment to:
"An address suitable for a @code{prefetch} instruction, or for any other
instruction with the same addressing mode as @code{prefetch}."
perhaps going on to say what the microMIPS, r6 and other cases are,
if you think that's better.
You need to update md.texi too; it isn't "yet" automatic.
> (if_then_else (match_test "TARGET_MICROMIPS")
> (match_test "umips_12bit_offset_address_p (op, mode)")
> - (match_test "mips_address_insns (op, mode, false)")))
> + (if_then_else (match_test "ISA_HAS_PREFETCH_9BIT")
> + (match_test "mipsr6_9bit_offset_address_p (op, mode)")
> + (match_test "mips_address_insns (op, mode, false)"))))
Please use (cond ...) instead.
> diff --git a/gcc/config/mips/linux.h b/gcc/config/mips/linux.h
> index e539422..751623f 100644
> --- a/gcc/config/mips/linux.h
> +++ b/gcc/config/mips/linux.h
> @@ -18,8 +18,9 @@ along with GCC; see the file COPYING3. If not see
> <http://www.gnu.org/licenses/>. */
>
> #define GLIBC_DYNAMIC_LINKER \
> - "%{mnan=2008:/lib/ld-linux-mipsn8.so.1;:/lib/ld.so.1}"
> + "%{mnan=2008|mips32r6|mips64r6:/lib/ld-linux-mipsn8.so.1;:/lib/ld.so.1}"
>
> #undef UCLIBC_DYNAMIC_LINKER
> #define UCLIBC_DYNAMIC_LINKER \
> - "%{mnan=2008:/lib/ld-uClibc-mipsn8.so.0;:/lib/ld-uClibc.so.0}"
> + "%{mnan=2008|mips32r6|mips64r6:/lib/ld-uClibc-mipsn8.so.0;" \
> + ":/lib/ld-uClibc.so.0}"
Rather than update all the specs like this, I think we should force
-mnan=2008 onto the command line for r6 using DRIVER_SELF_SPECS.
See e.g. MIPS_ISA_SYNCI_SPEC.
> diff --git a/gcc/config/mips/mips-protos.h b/gcc/config/mips/mips-protos.h
> index 0b32a70..9560506 100644
> --- a/gcc/config/mips/mips-protos.h
> +++ b/gcc/config/mips/mips-protos.h
> @@ -341,6 +341,7 @@ extern bool umips_load_store_pair_p (bool, rtx *);
> extern void umips_output_load_store_pair (bool, rtx *);
> extern bool umips_movep_target_p (rtx, rtx);
> extern bool umips_12bit_offset_address_p (rtx, enum machine_mode);
> +extern bool mipsr6_9bit_offset_address_p (rtx, enum machine_mode);
Would prefer just mips_9bit..., since a 9-bit offset looks the same
for all ISA levels. I suppose it should have been just mips_12bit... too.
Same for MIPSR6_9BIT_OFFSET_P.
> @@ -4186,6 +4230,46 @@ mips_rtx_costs (rtx x, int code, int outer_code, int
> opno ATTRIBUTE_UNUSED,
> }
> *total = mips_zero_extend_cost (mode, XEXP (x, 0));
> return false;
> + case TRUNCATE:
> + /* Costings for highpart multiplies. */
> + if (ISA_HAS_R6MUL
> + && (GET_CODE (XEXP (x, 0)) == ASHIFTRT
> + || GET_CODE (XEXP (x, 0)) == LSHIFTRT)
> + && CONST_INT_P (XEXP (XEXP (x, 0), 1))
> + && ((INTVAL (XEXP (XEXP (x, 0), 1)) == 32
> + && GET_MODE (XEXP (x, 0)) == DImode)
> + || (ISA_HAS_R6DMUL
> + && INTVAL (XEXP (XEXP (x, 0), 1)) == 64
> + && GET_MODE (XEXP (x, 0)) == TImode))
> + && GET_CODE (XEXP (XEXP (x, 0), 0)) == MULT
> + && ((GET_CODE (XEXP (XEXP (XEXP (x, 0), 0), 0)) == SIGN_EXTEND
> + && GET_CODE (XEXP (XEXP (XEXP (x, 0), 0), 1)) == SIGN_EXTEND)
> + || (GET_CODE (XEXP (XEXP (XEXP (x, 0), 0), 0)) == ZERO_EXTEND
> + && (GET_CODE (XEXP (XEXP (XEXP (x, 0), 0), 1))
> + == ZERO_EXTEND))))
Ouch :-/
> + {
> + if (!speed)
> + *total = COSTS_N_INSNS (1) + 1;
> + else if (mode == DImode)
> + *total = mips_cost->int_mult_di;
> + else
> + *total = mips_cost->int_mult_si;
> +
> + /* Sign extension is free, zero extension costs for DImode when
> + on a 64bit core / when DMUL is present. */
> + if (ISA_HAS_R6DMUL && GET_MODE (XEXP (x, 0)) == DImode)
> + {
> + if (GET_CODE (XEXP (XEXP (XEXP (x, 0), 0), 0)) == ZERO_EXTEND)
> + *total += rtx_cost (XEXP (XEXP (XEXP (x, 0), 0), 0),
> + ZERO_EXTEND, 0, speed);
> +
> + if (GET_CODE (XEXP (XEXP (XEXP (x, 0), 0), 1)) == ZERO_EXTEND)
> + *total += rtx_cost (XEXP (XEXP (XEXP (x, 0), 0), 1),
> + ZERO_EXTEND, 0, speed);
> + }
> + return true;
In the calls to rtx_cost, the outer code should be MULT rather than
ZERO_EXTEND. Maybe:
for (int i = 0; i < 2; ++i)
{
rtx op = XEXP (XEXP (XEXP (x, 0), 0), i);
if (ISA_HAS_R6DMUL
&& GET_CODE (op) == ZERO_EXTEND
&& GET_MODE (op) == DImode)
*total += rtx_cost (op, MULT, i, speed);
else
*total += rtx_cost (XEXP (op, 0), GET_CODE (op), 0, speed);
}
so that we consistently add the costs of the operands.
> @@ -4969,17 +5053,32 @@ mips_emit_compare (enum rtx_code *code, rtx *op0, rtx
> *op1, bool need_eq_ne_p)
> {
> enum rtx_code cmp_code;
>
> - /* Floating-point tests use a separate C.cond.fmt comparison to
> - set a condition code register. The branch or conditional move
> - will then compare that register against zero.
> + /* Floating-point tests use a separate C.cond.fmt or CMP.cond.fmt
> + comparison to set a condition code register. The branch or
> + conditional move will then compare that register against zero.
"condition code register" doesn't apply to CMP. Maybe just "register"?
> @@ -5105,7 +5232,9 @@ mips_expand_conditional_trap (rtx comparison)
>
> mode = GET_MODE (XEXP (comparison, 0));
> op0 = force_reg (mode, op0);
> - if (!arith_operand (op1, mode))
> + if (!arith_operand (op1, mode)
> + || (!ISA_HAS_COND_TRAPI
> + && !register_operand (op1, mode)))
> op1 = force_reg (mode, op1);
arith_operand isn't meaningful without ISA_HAS_COND_TRAPI, so:
if (!(ISA_HAS_COND_TRAPI
? arith_operand (op1, mode)
: register_operand (op1, mode)))
op1 = force_reg (mode, op1);
> @@ -11753,6 +11893,10 @@ mips_hard_regno_mode_ok_p (unsigned int regno, enum
> machine_mode mode)
> && ST_REG_P (regno)
> && (regno - ST_REG_FIRST) % 4 == 0);
>
> + if (mode == CCFmode)
> + return (ISA_HAS_CCF
> + && FP_REG_P (regno));
> +
> if (mode == CCmode)
> return ISA_HAS_8CC ? ST_REG_P (regno) : regno == FPSW_REGNUM;
No need for the line split.
> @@ -11925,6 +12069,9 @@ mips_mode_ok_for_mov_fmt_p (enum machine_mode mode)
> {
> switch (mode)
> {
> + case CCFmode:
> + return TARGET_HARD_FLOAT;
> +
> case SFmode:
> return TARGET_HARD_FLOAT;
Nit: might as well combine the cases.
> @@ -12190,6 +12337,10 @@ mips_secondary_reload_class (enum reg_class rclass,
> /* In this case we can use mov.fmt. */
> return NO_REGS;
>
> + /* We don't need a reload if the pseudo is in memory in CCF mode. */
> + if (mode == CCFmode && regno == -1)
> + return NO_REGS;
> +
> /* Otherwise, we need to reload through an integer register. */
> return GR_REGS;
> }
We should instead change the MEM_P in:
if (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;
to "(MEM_P (x) || regno == -1)". There's not really anything special
about CCFmode here.
> @@ -15789,7 +15940,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)
> + if (TARGET_MIPS16 || !ISA_HAS_MULT)
> /* No MTLO or MTHI available. */
> mips_tuning_info.fast_mult_zero_zero_p = true;
> else
I think ISA_HAS_HILO would be better than ISA_HAS_MULT, and should
be used to define ISA_HAS_MULT, ISA_HAS_DMULT etc. in mips.h.
Same for a few other ISA_HAS_MULT tests in the patch.
Probably worth adding a comment saying that the choice doesn't
matter here since we will never need to move to HI or LO.
> @@ -17035,7 +17186,9 @@ mips_option_override (void)
>
> if ((target_flags_explicit & MASK_FLOAT64) != 0)
> {
> - if (TARGET_SINGLE_FLOAT && TARGET_FLOAT64)
> + if (mips_isa_rev >= 6 && !TARGET_FLOAT64)
> + error ("unsupported combination: %s", "-mips[32|64]r6 -mfp32");
Should use the actual arch rather than [32|64]. Note that ACONCAT ((...))
is available for building temporary strings.
> @@ -17052,8 +17205,12 @@ mips_option_override (void)
> else
> {
> /* -msingle-float selects 32-bit float registers. Otherwise the
> - float registers should be the same size as the integer ones. */
> - if (TARGET_64BIT && TARGET_DOUBLE_FLOAT)
> + float registers should be the same size as the integer ones.
> + MIPS R6 has 64-bit float registers regardless of the size of
> + the integer ones. */
> + if (mips_isa_rev >= 6 && TARGET_DOUBLE_FLOAT)
> + target_flags |= MASK_FLOAT64;
> + else if (TARGET_64BIT && TARGET_DOUBLE_FLOAT)
> target_flags |= MASK_FLOAT64;
> else
> target_flags &= ~MASK_FLOAT64;
Sorry, a pet peeve is comments of the form "X must be Y" becoming
"X must be Y. When foo, X might not be Y.". Can you fold it into the
existing comment a bit more? E.g.:
/* -msingle-float selects 32-bit float registers. On r6 and later,
-mdouble-float selects 64-bit float registers, since the old
paired-register model is not supported. In other cases the float
registers should be the same size as the integer ones. */
> @@ -17209,6 +17366,25 @@ mips_option_override (void)
> }
> }
>
> + /* Set NaN and ABS defaults. */
> + if (mips_nan == MIPS_IEEE_754_DEFAULT && !ISA_HAS_NANLEGACY)
> + mips_nan = MIPS_IEEE_754_2008;
> + if (mips_abs == MIPS_IEEE_754_DEFAULT && !ISA_HAS_NANLEGACY)
> + mips_abs = MIPS_IEEE_754_2008;
> +
> + /* Check for NaN encoding support. */
> + if ((mips_nan == MIPS_IEEE_754_LEGACY
> + || mips_abs == MIPS_IEEE_754_LEGACY)
> + && !ISA_HAS_NANLEGACY)
> + warning (0, "the %qs architecture does not support the NaN legacy"
> + " encoding", mips_arch_info->name);
> +
> + if ((mips_nan == MIPS_IEEE_754_2008
> + || mips_abs == MIPS_IEEE_754_2008)
> + && !ISA_HAS_NAN2008)
> + warning (0, "the %qs architecture does not support the NaN 2008"
> + " encoding", mips_arch_info->name);
The message is misleading. mips_abs is about whether ABS is an arithmetic
or a sign-bit operation, not about the NaN encoding.
> @@ -17263,6 +17439,10 @@ mips_option_override (void)
> if (TARGET_DSPR2)
> TARGET_DSP = true;
>
> + if (TARGET_DSP && mips_isa_rev >= 6)
> + error ("the %qs architecture does not support DSP instructions",
> + mips_arch_info->name);
I think we'd later ICE if the code went on to use DSP registers,
so better set TARGET_DSPR2 and TARGET_DSP to false here.
...ah, actually, I see you added conditions to ISA_HAS_DSP instead.
I think doing it here would be better. The idea is that TARGET_*
should be accurate for the underlying architecture, with ISA_HAS_*
only varying depending on the ISA encoding.
> @@ -18006,7 +18195,10 @@ mips_trampoline_init (rtx m_tramp, tree fndecl, rtx
> chain_value)
> trampoline[i++] = OP (MIPS_LOAD_PTR (STATIC_CHAIN_REGNUM,
> static_chain_offset,
> PIC_FUNCTION_ADDR_REGNUM));
> - trampoline[i++] = OP (MIPS_JR (AT_REGNUM));
> + if (ISA_HAS_JR)
> + trampoline[i++] = OP (MIPS_JR (AT_REGNUM));
> + else
> + trampoline[i++] = OP (MIPS_JALR0 (AT_REGNUM));
> trampoline[i++] = OP (MIPS_MOVE (PIC_FUNCTION_ADDR_REGNUM, AT_REGNUM));
> }
> else if (ptr_mode == DImode)
> @@ -18032,7 +18224,10 @@ mips_trampoline_init (rtx m_tramp, tree fndecl, rtx
> chain_value)
> trampoline[i++] = OP (MIPS_LOAD_PTR (STATIC_CHAIN_REGNUM,
> static_chain_offset - 12,
> RETURN_ADDR_REGNUM));
> - trampoline[i++] = OP (MIPS_JR (PIC_FUNCTION_ADDR_REGNUM));
> + if (ISA_HAS_JR)
> + trampoline[i++] = OP (MIPS_JR (PIC_FUNCTION_ADDR_REGNUM));
> + else
> + trampoline[i++] = OP (MIPS_JALR0 (PIC_FUNCTION_ADDR_REGNUM));
> trampoline[i++] = OP (MIPS_MOVE (RETURN_ADDR_REGNUM, AT_REGNUM));
> }
> else
> @@ -18074,7 +18269,12 @@ mips_trampoline_init (rtx m_tramp, tree fndecl, rtx
> chain_value)
>
> /* Emit the JR here, if we can. */
> if (!ISA_HAS_LOAD_DELAY)
> - trampoline[i++] = OP (MIPS_JR (PIC_FUNCTION_ADDR_REGNUM));
> + {
> + if (ISA_HAS_JR)
> + trampoline[i++] = OP (MIPS_JR (PIC_FUNCTION_ADDR_REGNUM));
> + else
> + trampoline[i++] = OP (MIPS_JALR0 (PIC_FUNCTION_ADDR_REGNUM));
> + }
>
> /* Emit the load of the static chain register. */
> opcode = OP (MIPS_LOAD_PTR (STATIC_CHAIN_REGNUM,
> @@ -18086,7 +18286,10 @@ mips_trampoline_init (rtx m_tramp, tree fndecl, rtx
> chain_value)
> /* Emit the JR, if we couldn't above. */
> if (ISA_HAS_LOAD_DELAY)
> {
> - trampoline[i++] = OP (MIPS_JR (PIC_FUNCTION_ADDR_REGNUM));
> + if (ISA_HAS_JR)
> + trampoline[i++] = OP (MIPS_JR (PIC_FUNCTION_ADDR_REGNUM));
> + else
> + trampoline[i++] = OP (MIPS_JALR0 (PIC_FUNCTION_ADDR_REGNUM));
> trampoline[i++] = OP (MIPS_NOP);
> }
> }
Probably easier to make MIPS_JR return the JALR encoding for !ISA_HAS_JR.
> @@ -444,42 +446,12 @@ struct mips_cpu_info {
> builtin_define ("__mips=4"); \
> builtin_define ("_MIPS_ISA=_MIPS_ISA_MIPS4"); \
> } \
> - else if (ISA_MIPS32) \
> + else if (mips_isa >= 32 && mips_isa < 64)
> \
> { \
> builtin_define ("__mips=32"); \
> builtin_define ("_MIPS_ISA=_MIPS_ISA_MIPS32"); \
> } \
> - else if (ISA_MIPS32R2) \
> - { \
> - builtin_define ("__mips=32"); \
> - builtin_define ("_MIPS_ISA=_MIPS_ISA_MIPS32"); \
> - } \
> - else if (ISA_MIPS32R3) \
> - { \
> - builtin_define ("__mips=32"); \
> - builtin_define ("_MIPS_ISA=_MIPS_ISA_MIPS32"); \
> - } \
> - else if (ISA_MIPS32R5) \
> - { \
> - builtin_define ("__mips=32"); \
> - builtin_define ("_MIPS_ISA=_MIPS_ISA_MIPS32"); \
> - } \
> - else if (ISA_MIPS64) \
> - { \
> - builtin_define ("__mips=64"); \
> - builtin_define ("_MIPS_ISA=_MIPS_ISA_MIPS64"); \
> - } \
> - else if (ISA_MIPS64R2) \
> - { \
> - builtin_define ("__mips=64"); \
> - builtin_define ("_MIPS_ISA=_MIPS_ISA_MIPS64"); \
> - } \
> - else if (ISA_MIPS64R3) \
> - { \
> - builtin_define ("__mips=64"); \
> - builtin_define ("_MIPS_ISA=_MIPS_ISA_MIPS64"); \
> - } \
> - else if (ISA_MIPS64R5) \
> + else if (mips_isa >= 64)
> \
> { \
> builtin_define ("__mips=64"); \
> builtin_define ("_MIPS_ISA=_MIPS_ISA_MIPS64"); \
Oops, really should have noticed this one, sorry! Thanks for cleaning it up.
> @@ -927,6 +937,9 @@ struct mips_cpu_info {
> /* ISA has floating-point madd and msub instructions 'd = a * b [+-] c'. */
> #define ISA_HAS_FP_MADD4_MSUB4 ISA_HAS_FP4
>
> +/* ISA has floating-point maddf and msubf instructions 'd = d [+-] a * b'.
> */
> +#define ISA_HAS_FP_MADDF_MSUBF (mips_isa_rev >= 6)
> +
> /* ISA has floating-point madd and msub instructions 'c = a * b [+-] c'. */
> #define ISA_HAS_FP_MADD3_MSUB3 TARGET_LOONGSON_2EF
c = c ...
> +#define ISA_HAS_NANLEGACY (mips_isa_rev <= 5)
> +
> +#define ISA_HAS_NAN2008 (mips_isa_rev >= 2)
Nit, but the existing enum has a "_" before the LEGACY and 2008.
Might as well have one here too for consistency.
> @@ -327,6 +329,7 @@ (define_attr "accum_in" "none,0,1,2,3,4,5" (const_string
> "none"))
> ;; imadd integer multiply-add
> ;; idiv integer divide 2 operands
> ;; idiv3 integer divide 3 operands
> +;; idiv3nc integer divide 3 operands without clobbering HI/LO
> ;; move integer register move ({,D}ADD{,U} with rt = 0)
> ;; fmove floating point register move
> ;; fadd floating point add/subtract
This type isn't used anywhere (which is good -- I think reusing idiv3
is the right thing to do).
> @@ -759,6 +762,11 @@ (define_mode_iterator MOVECC [SI (DI "TARGET_64BIT")
> && !TARGET_LOONGSON_2EF
> && !TARGET_MIPS5900")])
>
> +;; This mode iterator allows :FPCC to be used anywhere that an FP condition
> +;; is needed.
> +(define_mode_iterator FPCC [(CC "!ISA_HAS_CCF")
> + (CCF "ISA_HAS_CCF")])
> +
> ;; 32-bit integer moves for which we provide move patterns.
> (define_mode_iterator IMOVE32
> [SI
> @@ -848,7 +856,7 @@ (define_mode_attr si8_di5 [(SI "8") (DI "5")])
>
> ;; This attribute gives the best constraint to use for registers of
> ;; a given mode.
> -(define_mode_attr reg [(SI "d") (DI "d") (CC "z")])
> +(define_mode_attr reg [(SI "d") (DI "d") (CC "z") (CCF "f")])
>
> ;; This attribute gives the format suffix for floating-point operations.
> (define_mode_attr fmt [(SF "s") (DF "d") (V2SF "ps")])
> @@ -888,6 +896,9 @@ (define_mode_attr divide_condition
> (define_mode_attr sqrt_condition
> [(SF "!ISA_MIPS1") (DF "!ISA_MIPS1") (V2SF "TARGET_SB1")])
>
> +;; This attribute provides the correct nmemonic for each FP condition mode.
> +(define_mode_attr fpcmp [(CC "c") (CCF "cmp")])
> +
> ;; This code iterator allows signed and unsigned widening multiplications
> ;; to use the same template.
> (define_code_iterator any_extend [sign_extend zero_extend])
This seems really clean, thanks.
> @@ -1105,16 +1126,25 @@ (define_expand "ctrap<mode>4"
> [(match_operand:GPR 1 "reg_or_0_operand")
> (match_operand:GPR 2 "arith_operand")])
> (match_operand 3 "const_0_operand"))]
> - "ISA_HAS_COND_TRAP"
> + "ISA_HAS_COND_TRAPI || ISA_HAS_COND_TRAP"
> {
> mips_expand_conditional_trap (operands[0]);
> DONE;
> })
>
> +(define_insn "*conditional_trapi<mode>"
> + [(trap_if (match_operator:GPR 0 "trap_comparison_operator"
> + [(match_operand:GPR 1 "reg_or_0_operand" "dJ")
> + (match_operand:GPR 2 "const_arith_operand" "I")])
> + (const_int 0))]
> + "ISA_HAS_COND_TRAPI"
> + "t%C0\t%z1,%2"
> + [(set_attr "type" "trap")])
> +
> (define_insn "*conditional_trap<mode>"
> [(trap_if (match_operator:GPR 0 "trap_comparison_operator"
> [(match_operand:GPR 1 "reg_or_0_operand" "dJ")
> - (match_operand:GPR 2 "arith_operand" "dI")])
> + (match_operand:GPR 2 "register_operand" "d")])
> (const_int 0))]
> "ISA_HAS_COND_TRAP"
> "t%C0\t%z1,%2"
It's better to keep the "d" and "I" alternatives as part of one pattern,
since that gives the register allocator more freedom. So I think we want
to keep *conditional_trap<mode> as-is and add a new pattern for
ISA_HAS_COND_TRAP && !ISA_HAS_COND_TRAPI.
In commutative comparisons the zero should come second, so it'd be
better to use reg_or_0_operand/dJ instead of register_operand/d.
Same goes for the register_operand in mips_expand_conditional_trap.
> @@ -1484,13 +1514,13 @@ (define_expand "mul<mode>3"
> [(set (match_operand:GPR 0 "register_operand")
> (mult:GPR (match_operand:GPR 1 "register_operand")
> (match_operand:GPR 2 "register_operand")))]
> - "ISA_HAS_<D>MULT"
> + "ISA_HAS_<D>MULT || ISA_HAS_R6<D>MUL"
> {
> rtx lo;
>
> - if (TARGET_LOONGSON_2EF || TARGET_LOONGSON_3A)
> - emit_insn (gen_mul<mode>3_mul3_loongson (operands[0], operands[1],
> - operands[2]));
> + if (TARGET_LOONGSON_2EF || TARGET_LOONGSON_3A || ISA_HAS_R6<D>MUL)
> + emit_insn (gen_mul<mode>3_mul3_r6 (operands[0], operands[1],
> + operands[2]));
> else if (ISA_HAS_<D>MUL3)
> emit_insn (gen_mul<mode>3_mul3 (operands[0], operands[1], operands[2]));
> else if (TARGET_MIPS16)
It's a bit confusing to use "_r6" as the suffix for a pattern that's
shared with Loongson. Maybe "_nohilo", or something?
> @@ -3872,7 +4018,7 @@ (define_expand "extvmisalign<mode>"
> (sign_extract:GPR (match_operand:BLK 1 "memory_operand")
> (match_operand 2 "const_int_operand")
> (match_operand 3 "const_int_operand")))]
> - "!TARGET_MIPS16"
> + "ISA_HAS_LWL_LWR && !TARGET_MIPS16"
Please put the TARGET_MIPS16 condition in the ISA_HAS_LWL_LWR definition.
> @@ -6906,6 +7059,41 @@ (define_insn "*mov<SCALARF:mode>_on_<MOVECC:mode>"
> [(set_attr "type" "condmove")
> (set_attr "mode" "<SCALARF:MODE>")])
>
> +(define_insn "*sel<code><GPR:mode>_using_<GPR2:mode>"
> + [(set (match_operand:GPR 0 "register_operand" "=d,d")
> + (if_then_else:GPR
> + (equality_op:GPR2 (match_operand:GPR2 1 "register_operand" "d,d")
> + (const_int 0))
> + (match_operand:GPR 2 "reg_or_0_operand" "d,J")
> + (match_operand:GPR 3 "reg_or_0_operand" "J,d")))]
> + "ISA_HAS_SEL
> + && (register_operand (operands[2], <GPR:MODE>mode)
> + ^ register_operand (operands[3], <GPR:MODE>mode))"
> + "@
> + <sel>\t%0,%2,%1
> + <selinv>\t%0,%3,%1"
> + [(set_attr "type" "condmove")
> + (set_attr "mode" "<GPR:MODE>")])
"!=" seems more obvious than "^".
> @@ -6914,8 +7102,13 @@ (define_expand "mov<mode>cc"
> (if_then_else:GPR (match_dup 5)
> (match_operand:GPR 2 "reg_or_0_operand")
> (match_operand:GPR 3 "reg_or_0_operand")))]
> - "ISA_HAS_CONDMOVE"
> + "ISA_HAS_CONDMOVE || ISA_HAS_SEL"
> {
> + if (ISA_HAS_SEL
> + && (GET_MODE (XEXP (operands[1], 0)) != SImode)
> + && (GET_MODE (XEXP (operands[1], 0)) != DImode))
> + FAIL;
> +
> mips_expand_conditional_move (operands);
> DONE;
> })
Maybe INTEGRAL_MODE_P here?
> @@ -6924,10 +7117,16 @@ (define_expand "mov<mode>cc"
> [(set (match_dup 4) (match_operand 1 "comparison_operator"))
> (set (match_operand:SCALARF 0 "register_operand")
> (if_then_else:SCALARF (match_dup 5)
> - (match_operand:SCALARF 2 "register_operand")
> - (match_operand:SCALARF 3 "register_operand")))]
> - "ISA_HAS_FP_CONDMOVE"
> -{
> + (match_operand:SCALARF 2 "reg_or_0_operand")
> + (match_operand:SCALARF 3 "reg_or_0_operand")))]
> + "ISA_HAS_FP_CONDMOVE
> + || (ISA_HAS_SEL && ISA_HAS_CCF)"
> +{
> + if (ISA_HAS_SEL
> + && GET_MODE (XEXP (operands[1], 0)) != SFmode
> + && GET_MODE (XEXP (operands[1], 0)) != DFmode)
> + FAIL;
> +
> mips_expand_conditional_move (operands);
> DONE;
> })
Same for FLOAT_MODE_P here.
Looks really good though. I was afraid r6 was going to be more invasive
than it ended up being.
Thanks,
Richard