Sorry for the slow review. Matthew Fortune <matthew.fort...@imgtec.com> 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