From 21dfc6dc74ab21fe6d5dc487c20cb121cacc7528 Mon Sep 17 00:00:00 2001 From: Richard Sandiford Date: Mon, 9 Jun 2008 20:45:56 +0000 Subject: [PATCH] md.texi: Synchronize with later constraints.md change. gcc/ * doc/md.texi: Synchronize with later constraints.md change. * longlong.h (umul_ppmm): Replace the MIPS asm implementation with a C implementation. * config/mips/mips.c (mips_legitimize_move): Remove MFHI and MFLO handling. (mips_subword): Assume TImode for CONST_INTs if TARGET_64BIT. (mips_split_doubleword_move): Use special MTHI and MFHI instructions when moving to and from MD_REGNUM. (mips_output_move): Don't handle moves from GPRs to HI_REGNUM. Handle moves from LO_REGNUM to GPRs using MFLO, MACC or DMACC. Handle byte and halfword moves. (mips_hard_regno_mode_ok_p): Handle MD_REGS and DSP_ACC_REGS separately. * config/mips/constraints.md (h): Turn into NO_REGS. (l, x): Update documentation. * config/mips/mips.md (UNSPEC_MFHILO): Delete. (UNSPEC_MFHI, UNSPEC_MTHI, UNSPEC_SET_HILO): New. (UNSPEC_TLS_LDM, UNSPEC_TLS_GET_TP): Renumber. (HILO): New mode iterator. (MOVE128): Add TI. (any_div): New code iterator. (u): Extend code attribute to div and udiv. (*add3_mips16, *movdi_64bit_mips16, *movsi_mips16): Use d_operand in the splitters. Remove redundant CONST_INT checks. (mulsi3_mult3, mul3_internal, mul3_r4000, *mul_acc_si) (*macc, *msac, *msac_using_macc, *macc2, *msac2, *mul_sub_si) (*muls): Remove "=h" clobbers. Adjust peephole2s and define_splits accordingly, using normal moves instead of unspecs to move LO into a GPR. Use d_operand and lo_operand instead of *_REG_P checks. (mulsidi3): Handle expansion in C code. (mulsidi3_32bit_internal): Rename to... (mulsidi3_32bit): ...this. (mulsidi3_32bit_r4000): Fix insn separator. (*mulsidi3_64bit): Rename to... (mulsidi3_64bit): ...this. Combine DImode "=h" and "=l" clobbers into a TImode "=x" clobber. In the split, use an UNSPEC_SET_HILO to set LO and HI to the multiplication result. Use a normal move for MFLO and an unspec for MFHI. (*mulsidi3_64bit_parts): Replace with... (mulsidi3_64bit_hilo): ...this new instruction. (mulsi3_highpart): Extend to TARGET_FIX_R4000. (mulsi3_highpart_internal): Turn into a define_insn_and_split and extend it to TARGET_FIX_R4000. Store the destination in a GPR instead of HI. Split the instruction into a separate multiplication and MFHI if !TARGET_FIX_R4000. (muldi3_highpart): Likewise. (mulsi3_highpart_mulhi_internal): Remove the first alternative and the "=h" clobber. (*mulsi3_highpart_neg_mulhi_internal): Likewise. (mulditi3): New expander. (mulditi3_internal, mulditi3_r4000): New patterns. (madsi): Remove "=h" clobber. (divmod4, udivmod4): Turn into define_insn_and_splits. Force the modulus result to be a GPR and split the instruction into a division followed by an MFHI after reload. (divmod4_hilo_): New instruction. (*lea_high64): Use d_operand in the define_peephole2. Likewise the MIPS16 HIGH define_split. (*movdi_32bit, *movdi_gp32_fp64, *movdi_32bit_mips16): Change type of acc<->gpr moves to "multi". (*movdi_64bit): Replace the single "x" alternative with alternatives for moving into and out of "a". (*movhi_internal, *movqi_internal): Likewise. Use mips_output_move. (*movsi_internal): Extend the "d<-A" alternative to "d<-a". (*movdi_64bit_mips16, *movsi_mips16): Add d<-a alternatives. Use d_operand in the splitters. Remove redundant CONST_INT checks. (*movhi_mips16, *movqi_mips16): Likewise. Use mips_output_move. (movti): New expander. (*movti, *movti_mips16): New insns. (mfhilo_, *mfhilo_, *mfhilo__macc): Delete. (mfhi_): New pattern. (mthi_): Likewise. * config/mips/predicates.md (fpr_operand): Delete. (d_operand): New predicate. gcc/testsuite/ * gcc.dg/torture/mips-hilo-1.c: Delete. * gcc.target/mips/pr35232.c: Likewise. * gcc.target/mips/fix-vr4130-1.c: Use modulus to create an mfhi. * gcc.target/mips/fix-vr4130-3.c: Likewise. * gcc.target/mips/int-moves-1.c: New test. * gcc.target/mips/int-moves-2.c: Likewise. * gcc.target/mips/fix-r4000-1.c: Likewise. * gcc.target/mips/fix-r4000-2.c: Likewise. * gcc.target/mips/fix-r4000-3.c: Likewise. * gcc.target/mips/fix-r4000-4.c: Likewise. * gcc.target/mips/fix-r4000-5.c: Likewise. * gcc.target/mips/fix-r4000-6.c: Likewise. * gcc.target/mips/fix-r4000-7.c: Likewise. * gcc.target/mips/fix-r4000-8.c: Likewise. * gcc.target/mips/fix-r4000-9.c: Likewise. * gcc.target/mips/fix-r4000-10.c: Likewise. * gcc.target/mips/fix-r4000-11.c: Likewise. * gcc.target/mips/fix-r4000-12.c: Likewise. * gcc.target/mips/timode-1.c: Likewise. * gcc.target/mips/timode-2.c: Likewise. From-SVN: r136600 --- gcc/ChangeLog | 77 ++ gcc/config/mips/constraints.md | 10 +- gcc/config/mips/mips.c | 103 ++- gcc/config/mips/mips.md | 828 ++++++++++--------- gcc/config/mips/predicates.md | 6 +- gcc/doc/md.texi | 8 +- gcc/longlong.h | 12 +- gcc/testsuite/ChangeLog | 23 + gcc/testsuite/gcc.dg/torture/mips-hilo-1.c | 73 -- gcc/testsuite/gcc.target/mips/fix-r4000-1.c | 6 + gcc/testsuite/gcc.target/mips/fix-r4000-10.c | 8 + gcc/testsuite/gcc.target/mips/fix-r4000-11.c | 4 + gcc/testsuite/gcc.target/mips/fix-r4000-12.c | 4 + gcc/testsuite/gcc.target/mips/fix-r4000-2.c | 7 + gcc/testsuite/gcc.target/mips/fix-r4000-3.c | 7 + gcc/testsuite/gcc.target/mips/fix-r4000-4.c | 8 + gcc/testsuite/gcc.target/mips/fix-r4000-5.c | 8 + gcc/testsuite/gcc.target/mips/fix-r4000-6.c | 6 + gcc/testsuite/gcc.target/mips/fix-r4000-7.c | 7 + gcc/testsuite/gcc.target/mips/fix-r4000-8.c | 7 + gcc/testsuite/gcc.target/mips/fix-r4000-9.c | 8 + gcc/testsuite/gcc.target/mips/fix-vr4130-1.c | 6 +- gcc/testsuite/gcc.target/mips/fix-vr4130-3.c | 8 +- gcc/testsuite/gcc.target/mips/int-moves-1.c | 40 + gcc/testsuite/gcc.target/mips/int-moves-2.c | 40 + gcc/testsuite/gcc.target/mips/pr35232.c | 17 - gcc/testsuite/gcc.target/mips/timode-1.c | 65 ++ gcc/testsuite/gcc.target/mips/timode-2.c | 64 ++ 28 files changed, 917 insertions(+), 543 deletions(-) delete mode 100644 gcc/testsuite/gcc.dg/torture/mips-hilo-1.c create mode 100644 gcc/testsuite/gcc.target/mips/fix-r4000-1.c create mode 100644 gcc/testsuite/gcc.target/mips/fix-r4000-10.c create mode 100644 gcc/testsuite/gcc.target/mips/fix-r4000-11.c create mode 100644 gcc/testsuite/gcc.target/mips/fix-r4000-12.c create mode 100644 gcc/testsuite/gcc.target/mips/fix-r4000-2.c create mode 100644 gcc/testsuite/gcc.target/mips/fix-r4000-3.c create mode 100644 gcc/testsuite/gcc.target/mips/fix-r4000-4.c create mode 100644 gcc/testsuite/gcc.target/mips/fix-r4000-5.c create mode 100644 gcc/testsuite/gcc.target/mips/fix-r4000-6.c create mode 100644 gcc/testsuite/gcc.target/mips/fix-r4000-7.c create mode 100644 gcc/testsuite/gcc.target/mips/fix-r4000-8.c create mode 100644 gcc/testsuite/gcc.target/mips/fix-r4000-9.c create mode 100644 gcc/testsuite/gcc.target/mips/int-moves-1.c create mode 100644 gcc/testsuite/gcc.target/mips/int-moves-2.c delete mode 100644 gcc/testsuite/gcc.target/mips/pr35232.c create mode 100644 gcc/testsuite/gcc.target/mips/timode-1.c create mode 100644 gcc/testsuite/gcc.target/mips/timode-2.c diff --git a/gcc/ChangeLog b/gcc/ChangeLog index da2a69ffce4..f3fbaa29f93 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,80 @@ +2008-06-09 Richard Sandiford + + * doc/md.texi: Synchronize with later constraints.md change. + * longlong.h (umul_ppmm): Replace the MIPS asm implementation + with a C implementation. + * config/mips/mips.c (mips_legitimize_move): Remove MFHI and + MFLO handling. + (mips_subword): Assume TImode for CONST_INTs if TARGET_64BIT. + (mips_split_doubleword_move): Use special MTHI and MFHI instructions + when moving to and from MD_REGNUM. + (mips_output_move): Don't handle moves from GPRs to HI_REGNUM. + Handle moves from LO_REGNUM to GPRs using MFLO, MACC or DMACC. + Handle byte and halfword moves. + (mips_hard_regno_mode_ok_p): Handle MD_REGS and DSP_ACC_REGS + separately. + * config/mips/constraints.md (h): Turn into NO_REGS. + (l, x): Update documentation. + * config/mips/mips.md (UNSPEC_MFHILO): Delete. + (UNSPEC_MFHI, UNSPEC_MTHI, UNSPEC_SET_HILO): New. + (UNSPEC_TLS_LDM, UNSPEC_TLS_GET_TP): Renumber. + (HILO): New mode iterator. + (MOVE128): Add TI. + (any_div): New code iterator. + (u): Extend code attribute to div and udiv. + (*add3_mips16, *movdi_64bit_mips16, *movsi_mips16): Use + d_operand in the splitters. Remove redundant CONST_INT checks. + (mulsi3_mult3, mul3_internal, mul3_r4000, *mul_acc_si) + (*macc, *msac, *msac_using_macc, *macc2, *msac2, *mul_sub_si) + (*muls): Remove "=h" clobbers. Adjust peephole2s and define_splits + accordingly, using normal moves instead of unspecs to move LO into + a GPR. Use d_operand and lo_operand instead of *_REG_P checks. + (mulsidi3): Handle expansion in C code. + (mulsidi3_32bit_internal): Rename to... + (mulsidi3_32bit): ...this. + (mulsidi3_32bit_r4000): Fix insn separator. + (*mulsidi3_64bit): Rename to... + (mulsidi3_64bit): ...this. Combine DImode "=h" and "=l" clobbers + into a TImode "=x" clobber. In the split, use an UNSPEC_SET_HILO + to set LO and HI to the multiplication result. Use a normal move + for MFLO and an unspec for MFHI. + (*mulsidi3_64bit_parts): Replace with... + (mulsidi3_64bit_hilo): ...this new instruction. + (mulsi3_highpart): Extend to TARGET_FIX_R4000. + (mulsi3_highpart_internal): Turn into a define_insn_and_split + and extend it to TARGET_FIX_R4000. Store the destination in a GPR + instead of HI. Split the instruction into a separate multiplication + and MFHI if !TARGET_FIX_R4000. + (muldi3_highpart): Likewise. + (mulsi3_highpart_mulhi_internal): Remove the first alternative + and the "=h" clobber. + (*mulsi3_highpart_neg_mulhi_internal): Likewise. + (mulditi3): New expander. + (mulditi3_internal, mulditi3_r4000): New patterns. + (madsi): Remove "=h" clobber. + (divmod4, udivmod4): Turn into define_insn_and_splits. + Force the modulus result to be a GPR and split the instruction into + a division followed by an MFHI after reload. + (divmod4_hilo_): New instruction. + (*lea_high64): Use d_operand in the define_peephole2. Likewise + the MIPS16 HIGH define_split. + (*movdi_32bit, *movdi_gp32_fp64, *movdi_32bit_mips16): Change type + of acc<->gpr moves to "multi". + (*movdi_64bit): Replace the single "x" alternative with + alternatives for moving into and out of "a". + (*movhi_internal, *movqi_internal): Likewise. Use mips_output_move. + (*movsi_internal): Extend the "d<-A" alternative to "d<-a". + (*movdi_64bit_mips16, *movsi_mips16): Add d<-a alternatives. + Use d_operand in the splitters. Remove redundant CONST_INT checks. + (*movhi_mips16, *movqi_mips16): Likewise. Use mips_output_move. + (movti): New expander. + (*movti, *movti_mips16): New insns. + (mfhilo_, *mfhilo_, *mfhilo__macc): Delete. + (mfhi_): New pattern. + (mthi_): Likewise. + * config/mips/predicates.md (fpr_operand): Delete. + (d_operand): New predicate. + 2008-06-09 Michael Meissner * config.gcc (i[34567]86-*-*): Put test in quotes to prevent diff --git a/gcc/config/mips/constraints.md b/gcc/config/mips/constraints.md index 53e0189ec94..a387489f204 100644 --- a/gcc/config/mips/constraints.md +++ b/gcc/config/mips/constraints.md @@ -29,14 +29,16 @@ (define_register_constraint "f" "TARGET_HARD_FLOAT ? FP_REGS : NO_REGS" "A floating-point register (if available).") -(define_register_constraint "h" "TARGET_BIG_ENDIAN ? MD0_REG : MD1_REG" - "The @code{hi} register.") +(define_register_constraint "h" "NO_REGS" + "Formerly the @code{hi} register. This constraint is no longer supported.") (define_register_constraint "l" "TARGET_BIG_ENDIAN ? MD1_REG : MD0_REG" - "The @code{lo} register.") + "The @code{lo} register. Use this register to store values that are + no bigger than a word.") (define_register_constraint "x" "MD_REGS" - "The @code{hi} and @code{lo} registers.") + "The concatenated @code{hi} and @code{lo} registers. Use this register + to store doubleword values.") (define_register_constraint "b" "ALL_REGS" "@internal") diff --git a/gcc/config/mips/mips.c b/gcc/config/mips/mips.c index 82009308349..eddb5a85389 100644 --- a/gcc/config/mips/mips.c +++ b/gcc/config/mips/mips.c @@ -2675,23 +2675,6 @@ mips_legitimize_move (enum machine_mode mode, rtx dest, rtx src) return true; } - /* Check for individual, fully-reloaded mflo and mfhi instructions. */ - if (GET_MODE_SIZE (mode) <= UNITS_PER_WORD - && REG_P (src) && MD_REG_P (REGNO (src)) - && REG_P (dest) && GP_REG_P (REGNO (dest))) - { - int other_regno = REGNO (src) == HI_REGNUM ? LO_REGNUM : HI_REGNUM; - if (GET_MODE_SIZE (mode) <= 4) - emit_insn (gen_mfhilo_si (gen_lowpart (SImode, dest), - gen_lowpart (SImode, src), - gen_rtx_REG (SImode, other_regno))); - else - emit_insn (gen_mfhilo_di (gen_lowpart (DImode, dest), - gen_lowpart (DImode, src), - gen_rtx_REG (DImode, other_regno))); - return true; - } - /* We need to deal with constants that would be legitimate immediate_operands but aren't legitimate move_operands. */ if (CONSTANT_P (src) && !move_operand (src, mode)) @@ -3488,7 +3471,7 @@ mips_subword (rtx op, bool high_p) mode = GET_MODE (op); if (mode == VOIDmode) - mode = DImode; + mode = TARGET_64BIT ? TImode : DImode; if (TARGET_BIG_ENDIAN ? !high_p : high_p) byte = UNITS_PER_WORD; @@ -3539,6 +3522,8 @@ mips_split_64bit_move_p (rtx dest, rtx src) void mips_split_doubleword_move (rtx dest, rtx src) { + rtx low_dest; + if (FP_REG_RTX_P (dest) || FP_REG_RTX_P (src)) { if (!TARGET_64BIT && GET_MODE (dest) == DImode) @@ -3552,12 +3537,27 @@ mips_split_doubleword_move (rtx dest, rtx src) else gcc_unreachable (); } + else if (REG_P (dest) && REGNO (dest) == MD_REG_FIRST) + { + low_dest = mips_subword (dest, false); + mips_emit_move (low_dest, mips_subword (src, false)); + if (TARGET_64BIT) + emit_insn (gen_mthidi_ti (dest, mips_subword (src, true), low_dest)); + else + emit_insn (gen_mthisi_di (dest, mips_subword (src, true), low_dest)); + } + else if (REG_P (src) && REGNO (src) == MD_REG_FIRST) + { + mips_emit_move (mips_subword (dest, false), mips_subword (src, false)); + if (TARGET_64BIT) + emit_insn (gen_mfhidi_ti (mips_subword (dest, true), src)); + else + emit_insn (gen_mfhisi_di (mips_subword (dest, true), src)); + } else { /* The operation can be split into two normal moves. Decide in which order to do them. */ - rtx low_dest; - low_dest = mips_subword (dest, false); if (REG_P (low_dest) && reg_overlap_mentioned_p (low_dest, src)) @@ -3600,8 +3600,9 @@ mips_output_move (rtx dest, rtx src) if (GP_REG_P (REGNO (dest))) return "move\t%0,%z1"; - if (MD_REG_P (REGNO (dest))) - return "mt%0\t%z1"; + /* Moves to HI are handled by special .md insns. */ + if (REGNO (dest) == LO_REGNUM) + return "mtlo\t%z1"; if (DSP_ACC_REG_P (REGNO (dest))) { @@ -3624,14 +3625,29 @@ mips_output_move (rtx dest, rtx src) } } if (dest_code == MEM) - return dbl_p ? "sd\t%z1,%0" : "sw\t%z1,%0"; + switch (GET_MODE_SIZE (mode)) + { + case 1: return "sb\t%z1,%0"; + case 2: return "sh\t%z1,%0"; + case 4: return "sw\t%z1,%0"; + case 8: return "sd\t%z1,%0"; + } } if (dest_code == REG && GP_REG_P (REGNO (dest))) { if (src_code == REG) { - /* Handled by separate patterns. */ - gcc_assert (!MD_REG_P (REGNO (src))); + /* Moves from HI are handled by special .md insns. */ + if (REGNO (src) == LO_REGNUM) + { + /* When generating VR4120 or VR4130 code, we use MACC and + DMACC instead of MFLO. This avoids both the normal + MIPS III HI/LO hazards and the errata related to + -mfix-vr4130. */ + if (ISA_HAS_MACCHI) + return dbl_p ? "dmacc\t%0,%.,%." : "macc\t%0,%.,%."; + return "mflo\t%0"; + } if (DSP_ACC_REG_P (REGNO (src))) { @@ -3658,7 +3674,13 @@ mips_output_move (rtx dest, rtx src) } if (src_code == MEM) - return dbl_p ? "ld\t%0,%1" : "lw\t%0,%1"; + switch (GET_MODE_SIZE (mode)) + { + case 1: return "lbu\t%0,%1"; + case 2: return "lhu\t%0,%1"; + case 4: return "lw\t%0,%1"; + case 8: return "ld\t%0,%1"; + } if (src_code == CONST_INT) { @@ -8954,13 +8976,30 @@ mips_hard_regno_mode_ok_p (unsigned int regno, enum machine_mode mode) if (ACC_REG_P (regno) && (INTEGRAL_MODE_P (mode) || ALL_FIXED_POINT_MODE_P (mode))) { - if (size <= UNITS_PER_WORD) - return true; + if (MD_REG_P (regno)) + { + /* After a multiplication or division, clobbering HI makes + the value of LO unpredictable, and vice versa. This means + that, for all interesting cases, HI and LO are effectively + a single register. + + We model this by requiring that any value that uses HI + also uses LO. */ + if (size <= UNITS_PER_WORD * 2) + return regno == (size <= UNITS_PER_WORD ? LO_REGNUM : MD_REG_FIRST); + } + else + { + /* DSP accumulators do not have the same restrictions as + HI and LO, so we can treat them as normal doubleword + registers. */ + if (size <= UNITS_PER_WORD) + return true; - if (size <= UNITS_PER_WORD * 2) - return (DSP_ACC_REG_P (regno) - ? ((regno - DSP_ACC_REG_FIRST) & 1) == 0 - : regno == MD_REG_FIRST); + if (size <= UNITS_PER_WORD * 2 + && ((regno - DSP_ACC_REG_FIRST) & 1) == 0) + return true; + } } if (ALL_COP_REG_P (regno)) diff --git a/gcc/config/mips/mips.md b/gcc/config/mips/mips.md index da7cb10f8b5..47441cd1c1e 100644 --- a/gcc/config/mips/mips.md +++ b/gcc/config/mips/mips.md @@ -44,9 +44,11 @@ (UNSPEC_LOAD_CALL 23) (UNSPEC_LOAD_GOT 24) (UNSPEC_GP 25) - (UNSPEC_MFHILO 26) - (UNSPEC_TLS_LDM 27) - (UNSPEC_TLS_GET_TP 28) + (UNSPEC_MFHI 26) + (UNSPEC_MTHI 27) + (UNSPEC_SET_HILO 28) + (UNSPEC_TLS_LDM 29) + (UNSPEC_TLS_GET_TP 30) (UNSPEC_MFHC1 31) (UNSPEC_MTHC1 32) (UNSPEC_CLEAR_HAZARD 33) @@ -484,6 +486,10 @@ ;; modes. (define_mode_iterator GPR2 [SI (DI "TARGET_64BIT")]) +;; This mode iterator allows :HILO to be used as the mode of the +;; concatenated HI and LO registers. +(define_mode_iterator HILO [(DI "!TARGET_64BIT") (TI "TARGET_64BIT")]) + ;; This mode iterator allows :P to be used for patterns that operate on ;; pointer-sized quantities. Exactly one of the two alternatives will match. (define_mode_iterator P [(SI "Pmode == SImode") (DI "Pmode == DImode")]) @@ -497,7 +503,7 @@ [DI DF (V2SF "TARGET_HARD_FLOAT && TARGET_PAIRED_SINGLE_FLOAT")]) ;; 128-bit modes for which we provide move patterns on 64-bit targets. -(define_mode_iterator MOVE128 [TF]) +(define_mode_iterator MOVE128 [TI TF]) ;; This mode iterator allows the QI and HI extension patterns to be ;; defined from the same template. @@ -613,6 +619,10 @@ ;; from the same template. (define_code_iterator any_shift [ashift ashiftrt lshiftrt]) +;; This code iterator allows unsigned and signed division to be generated +;; from the same template. +(define_code_iterator any_div [div udiv]) + ;; This code iterator allows all native floating-point comparisons to be ;; generated from the same template. (define_code_iterator fcond [unordered uneq unlt unle eq lt le]) @@ -631,6 +641,7 @@ ;; expands to an empty string when doing a signed operation and ;; "u" when doing an unsigned operation. (define_code_attr u [(sign_extend "") (zero_extend "u") + (div "") (udiv "u") (gt "") (gtu "u") (ge "") (geu "u") (lt "") (ltu "u") @@ -865,13 +876,10 @@ ;; simply adding a constant to a register. (define_split - [(set (match_operand:SI 0 "register_operand") + [(set (match_operand:SI 0 "d_operand") (plus:SI (match_dup 0) (match_operand:SI 1 "const_int_operand")))] "TARGET_MIPS16 && reload_completed && !TARGET_DEBUG_D_MODE - && REG_P (operands[0]) - && M16_REG_P (REGNO (operands[0])) - && GET_CODE (operands[1]) == CONST_INT && ((INTVAL (operands[1]) > 0x7f && INTVAL (operands[1]) <= 0x7f + 0x7f) || (INTVAL (operands[1]) < - 0x80 @@ -894,16 +902,11 @@ }) (define_split - [(set (match_operand:SI 0 "register_operand") - (plus:SI (match_operand:SI 1 "register_operand") + [(set (match_operand:SI 0 "d_operand") + (plus:SI (match_operand:SI 1 "d_operand") (match_operand:SI 2 "const_int_operand")))] "TARGET_MIPS16 && reload_completed && !TARGET_DEBUG_D_MODE - && REG_P (operands[0]) - && M16_REG_P (REGNO (operands[0])) - && REG_P (operands[1]) - && M16_REG_P (REGNO (operands[1])) && REGNO (operands[0]) != REGNO (operands[1]) - && GET_CODE (operands[2]) == CONST_INT && ((INTVAL (operands[2]) > 0x7 && INTVAL (operands[2]) <= 0x7 + 0x7f) || (INTVAL (operands[2]) < - 0x8 @@ -926,13 +929,10 @@ }) (define_split - [(set (match_operand:DI 0 "register_operand") + [(set (match_operand:DI 0 "d_operand") (plus:DI (match_dup 0) (match_operand:DI 1 "const_int_operand")))] "TARGET_MIPS16 && TARGET_64BIT && reload_completed && !TARGET_DEBUG_D_MODE - && REG_P (operands[0]) - && M16_REG_P (REGNO (operands[0])) - && GET_CODE (operands[1]) == CONST_INT && ((INTVAL (operands[1]) > 0xf && INTVAL (operands[1]) <= 0xf + 0xf) || (INTVAL (operands[1]) < - 0x10 @@ -955,16 +955,11 @@ }) (define_split - [(set (match_operand:DI 0 "register_operand") - (plus:DI (match_operand:DI 1 "register_operand") + [(set (match_operand:DI 0 "d_operand") + (plus:DI (match_operand:DI 1 "d_operand") (match_operand:DI 2 "const_int_operand")))] "TARGET_MIPS16 && TARGET_64BIT && reload_completed && !TARGET_DEBUG_D_MODE - && REG_P (operands[0]) - && M16_REG_P (REGNO (operands[0])) - && REG_P (operands[1]) - && M16_REG_P (REGNO (operands[1])) && REGNO (operands[0]) != REGNO (operands[1]) - && GET_CODE (operands[2]) == CONST_INT && ((INTVAL (operands[2]) > 0x7 && INTVAL (operands[2]) <= 0x7 + 0xf) || (INTVAL (operands[2]) < - 0x8 @@ -1175,8 +1170,7 @@ [(set (match_operand:SI 0 "register_operand" "=d,l") (mult:SI (match_operand:SI 1 "register_operand" "d,d") (match_operand:SI 2 "register_operand" "d,d"))) - (clobber (match_scratch:SI 3 "=h,h")) - (clobber (match_scratch:SI 4 "=l,X"))] + (clobber (match_scratch:SI 3 "=l,X"))] "ISA_HAS_MUL3" { if (which_alternative == 1) @@ -1195,30 +1189,26 @@ ;; Operand 0: LO ;; Operand 1: GPR (1st multiplication operand) ;; Operand 2: GPR (2nd multiplication operand) -;; Operand 3: HI -;; Operand 4: GPR (destination) +;; Operand 3: GPR (destination) (define_peephole2 [(parallel - [(set (match_operand:SI 0 "register_operand") - (mult:SI (match_operand:SI 1 "register_operand") - (match_operand:SI 2 "register_operand"))) - (clobber (match_operand:SI 3 "register_operand")) + [(set (match_operand:SI 0 "lo_operand") + (mult:SI (match_operand:SI 1 "d_operand") + (match_operand:SI 2 "d_operand"))) (clobber (scratch:SI))]) - (set (match_operand:SI 4 "register_operand") - (unspec [(match_dup 0) (match_dup 3)] UNSPEC_MFHILO))] + (set (match_operand:SI 3 "d_operand") + (match_dup 0))] "ISA_HAS_MUL3 && peep2_reg_dead_p (2, operands[0])" [(parallel - [(set (match_dup 4) + [(set (match_dup 3) (mult:SI (match_dup 1) (match_dup 2))) - (clobber (match_dup 3)) (clobber (match_dup 0))])]) (define_insn "mul3_internal" [(set (match_operand:GPR 0 "register_operand" "=l") (mult:GPR (match_operand:GPR 1 "register_operand" "d") - (match_operand:GPR 2 "register_operand" "d"))) - (clobber (match_scratch:GPR 3 "=h"))] + (match_operand:GPR 2 "register_operand" "d")))] "!TARGET_FIX_R4000" "mult\t%1,%2" [(set_attr "type" "imul") @@ -1228,8 +1218,7 @@ [(set (match_operand:GPR 0 "register_operand" "=d") (mult:GPR (match_operand:GPR 1 "register_operand" "d") (match_operand:GPR 2 "register_operand" "d"))) - (clobber (match_scratch:GPR 3 "=h")) - (clobber (match_scratch:GPR 4 "=l"))] + (clobber (match_scratch:GPR 3 "=l"))] "TARGET_FIX_R4000" "mult\t%1,%2\;mflo\t%0" [(set_attr "type" "imul") @@ -1243,16 +1232,13 @@ ;; Operand 0: LO ;; Operand 1: GPR (1st multiplication operand) ;; Operand 2: GPR (2nd multiplication operand) -;; Operand 3: HI -;; Operand 4: GPR (destination) +;; Operand 3: GPR (destination) (define_peephole2 - [(parallel - [(set (match_operand:SI 0 "register_operand") - (mult:SI (match_operand:SI 1 "register_operand") - (match_operand:SI 2 "register_operand"))) - (clobber (match_operand:SI 3 "register_operand"))]) - (set (match_operand:SI 4 "register_operand") - (unspec:SI [(match_dup 0) (match_dup 3)] UNSPEC_MFHILO))] + [(set (match_operand:SI 0 "lo_operand") + (mult:SI (match_operand:SI 1 "d_operand") + (match_operand:SI 2 "d_operand"))) + (set (match_operand:SI 3 "d_operand") + (match_dup 0))] "ISA_HAS_MACC && !ISA_HAS_MUL3" [(set (match_dup 0) (const_int 0)) @@ -1261,11 +1247,10 @@ (plus:SI (mult:SI (match_dup 1) (match_dup 2)) (match_dup 0))) - (set (match_dup 4) + (set (match_dup 3) (plus:SI (mult:SI (match_dup 1) (match_dup 2)) - (match_dup 0))) - (clobber (match_dup 3))])]) + (match_dup 0)))])]) ;; Multiply-accumulate patterns @@ -1284,9 +1269,8 @@ (plus:SI (mult:SI (match_operand:SI 1 "register_operand" "d,d,d") (match_operand:SI 2 "register_operand" "d,d,d")) (match_operand:SI 3 "register_operand" "0,l,*d"))) - (clobber (match_scratch:SI 4 "=h,h,h")) - (clobber (match_scratch:SI 5 "=X,3,l")) - (clobber (match_scratch:SI 6 "=X,X,&d"))] + (clobber (match_scratch:SI 4 "=X,3,l")) + (clobber (match_scratch:SI 5 "=X,X,&d"))] "(TARGET_MIPS3900 || GENERATE_MADD_MSUB) && !TARGET_MIPS16" @@ -1302,53 +1286,45 @@ (set_attr "mode" "SI") (set_attr "length" "4,4,8")]) -;; Split the above insn if we failed to get LO allocated. +;; Split *mul_acc_si if both the source and destination accumulator +;; values are GPRs. (define_split - [(set (match_operand:SI 0 "register_operand") - (plus:SI (mult:SI (match_operand:SI 1 "register_operand") - (match_operand:SI 2 "register_operand")) - (match_operand:SI 3 "register_operand"))) - (clobber (match_scratch:SI 4)) - (clobber (match_scratch:SI 5)) - (clobber (match_scratch:SI 6))] - "reload_completed && !TARGET_DEBUG_D_MODE - && GP_REG_P (true_regnum (operands[0])) - && GP_REG_P (true_regnum (operands[3]))" - [(parallel [(set (match_dup 6) + [(set (match_operand:SI 0 "d_operand") + (plus:SI (mult:SI (match_operand:SI 1 "d_operand") + (match_operand:SI 2 "d_operand")) + (match_operand:SI 3 "d_operand"))) + (clobber (match_operand:SI 4 "lo_operand")) + (clobber (match_operand:SI 5 "d_operand"))] + "reload_completed && !TARGET_DEBUG_D_MODE" + [(parallel [(set (match_dup 5) (mult:SI (match_dup 1) (match_dup 2))) - (clobber (match_dup 4)) - (clobber (match_dup 5))]) - (set (match_dup 0) (plus:SI (match_dup 6) (match_dup 3)))] + (clobber (match_dup 4))]) + (set (match_dup 0) (plus:SI (match_dup 5) (match_dup 3)))] "") -;; Splitter to copy result of MADD to a general register +;; Split *mul_acc_si if the destination accumulator value is in a GPR +;; and the source accumulator value is in LO. (define_split - [(set (match_operand:SI 0 "register_operand") - (plus:SI (mult:SI (match_operand:SI 1 "register_operand") - (match_operand:SI 2 "register_operand")) - (match_operand:SI 3 "register_operand"))) - (clobber (match_scratch:SI 4)) - (clobber (match_scratch:SI 5)) - (clobber (match_scratch:SI 6))] - "reload_completed && !TARGET_DEBUG_D_MODE - && GP_REG_P (true_regnum (operands[0])) - && true_regnum (operands[3]) == LO_REGNUM" + [(set (match_operand:SI 0 "d_operand") + (plus:SI (mult:SI (match_operand:SI 1 "d_operand") + (match_operand:SI 2 "d_operand")) + (match_operand:SI 3 "lo_operand"))) + (clobber (match_dup 3)) + (clobber (scratch:SI))] + "reload_completed && !TARGET_DEBUG_D_MODE" [(parallel [(set (match_dup 3) (plus:SI (mult:SI (match_dup 1) (match_dup 2)) (match_dup 3))) - (clobber (match_dup 4)) - (clobber (match_dup 5)) - (clobber (match_dup 6))]) - (set (match_dup 0) (unspec:SI [(match_dup 5) (match_dup 4)] UNSPEC_MFHILO))] - "") + (clobber (scratch:SI)) + (clobber (scratch:SI))]) + (set (match_dup 0) (match_dup 3))]) (define_insn "*macc" [(set (match_operand:SI 0 "register_operand" "=l,d") (plus:SI (mult:SI (match_operand:SI 1 "register_operand" "d,d") (match_operand:SI 2 "register_operand" "d,d")) (match_operand:SI 3 "register_operand" "0,l"))) - (clobber (match_scratch:SI 4 "=h,h")) - (clobber (match_scratch:SI 5 "=X,3"))] + (clobber (match_scratch:SI 4 "=X,3"))] "ISA_HAS_MACC" { if (which_alternative == 1) @@ -1369,8 +1345,7 @@ (minus:SI (match_operand:SI 1 "register_operand" "0,l") (mult:SI (match_operand:SI 2 "register_operand" "d,d") (match_operand:SI 3 "register_operand" "d,d")))) - (clobber (match_scratch:SI 4 "=h,h")) - (clobber (match_scratch:SI 5 "=X,1"))] + (clobber (match_scratch:SI 4 "=X,1"))] "ISA_HAS_MSAC" { if (which_alternative == 1) @@ -1389,21 +1364,19 @@ (minus:SI (match_operand:SI 1 "register_operand" "0,l") (mult:SI (match_operand:SI 2 "register_operand" "d,d") (match_operand:SI 3 "register_operand" "d,d")))) - (clobber (match_scratch:SI 4 "=h,h")) - (clobber (match_scratch:SI 5 "=X,1")) - (clobber (match_scratch:SI 6 "=d,d"))] + (clobber (match_scratch:SI 4 "=X,1")) + (clobber (match_scratch:SI 5 "=d,d"))] "ISA_HAS_MACC && !ISA_HAS_MSAC" "#" "&& reload_completed" - [(set (match_dup 6) + [(set (match_dup 5) (neg:SI (match_dup 3))) (parallel [(set (match_dup 0) (plus:SI (mult:SI (match_dup 2) - (match_dup 6)) + (match_dup 5)) (match_dup 1))) - (clobber (match_dup 4)) - (clobber (match_dup 5))])] + (clobber (match_dup 4))])] "" [(set_attr "type" "imadd") (set_attr "length" "8")]) @@ -1418,8 +1391,7 @@ (set (match_operand:SI 3 "register_operand" "=d") (plus:SI (mult:SI (match_dup 1) (match_dup 2)) - (match_dup 0))) - (clobber (match_scratch:SI 4 "=h"))] + (match_dup 0)))] "ISA_HAS_MACC && reload_completed" "macc\t%3,%1,%2" [(set_attr "type" "imadd") @@ -1433,8 +1405,7 @@ (set (match_operand:SI 3 "register_operand" "=d") (minus:SI (match_dup 0) (mult:SI (match_dup 1) - (match_dup 2)))) - (clobber (match_scratch:SI 4 "=h"))] + (match_dup 2))))] "ISA_HAS_MSAC && reload_completed" "msac\t%3,%1,%2" [(set_attr "type" "imadd") @@ -1445,23 +1416,19 @@ ;; ;; Operand 0: LO ;; Operand 1: macc/msac -;; Operand 2: HI -;; Operand 3: GPR (destination) +;; Operand 2: GPR (destination) (define_peephole2 [(parallel - [(set (match_operand:SI 0 "register_operand") + [(set (match_operand:SI 0 "lo_operand") (match_operand:SI 1 "macc_msac_operand")) - (clobber (match_operand:SI 2 "register_operand")) (clobber (scratch:SI))]) - (set (match_operand:SI 3 "register_operand") - (unspec:SI [(match_dup 0) (match_dup 2)] UNSPEC_MFHILO))] + (set (match_operand:SI 2 "d_operand") + (match_dup 0))] "" [(parallel [(set (match_dup 0) (match_dup 1)) - (set (match_dup 3) - (match_dup 1)) - (clobber (match_dup 2))])] - "") + (set (match_dup 2) + (match_dup 1))])]) ;; When we have a three-address multiplication instruction, it should ;; be faster to do a separate multiply and add, rather than moving @@ -1475,32 +1442,26 @@ ;; Operand 2: GPR (addend) ;; Operand 3: GPR (destination) ;; Operand 4: macc/msac -;; Operand 5: HI -;; Operand 6: new multiplication -;; Operand 7: new addition/subtraction +;; Operand 5: new multiplication +;; Operand 6: new addition/subtraction (define_peephole2 [(match_scratch:SI 0 "d") - (set (match_operand:SI 1 "register_operand") - (match_operand:SI 2 "register_operand")) + (set (match_operand:SI 1 "lo_operand") + (match_operand:SI 2 "d_operand")) (match_dup 0) (parallel - [(set (match_operand:SI 3 "register_operand") + [(set (match_operand:SI 3 "d_operand") (match_operand:SI 4 "macc_msac_operand")) - (clobber (match_operand:SI 5 "register_operand")) (clobber (match_dup 1))])] - "ISA_HAS_MUL3 - && true_regnum (operands[1]) == LO_REGNUM - && peep2_reg_dead_p (2, operands[1]) - && GP_REG_P (true_regnum (operands[3]))" + "ISA_HAS_MUL3 && peep2_reg_dead_p (2, operands[1])" [(parallel [(set (match_dup 0) - (match_dup 6)) - (clobber (match_dup 5)) + (match_dup 5)) (clobber (match_dup 1))]) (set (match_dup 3) - (match_dup 7))] + (match_dup 6))] { - operands[6] = XEXP (operands[4], GET_CODE (operands[4]) == PLUS ? 0 : 1); - operands[7] = gen_rtx_fmt_ee (GET_CODE (operands[4]), SImode, + operands[5] = XEXP (operands[4], GET_CODE (operands[4]) == PLUS ? 0 : 1); + operands[6] = gen_rtx_fmt_ee (GET_CODE (operands[4]), SImode, operands[2], operands[0]); }) @@ -1510,33 +1471,30 @@ ;; Operand 1: LO ;; Operand 2: GPR (addend) ;; Operand 3: macc/msac -;; Operand 4: HI -;; Operand 5: GPR (destination) -;; Operand 6: new multiplication -;; Operand 7: new addition/subtraction +;; Operand 4: GPR (destination) +;; Operand 5: new multiplication +;; Operand 6: new addition/subtraction (define_peephole2 [(match_scratch:SI 0 "d") - (set (match_operand:SI 1 "register_operand") - (match_operand:SI 2 "register_operand")) + (set (match_operand:SI 1 "lo_operand") + (match_operand:SI 2 "d_operand")) (match_dup 0) (parallel [(set (match_dup 1) (match_operand:SI 3 "macc_msac_operand")) - (clobber (match_operand:SI 4 "register_operand")) (clobber (scratch:SI))]) (match_dup 0) - (set (match_operand:SI 5 "register_operand") - (unspec:SI [(match_dup 1) (match_dup 4)] UNSPEC_MFHILO))] + (set (match_operand:SI 4 "d_operand") + (match_dup 1))] "ISA_HAS_MUL3 && peep2_reg_dead_p (3, operands[1])" [(parallel [(set (match_dup 0) - (match_dup 6)) - (clobber (match_dup 4)) + (match_dup 5)) (clobber (match_dup 1))]) - (set (match_dup 5) - (match_dup 7))] + (set (match_dup 4) + (match_dup 6))] { - operands[6] = XEXP (operands[4], GET_CODE (operands[4]) == PLUS ? 0 : 1); - operands[7] = gen_rtx_fmt_ee (GET_CODE (operands[4]), SImode, + operands[5] = XEXP (operands[3], GET_CODE (operands[3]) == PLUS ? 0 : 1); + operands[6] = gen_rtx_fmt_ee (GET_CODE (operands[3]), SImode, operands[2], operands[0]); }) @@ -1545,9 +1503,8 @@ (minus:SI (match_operand:SI 1 "register_operand" "0,l,*d") (mult:SI (match_operand:SI 2 "register_operand" "d,d,d") (match_operand:SI 3 "register_operand" "d,d,d")))) - (clobber (match_scratch:SI 4 "=h,h,h")) - (clobber (match_scratch:SI 5 "=X,1,l")) - (clobber (match_scratch:SI 6 "=X,X,&d"))] + (clobber (match_scratch:SI 4 "=X,1,l")) + (clobber (match_scratch:SI 5 "=X,X,&d"))] "GENERATE_MADD_MSUB" "@ msub\t%2,%3 @@ -1557,52 +1514,45 @@ (set_attr "mode" "SI") (set_attr "length" "4,8,8")]) -;; Split the above insn if we failed to get LO allocated. +;; Split *mul_sub_si if both the source and destination accumulator +;; values are GPRs. (define_split - [(set (match_operand:SI 0 "register_operand") - (minus:SI (match_operand:SI 1 "register_operand") - (mult:SI (match_operand:SI 2 "register_operand") - (match_operand:SI 3 "register_operand")))) - (clobber (match_scratch:SI 4)) - (clobber (match_scratch:SI 5)) - (clobber (match_scratch:SI 6))] - "reload_completed && !TARGET_DEBUG_D_MODE - && GP_REG_P (true_regnum (operands[0])) - && GP_REG_P (true_regnum (operands[1]))" - [(parallel [(set (match_dup 6) + [(set (match_operand:SI 0 "d_operand") + (minus:SI (match_operand:SI 1 "d_operand") + (mult:SI (match_operand:SI 2 "d_operand") + (match_operand:SI 3 "d_operand")))) + (clobber (match_operand:SI 4 "lo_operand")) + (clobber (match_operand:SI 5 "d_operand"))] + "reload_completed && !TARGET_DEBUG_D_MODE" + [(parallel [(set (match_dup 5) (mult:SI (match_dup 2) (match_dup 3))) - (clobber (match_dup 4)) - (clobber (match_dup 5))]) - (set (match_dup 0) (minus:SI (match_dup 1) (match_dup 6)))] + (clobber (match_dup 4))]) + (set (match_dup 0) (minus:SI (match_dup 1) (match_dup 5)))] "") -;; Splitter to copy result of MSUB to a general register +;; Split *mul_acc_si if the destination accumulator value is in a GPR +;; and the source accumulator value is in LO. (define_split - [(set (match_operand:SI 0 "register_operand") - (minus:SI (match_operand:SI 1 "register_operand") - (mult:SI (match_operand:SI 2 "register_operand") - (match_operand:SI 3 "register_operand")))) - (clobber (match_scratch:SI 4)) - (clobber (match_scratch:SI 5)) - (clobber (match_scratch:SI 6))] - "reload_completed && !TARGET_DEBUG_D_MODE - && GP_REG_P (true_regnum (operands[0])) - && true_regnum (operands[1]) == LO_REGNUM" + [(set (match_operand:SI 0 "d_operand") + (minus:SI (match_operand:SI 1 "lo_operand") + (mult:SI (match_operand:SI 2 "d_operand") + (match_operand:SI 3 "d_operand")))) + (clobber (match_dup 1)) + (clobber (scratch:SI))] + "reload_completed && !TARGET_DEBUG_D_MODE" [(parallel [(set (match_dup 1) (minus:SI (match_dup 1) (mult:SI (match_dup 2) (match_dup 3)))) - (clobber (match_dup 4)) - (clobber (match_dup 5)) - (clobber (match_dup 6))]) - (set (match_dup 0) (unspec:SI [(match_dup 5) (match_dup 4)] UNSPEC_MFHILO))] + (clobber (scratch:SI)) + (clobber (scratch:SI))]) + (set (match_dup 0) (match_dup 1))] "") (define_insn "*muls" - [(set (match_operand:SI 0 "register_operand" "=l,d") + [(set (match_operand:SI 0 "register_operand" "=l,d") (neg:SI (mult:SI (match_operand:SI 1 "register_operand" "d,d") (match_operand:SI 2 "register_operand" "d,d")))) - (clobber (match_scratch:SI 3 "=h,h")) - (clobber (match_scratch:SI 4 "=X,l"))] + (clobber (match_scratch:SI 3 "=X,l"))] "ISA_HAS_MULS" "@ muls\t$0,%1,%2 @@ -1610,31 +1560,23 @@ [(set_attr "type" "imul,imul3") (set_attr "mode" "SI")]) -;; ??? We could define a mulditi3 pattern when TARGET_64BIT. - (define_expand "mulsidi3" - [(parallel - [(set (match_operand:DI 0 "register_operand") - (mult:DI (any_extend:DI (match_operand:SI 1 "register_operand")) - (any_extend:DI (match_operand:SI 2 "register_operand")))) - (clobber (scratch:DI)) - (clobber (scratch:DI)) - (clobber (scratch:DI))])] + [(set (match_operand:DI 0 "register_operand") + (mult:DI (any_extend:DI (match_operand:SI 1 "register_operand")) + (any_extend:DI (match_operand:SI 2 "register_operand"))))] "!TARGET_64BIT || !TARGET_FIX_R4000" { - if (!TARGET_64BIT) - { - if (!TARGET_FIX_R4000) - emit_insn (gen_mulsidi3_32bit_internal (operands[0], operands[1], - operands[2])); - else - emit_insn (gen_mulsidi3_32bit_r4000 (operands[0], operands[1], - operands[2])); - DONE; - } + if (TARGET_64BIT) + emit_insn (gen_mulsidi3_64bit (operands[0], operands[1], operands[2])); + else if (TARGET_FIX_R4000) + emit_insn (gen_mulsidi3_32bit_r4000 (operands[0], operands[1], + operands[2])); + else + emit_insn (gen_mulsidi3_32bit (operands[0], operands[1], operands[2])); + DONE; }) -(define_insn "mulsidi3_32bit_internal" +(define_insn "mulsidi3_32bit" [(set (match_operand:DI 0 "register_operand" "=x") (mult:DI (any_extend:DI (match_operand:SI 1 "register_operand" "d")) (any_extend:DI (match_operand:SI 2 "register_operand" "d"))))] @@ -1649,42 +1591,35 @@ (any_extend:DI (match_operand:SI 2 "register_operand" "d")))) (clobber (match_scratch:DI 3 "=x"))] "!TARGET_64BIT && TARGET_FIX_R4000" - "mult\t%1,%2\;mflo\t%L0;mfhi\t%M0" + "mult\t%1,%2\;mflo\t%L0\;mfhi\t%M0" [(set_attr "type" "imul") (set_attr "mode" "SI") (set_attr "length" "12")]) -(define_insn_and_split "*mulsidi3_64bit" +(define_insn_and_split "mulsidi3_64bit" [(set (match_operand:DI 0 "register_operand" "=d") (mult:DI (any_extend:DI (match_operand:SI 1 "register_operand" "d")) (any_extend:DI (match_operand:SI 2 "register_operand" "d")))) - (clobber (match_scratch:DI 3 "=l")) - (clobber (match_scratch:DI 4 "=h")) - (clobber (match_scratch:DI 5 "=d"))] + (clobber (match_scratch:TI 3 "=x")) + (clobber (match_scratch:DI 4 "=d"))] "TARGET_64BIT && !TARGET_FIX_R4000" "#" "&& reload_completed" - [(parallel - [(set (match_dup 3) - (sign_extend:DI - (mult:SI (match_dup 1) - (match_dup 2)))) - (set (match_dup 4) - (ashiftrt:DI - (mult:DI (any_extend:DI (match_dup 1)) - (any_extend:DI (match_dup 2))) - (const_int 32)))]) - - ;; OP5 <- LO, OP0 <- HI - (set (match_dup 5) (unspec:DI [(match_dup 3) (match_dup 4)] UNSPEC_MFHILO)) - (set (match_dup 0) (unspec:DI [(match_dup 4) (match_dup 3)] UNSPEC_MFHILO)) - - ;; Zero-extend OP5. - (set (match_dup 5) - (ashift:DI (match_dup 5) + [(set (match_dup 3) + (unspec:TI [(mult:DI (any_extend:DI (match_dup 1)) + (any_extend:DI (match_dup 2)))] + UNSPEC_SET_HILO)) + + ;; OP4 <- LO, OP0 <- HI + (set (match_dup 4) (match_dup 5)) + (set (match_dup 0) (unspec:DI [(match_dup 3)] UNSPEC_MFHI)) + + ;; Zero-extend OP4. + (set (match_dup 4) + (ashift:DI (match_dup 4) (const_int 32))) - (set (match_dup 5) - (lshiftrt:DI (match_dup 5) + (set (match_dup 4) + (lshiftrt:DI (match_dup 4) (const_int 32))) ;; Shift OP0 into place. @@ -1695,24 +1630,21 @@ ;; OR the two halves together (set (match_dup 0) (ior:DI (match_dup 0) - (match_dup 5)))] - "" + (match_dup 4)))] + { operands[5] = gen_rtx_REG (DImode, LO_REGNUM); } [(set_attr "type" "imul") (set_attr "mode" "SI") (set_attr "length" "24")]) -(define_insn "*mulsidi3_64bit_parts" - [(set (match_operand:DI 0 "register_operand" "=l") - (sign_extend:DI - (mult:SI (match_operand:SI 2 "register_operand" "d") - (match_operand:SI 3 "register_operand" "d")))) - (set (match_operand:DI 1 "register_operand" "=h") - (ashiftrt:DI - (mult:DI (any_extend:DI (match_dup 2)) - (any_extend:DI (match_dup 3))) - (const_int 32)))] +(define_insn "mulsidi3_64bit_hilo" + [(set (match_operand:TI 0 "register_operand" "=x") + (unspec:TI + [(mult:DI + (any_extend:DI (match_operand:SI 1 "register_operand" "d")) + (any_extend:DI (match_operand:SI 2 "register_operand" "d")))] + UNSPEC_SET_HILO))] "TARGET_64BIT && !TARGET_FIX_R4000" - "mult\t%2,%3" + "mult\t%1,%2" [(set_attr "type" "imul") (set_attr "mode" "SI")]) @@ -1756,7 +1688,7 @@ (mult:DI (any_extend:DI (match_operand:SI 1 "register_operand")) (any_extend:DI (match_operand:SI 2 "register_operand"))) (const_int 32))))] - "ISA_HAS_MULHI || !TARGET_FIX_R4000" + "" { if (ISA_HAS_MULHI) emit_insn (gen_mulsi3_highpart_mulhi_internal (operands[0], @@ -1768,72 +1700,133 @@ DONE; }) -(define_insn "mulsi3_highpart_internal" - [(set (match_operand:SI 0 "register_operand" "=h") +(define_insn_and_split "mulsi3_highpart_internal" + [(set (match_operand:SI 0 "register_operand" "=d") (truncate:SI (lshiftrt:DI (mult:DI (any_extend:DI (match_operand:SI 1 "register_operand" "d")) (any_extend:DI (match_operand:SI 2 "register_operand" "d"))) (const_int 32)))) (clobber (match_scratch:SI 3 "=l"))] - "!ISA_HAS_MULHI && !TARGET_FIX_R4000" - "mult\t%1,%2" + "!ISA_HAS_MULHI" + { return TARGET_FIX_R4000 ? "mult\t%1,%2\n\tmfhi\t%0" : "#"; } + "&& reload_completed && !TARGET_FIX_R4000" + [(const_int 0)] +{ + rtx hilo; + + if (TARGET_64BIT) + { + hilo = gen_rtx_REG (TImode, MD_REG_FIRST); + emit_insn (gen_mulsidi3_64bit_hilo (hilo, operands[1], operands[2])); + emit_insn (gen_mfhisi_ti (operands[0], hilo)); + } + else + { + hilo = gen_rtx_REG (DImode, MD_REG_FIRST); + emit_insn (gen_mulsidi3_32bit (hilo, operands[1], operands[2])); + emit_insn (gen_mfhisi_di (operands[0], hilo)); + } + DONE; +} [(set_attr "type" "imul") - (set_attr "mode" "SI")]) + (set_attr "mode" "SI") + (set_attr "length" "8")]) (define_insn "mulsi3_highpart_mulhi_internal" - [(set (match_operand:SI 0 "register_operand" "=h,d") + [(set (match_operand:SI 0 "register_operand" "=d") (truncate:SI (lshiftrt:DI (mult:DI - (any_extend:DI (match_operand:SI 1 "register_operand" "d,d")) - (any_extend:DI (match_operand:SI 2 "register_operand" "d,d"))) + (any_extend:DI (match_operand:SI 1 "register_operand" "d")) + (any_extend:DI (match_operand:SI 2 "register_operand" "d"))) (const_int 32)))) - (clobber (match_scratch:SI 3 "=l,l")) - (clobber (match_scratch:SI 4 "=X,h"))] + (clobber (match_scratch:SI 3 "=l"))] "ISA_HAS_MULHI" - "@ - mult\t%1,%2 - mulhi\t%0,%1,%2" - [(set_attr "type" "imul,imul3") + "mulhi\t%0,%1,%2" + [(set_attr "type" "imul3") (set_attr "mode" "SI")]) (define_insn "*mulsi3_highpart_neg_mulhi_internal" - [(set (match_operand:SI 0 "register_operand" "=h,d") + [(set (match_operand:SI 0 "register_operand" "=d") (truncate:SI (lshiftrt:DI (neg:DI (mult:DI - (any_extend:DI (match_operand:SI 1 "register_operand" "d,d")) - (any_extend:DI (match_operand:SI 2 "register_operand" "d,d")))) + (any_extend:DI (match_operand:SI 1 "register_operand" "d")) + (any_extend:DI (match_operand:SI 2 "register_operand" "d")))) (const_int 32)))) - (clobber (match_scratch:SI 3 "=l,l")) - (clobber (match_scratch:SI 4 "=X,h"))] + (clobber (match_scratch:SI 3 "=l"))] "ISA_HAS_MULHI" - "@ - mulshi\t%.,%1,%2 - mulshi\t%0,%1,%2" - [(set_attr "type" "imul,imul3") + "mulshi\t%0,%1,%2" + [(set_attr "type" "imul3") (set_attr "mode" "SI")]) ;; Disable unsigned multiplication for -mfix-vr4120. This is for VR4120 ;; errata MD(0), which says that dmultu does not always produce the ;; correct result. -(define_insn "muldi3_highpart" - [(set (match_operand:DI 0 "register_operand" "=h") +(define_insn_and_split "muldi3_highpart" + [(set (match_operand:DI 0 "register_operand" "=d") (truncate:DI (lshiftrt:TI - (mult:TI - (any_extend:TI (match_operand:DI 1 "register_operand" "d")) - (any_extend:TI (match_operand:DI 2 "register_operand" "d"))) + (mult:TI (any_extend:TI (match_operand:DI 1 "register_operand" "d")) + (any_extend:TI (match_operand:DI 2 "register_operand" "d"))) (const_int 64)))) (clobber (match_scratch:DI 3 "=l"))] - "TARGET_64BIT && !TARGET_FIX_R4000 + "TARGET_64BIT && !( == ZERO_EXTEND && TARGET_FIX_VR4120)" + { return TARGET_FIX_R4000 ? "dmult\t%1,%2\n\tmfhi\t%0" : "#"; } + "&& reload_completed && !TARGET_FIX_R4000" + [(const_int 0)] +{ + rtx hilo; + + hilo = gen_rtx_REG (TImode, MD_REG_FIRST); + emit_insn (gen_mulditi3_internal (hilo, operands[1], operands[2])); + emit_insn (gen_mfhidi_ti (operands[0], hilo)); + DONE; +} + [(set_attr "type" "imul") + (set_attr "mode" "DI") + (set_attr "length" "8")]) + +(define_expand "mulditi3" + [(set (match_operand:TI 0 "register_operand") + (mult:TI (any_extend:TI (match_operand:DI 1 "register_operand")) + (any_extend:TI (match_operand:DI 2 "register_operand"))))] + "TARGET_64BIT && !( == ZERO_EXTEND && TARGET_FIX_VR4120)" +{ + if (TARGET_FIX_R4000) + emit_insn (gen_mulditi3_r4000 (operands[0], operands[1], operands[2])); + else + emit_insn (gen_mulditi3_internal (operands[0], operands[1], + operands[2])); + DONE; +}) + +(define_insn "mulditi3_internal" + [(set (match_operand:TI 0 "register_operand" "=x") + (mult:TI (any_extend:TI (match_operand:DI 1 "register_operand" "d")) + (any_extend:TI (match_operand:DI 2 "register_operand" "d"))))] + "TARGET_64BIT + && !TARGET_FIX_R4000 && !( == ZERO_EXTEND && TARGET_FIX_VR4120)" "dmult\t%1,%2" [(set_attr "type" "imul") (set_attr "mode" "DI")]) +(define_insn "mulditi3_r4000" + [(set (match_operand:TI 0 "register_operand" "=d") + (mult:TI (any_extend:TI (match_operand:DI 1 "register_operand" "d")) + (any_extend:TI (match_operand:DI 2 "register_operand" "d")))) + (clobber (match_scratch:TI 3 "=x"))] + "TARGET_64BIT + && TARGET_FIX_R4000 + && !( == ZERO_EXTEND && TARGET_FIX_VR4120)" + "dmult\t%1,%2\;mflo\t%L0\;mfhi\t%M0" + [(set_attr "type" "imul") + (set_attr "mode" "DI") + (set_attr "length" "12")]) + ;; The R4650 supports a 32-bit multiply/ 64-bit accumulate ;; instruction. The HI/LO registers are used as a 64-bit accumulator. @@ -1841,8 +1834,7 @@ [(set (match_operand:SI 0 "register_operand" "+l") (plus:SI (mult:SI (match_operand:SI 1 "register_operand" "d") (match_operand:SI 2 "register_operand" "d")) - (match_dup 0))) - (clobber (match_scratch:SI 3 "=h"))] + (match_dup 0)))] "TARGET_MAD" "mad\t%1,%2" [(set_attr "type" "imadd") @@ -2017,29 +2009,80 @@ ;; VR4120 errata MD(A1): signed division instructions do not work correctly ;; with negative operands. We use special libgcc functions instead. -(define_insn "divmod4" +(define_insn_and_split "divmod4" [(set (match_operand:GPR 0 "register_operand" "=l") (div:GPR (match_operand:GPR 1 "register_operand" "d") (match_operand:GPR 2 "register_operand" "d"))) - (set (match_operand:GPR 3 "register_operand" "=h") + (set (match_operand:GPR 3 "register_operand" "=d") (mod:GPR (match_dup 1) (match_dup 2)))] "!TARGET_FIX_VR4120" - { return mips_output_division ("div\t$0,%1,%2", operands); } - [(set_attr "type" "idiv") - (set_attr "mode" "")]) + "#" + "&& reload_completed" + [(const_int 0)] +{ + rtx hilo; + + if (TARGET_64BIT) + { + hilo = gen_rtx_REG (TImode, MD_REG_FIRST); + emit_insn (gen_divmod4_hilo_ti (hilo, operands[1], operands[2])); + emit_insn (gen_mfhi_ti (operands[3], hilo)); + } + else + { + hilo = gen_rtx_REG (DImode, MD_REG_FIRST); + emit_insn (gen_divmod4_hilo_di (hilo, operands[1], operands[2])); + emit_insn (gen_mfhi_di (operands[3], hilo)); + } + DONE; +} + [(set_attr "type" "idiv") + (set_attr "mode" "") + (set_attr "length" "8")]) -(define_insn "udivmod4" +(define_insn_and_split "udivmod4" [(set (match_operand:GPR 0 "register_operand" "=l") (udiv:GPR (match_operand:GPR 1 "register_operand" "d") (match_operand:GPR 2 "register_operand" "d"))) - (set (match_operand:GPR 3 "register_operand" "=h") + (set (match_operand:GPR 3 "register_operand" "=d") (umod:GPR (match_dup 1) (match_dup 2)))] "" - { return mips_output_division ("divu\t$0,%1,%2", operands); } + "#" + "reload_completed" + [(const_int 0)] +{ + rtx hilo; + + if (TARGET_64BIT) + { + hilo = gen_rtx_REG (TImode, MD_REG_FIRST); + emit_insn (gen_udivmod4_hilo_ti (hilo, operands[1], operands[2])); + emit_insn (gen_mfhi_ti (operands[3], hilo)); + } + else + { + hilo = gen_rtx_REG (DImode, MD_REG_FIRST); + emit_insn (gen_udivmod4_hilo_di (hilo, operands[1], operands[2])); + emit_insn (gen_mfhi_di (operands[3], hilo)); + } + DONE; +} + [(set_attr "type" "idiv") + (set_attr "mode" "") + (set_attr "length" "8")]) + +(define_insn "divmod4_hilo_" + [(set (match_operand:HILO 0 "register_operand" "=x") + (unspec:HILO + [(any_div:GPR (match_operand:GPR 1 "register_operand" "d") + (match_operand:GPR 2 "register_operand" "d"))] + UNSPEC_SET_HILO))] + "" + { return mips_output_division ("div\t%.,%1,%2", operands); } [(set_attr "type" "idiv") - (set_attr "mode" "")]) + (set_attr "mode" "")]) ;; ;; .................... @@ -3241,7 +3284,7 @@ ;; dsll32 op1,op1,0 ;; daddu op1,op1,op0 (define_peephole2 - [(set (match_operand:DI 1 "register_operand") + [(set (match_operand:DI 1 "d_operand") (high:DI (match_operand:DI 2 "absolute_symbolic_operand"))) (match_scratch:DI 0 "d")] "TARGET_EXPLICIT_RELOCS && ABI_HAS_64BIT_SYMBOLS" @@ -3294,8 +3337,8 @@ ;; ;; on MIPS16 targets. (define_split - [(set (match_operand:SI 0 "register_operand" "=d") - (high:SI (match_operand:SI 1 "absolute_symbolic_operand" "")))] + [(set (match_operand:SI 0 "d_operand") + (high:SI (match_operand:SI 1 "absolute_symbolic_operand")))] "TARGET_MIPS16 && reload_completed" [(set (match_dup 0) (match_dup 2)) (set (match_dup 0) (ashift:SI (match_dup 0) (const_int 16)))] @@ -3464,7 +3507,7 @@ && (register_operand (operands[0], DImode) || reg_or_0_operand (operands[1], DImode))" { return mips_output_move (operands[0], operands[1]); } - [(set_attr "type" "multi,multi,load,store,mthilo,mfhilo,mtc,load,mfc,store") + [(set_attr "type" "multi,multi,load,store,multi,multi,mtc,load,mfc,store") (set_attr "mode" "DI") (set_attr "length" "8,16,*,*,8,8,8,*,8,*")]) @@ -3475,7 +3518,7 @@ && (register_operand (operands[0], DImode) || reg_or_0_operand (operands[1], DImode))" { return mips_output_move (operands[0], operands[1]); } - [(set_attr "type" "multi,multi,load,store,mthilo,mfhilo,mtc,fpload,mfc,fpstore") + [(set_attr "type" "multi,multi,load,store,multi,multi,mtc,fpload,mfc,fpstore") (set_attr "mode" "DI") (set_attr "length" "8,16,*,*,8,8,8,*,8,*")]) @@ -3486,29 +3529,29 @@ && (register_operand (operands[0], DImode) || register_operand (operands[1], DImode))" { return mips_output_move (operands[0], operands[1]); } - [(set_attr "type" "multi,multi,multi,multi,multi,load,store,mfhilo") + [(set_attr "type" "multi,multi,multi,multi,multi,load,store,multi") (set_attr "mode" "DI") (set_attr "length" "8,8,8,8,12,*,*,8")]) (define_insn "*movdi_64bit" - [(set (match_operand:DI 0 "nonimmediate_operand" "=d,d,e,d,m,*f,*f,*d,*m,*x,*B*C*D,*B*C*D,*d,*m") - (match_operand:DI 1 "move_operand" "d,U,T,m,dJ,*d*J,*m,*f,*f,*J*d,*d,*m,*B*C*D,*B*C*D"))] + [(set (match_operand:DI 0 "nonimmediate_operand" "=d,d,e,d,m,*f,*f,*d,*m,*a,*d,*B*C*D,*B*C*D,*d,*m") + (match_operand:DI 1 "move_operand" "d,U,T,m,dJ,*d*J,*m,*f,*f,*J*d,*a,*d,*m,*B*C*D,*B*C*D"))] "TARGET_64BIT && !TARGET_MIPS16 && (register_operand (operands[0], DImode) || reg_or_0_operand (operands[1], DImode))" { return mips_output_move (operands[0], operands[1]); } - [(set_attr "type" "move,const,const,load,store,mtc,fpload,mfc,fpstore,mthilo,mtc,load,mfc,store") + [(set_attr "type" "move,const,const,load,store,mtc,fpload,mfc,fpstore,mthilo,mfhilo,mtc,load,mfc,store") (set_attr "mode" "DI") - (set_attr "length" "4,*,*,*,*,4,*,4,*,4,8,*,8,*")]) + (set_attr "length" "4,*,*,*,*,4,*,4,*,4,4,8,*,8,*")]) (define_insn "*movdi_64bit_mips16" - [(set (match_operand:DI 0 "nonimmediate_operand" "=d,y,d,d,d,d,d,d,m") - (match_operand:DI 1 "move_operand" "d,d,y,K,N,kf,U,m,d"))] + [(set (match_operand:DI 0 "nonimmediate_operand" "=d,y,d,d,d,d,d,d,m,*d") + (match_operand:DI 1 "move_operand" "d,d,y,K,N,kf,U,m,d,*a"))] "TARGET_64BIT && TARGET_MIPS16 && (register_operand (operands[0], DImode) || register_operand (operands[1], DImode))" { return mips_output_move (operands[0], operands[1]); } - [(set_attr "type" "move,move,move,arith,arith,load,const,load,store") + [(set_attr "type" "move,move,move,arith,arith,load,const,load,store,mfhilo") (set_attr "mode" "DI") (set_attr_alternative "length" [(const_int 4) @@ -3523,7 +3566,8 @@ (const_int 8) (const_string "*") (const_string "*") - (const_string "*")])]) + (const_string "*") + (const_int 4)])]) ;; On the mips16, we can split ld $r,N($r) into an add and a load, @@ -3531,14 +3575,11 @@ ;; load are 2 2 byte instructions. (define_split - [(set (match_operand:DI 0 "register_operand") + [(set (match_operand:DI 0 "d_operand") (mem:DI (plus:DI (match_dup 0) (match_operand:DI 1 "const_int_operand"))))] "TARGET_64BIT && TARGET_MIPS16 && reload_completed && !TARGET_DEBUG_D_MODE - && REG_P (operands[0]) - && M16_REG_P (REGNO (operands[0])) - && GET_CODE (operands[1]) == CONST_INT && ((INTVAL (operands[1]) < 0 && INTVAL (operands[1]) >= -0x10) || (INTVAL (operands[1]) >= 32 * 8 @@ -3589,7 +3630,7 @@ (define_insn "*movsi_internal" [(set (match_operand:SI 0 "nonimmediate_operand" "=d,d,e,d,m,*f,*f,*d,*m,*d,*z,*a,*d,*B*C*D,*B*C*D,*d,*m") - (match_operand:SI 1 "move_operand" "d,U,T,m,dJ,*d*J,*m,*f,*f,*z,*d,*J*d,*A,*d,*m,*B*C*D,*B*C*D"))] + (match_operand:SI 1 "move_operand" "d,U,T,m,dJ,*d*J,*m,*f,*f,*z,*d,*J*d,*a,*d,*m,*B*C*D,*B*C*D"))] "!TARGET_MIPS16 && (register_operand (operands[0], SImode) || reg_or_0_operand (operands[1], SImode))" @@ -3599,13 +3640,13 @@ (set_attr "length" "4,*,*,*,*,4,*,4,*,4,4,4,4,4,*,4,*")]) (define_insn "*movsi_mips16" - [(set (match_operand:SI 0 "nonimmediate_operand" "=d,y,d,d,d,d,d,d,m") - (match_operand:SI 1 "move_operand" "d,d,y,K,N,kf,U,m,d"))] + [(set (match_operand:SI 0 "nonimmediate_operand" "=d,y,d,d,d,d,d,d,m,*d") + (match_operand:SI 1 "move_operand" "d,d,y,K,N,kf,U,m,d,*a"))] "TARGET_MIPS16 && (register_operand (operands[0], SImode) || register_operand (operands[1], SImode))" { return mips_output_move (operands[0], operands[1]); } - [(set_attr "type" "move,move,move,arith,arith,load,const,load,store") + [(set_attr "type" "move,move,move,arith,arith,load,const,load,store,mfhilo") (set_attr "mode" "SI") (set_attr_alternative "length" [(const_int 4) @@ -3620,20 +3661,18 @@ (const_int 8) (const_string "*") (const_string "*") - (const_string "*")])]) + (const_string "*") + (const_int 4)])]) ;; On the mips16, we can split lw $r,N($r) into an add and a load, ;; when the original load is a 4 byte instruction but the add and the ;; load are 2 2 byte instructions. (define_split - [(set (match_operand:SI 0 "register_operand") + [(set (match_operand:SI 0 "d_operand") (mem:SI (plus:SI (match_dup 0) (match_operand:SI 1 "const_int_operand"))))] "TARGET_MIPS16 && reload_completed && !TARGET_DEBUG_D_MODE - && REG_P (operands[0]) - && M16_REG_P (REGNO (operands[0])) - && GET_CODE (operands[1]) == CONST_INT && ((INTVAL (operands[1]) < 0 && INTVAL (operands[1]) >= -0x80) || (INTVAL (operands[1]) >= 32 * 4 @@ -3669,12 +3708,9 @@ ;; instructions. (define_split - [(set (match_operand:SI 0 "register_operand") + [(set (match_operand:SI 0 "d_operand") (match_operand:SI 1 "const_int_operand"))] "TARGET_MIPS16 && reload_completed && !TARGET_DEBUG_D_MODE - && REG_P (operands[0]) - && M16_REG_P (REGNO (operands[0])) - && GET_CODE (operands[1]) == CONST_INT && INTVAL (operands[1]) >= 0x100 && INTVAL (operands[1]) <= 0xff + 0x7f" [(set (match_dup 0) (match_dup 1)) @@ -3797,36 +3833,24 @@ }) (define_insn "*movhi_internal" - [(set (match_operand:HI 0 "nonimmediate_operand" "=d,d,d,m,*x") - (match_operand:HI 1 "move_operand" "d,I,m,dJ,*d"))] + [(set (match_operand:HI 0 "nonimmediate_operand" "=d,d,d,m,*a,*d") + (match_operand:HI 1 "move_operand" "d,I,m,dJ,*d*J,*a"))] "!TARGET_MIPS16 && (register_operand (operands[0], HImode) || reg_or_0_operand (operands[1], HImode))" - "@ - move\t%0,%1 - li\t%0,%1 - lhu\t%0,%1 - sh\t%z1,%0 - mt%0\t%1" - [(set_attr "type" "move,arith,load,store,mthilo") + { return mips_output_move (operands[0], operands[1]); } + [(set_attr "type" "move,arith,load,store,mthilo,mfhilo") (set_attr "mode" "HI") - (set_attr "length" "4,4,*,*,4")]) + (set_attr "length" "4,4,*,*,4,4")]) (define_insn "*movhi_mips16" - [(set (match_operand:HI 0 "nonimmediate_operand" "=d,y,d,d,d,d,m") - (match_operand:HI 1 "move_operand" "d,d,y,K,N,m,d"))] + [(set (match_operand:HI 0 "nonimmediate_operand" "=d,y,d,d,d,d,m,*d") + (match_operand:HI 1 "move_operand" "d,d,y,K,N,m,d,*a"))] "TARGET_MIPS16 && (register_operand (operands[0], HImode) || register_operand (operands[1], HImode))" - "@ - move\t%0,%1 - move\t%0,%1 - move\t%0,%1 - li\t%0,%1 - # - lhu\t%0,%1 - sh\t%1,%0" - [(set_attr "type" "move,move,move,arith,arith,load,store") + { return mips_output_move (operands[0], operands[1]); } + [(set_attr "type" "move,move,move,arith,arith,load,store,mfhilo") (set_attr "mode" "HI") (set_attr_alternative "length" [(const_int 4) @@ -3839,6 +3863,7 @@ (const_int 8) (const_int 12)) (const_string "*") + (const_string "*") (const_string "*")])]) @@ -3847,13 +3872,10 @@ ;; load are 2 2 byte instructions. (define_split - [(set (match_operand:HI 0 "register_operand") + [(set (match_operand:HI 0 "d_operand") (mem:HI (plus:SI (match_dup 0) (match_operand:SI 1 "const_int_operand"))))] "TARGET_MIPS16 && reload_completed && !TARGET_DEBUG_D_MODE - && REG_P (operands[0]) - && M16_REG_P (REGNO (operands[0])) - && GET_CODE (operands[1]) == CONST_INT && ((INTVAL (operands[1]) < 0 && INTVAL (operands[1]) >= -0x80) || (INTVAL (operands[1]) >= 32 * 2 @@ -3901,51 +3923,36 @@ }) (define_insn "*movqi_internal" - [(set (match_operand:QI 0 "nonimmediate_operand" "=d,d,d,m,*x") - (match_operand:QI 1 "move_operand" "d,I,m,dJ,*d"))] + [(set (match_operand:QI 0 "nonimmediate_operand" "=d,d,d,m,*a,*d") + (match_operand:QI 1 "move_operand" "d,I,m,dJ,*d*J,*a"))] "!TARGET_MIPS16 && (register_operand (operands[0], QImode) || reg_or_0_operand (operands[1], QImode))" - "@ - move\t%0,%1 - li\t%0,%1 - lbu\t%0,%1 - sb\t%z1,%0 - mt%0\t%1" - [(set_attr "type" "move,arith,load,store,mthilo") + { return mips_output_move (operands[0], operands[1]); } + [(set_attr "type" "move,arith,load,store,mthilo,mfhilo") (set_attr "mode" "QI") - (set_attr "length" "4,4,*,*,4")]) + (set_attr "length" "4,4,*,*,4,4")]) (define_insn "*movqi_mips16" - [(set (match_operand:QI 0 "nonimmediate_operand" "=d,y,d,d,d,d,m") - (match_operand:QI 1 "move_operand" "d,d,y,K,N,m,d"))] + [(set (match_operand:QI 0 "nonimmediate_operand" "=d,y,d,d,d,d,m,*d") + (match_operand:QI 1 "move_operand" "d,d,y,K,N,m,d,*a"))] "TARGET_MIPS16 && (register_operand (operands[0], QImode) || register_operand (operands[1], QImode))" - "@ - move\t%0,%1 - move\t%0,%1 - move\t%0,%1 - li\t%0,%1 - # - lbu\t%0,%1 - sb\t%1,%0" - [(set_attr "type" "move,move,move,arith,arith,load,store") + { return mips_output_move (operands[0], operands[1]); } + [(set_attr "type" "move,move,move,arith,arith,load,store,mfhilo") (set_attr "mode" "QI") - (set_attr "length" "4,4,4,4,8,*,*")]) + (set_attr "length" "4,4,4,4,8,*,*,4")]) ;; On the mips16, we can split lb $r,N($r) into an add and a load, ;; when the original load is a 4 byte instruction but the add and the ;; load are 2 2 byte instructions. (define_split - [(set (match_operand:QI 0 "register_operand") + [(set (match_operand:QI 0 "d_operand") (mem:QI (plus:SI (match_dup 0) (match_operand:SI 1 "const_int_operand"))))] "TARGET_MIPS16 && reload_completed && !TARGET_DEBUG_D_MODE - && REG_P (operands[0]) - && M16_REG_P (REGNO (operands[0])) - && GET_CODE (operands[1]) == CONST_INT && ((INTVAL (operands[1]) < 0 && INTVAL (operands[1]) >= -0x80) || (INTVAL (operands[1]) >= 32 @@ -4065,6 +4072,39 @@ (set_attr "mode" "DF") (set_attr "length" "8,8,8,*,*")]) +;; 128-bit integer moves + +(define_expand "movti" + [(set (match_operand:TI 0) + (match_operand:TI 1))] + "TARGET_64BIT" +{ + if (mips_legitimize_move (TImode, operands[0], operands[1])) + DONE; +}) + +(define_insn "*movti" + [(set (match_operand:TI 0 "nonimmediate_operand" "=d,d,m,*a,*d") + (match_operand:TI 1 "move_operand" "di,m,dJ,*d*J,*a"))] + "TARGET_64BIT + && !TARGET_MIPS16 + && (register_operand (operands[0], TImode) + || reg_or_0_operand (operands[1], TImode))" + "#" + [(set_attr "type" "multi,load,store,multi,multi") + (set_attr "length" "8,*,*,8,8")]) + +(define_insn "*movti_mips16" + [(set (match_operand:TI 0 "nonimmediate_operand" "=d,y,d,d,d,d,m,*d") + (match_operand:TI 1 "move_operand" "d,d,y,K,N,m,d,*a"))] + "TARGET_64BIT + && TARGET_MIPS16 + && (register_operand (operands[0], TImode) + || register_operand (operands[1], TImode))" + "#" + [(set_attr "type" "multi,multi,multi,multi,multi,load,store,multi") + (set_attr "length" "8,8,8,12,16,*,*,8")]) + ;; 128-bit floating point moves (define_expand "movtf" @@ -4123,7 +4163,7 @@ ;; When generating mips16 code, split moves of negative constants into ;; a positive "li" followed by a negation. (define_split - [(set (match_operand 0 "register_operand") + [(set (match_operand 0 "d_operand") (match_operand 1 "const_int_operand"))] "TARGET_MIPS16 && reload_completed && INTVAL (operands[1]) < 0" [(set (match_dup 2) @@ -4172,44 +4212,33 @@ (set_attr "mode" "SF") (set_attr "length" "4,8,*,*,*,8,8,8,*,*")]) -;; The HI and LO registers are not truly independent. If we move an mthi -;; instruction before an mflo instruction, it will make the result of the -;; mflo unpredictable. The same goes for mtlo and mfhi. -;; -;; We cope with this by making the mflo and mfhi patterns use both HI and LO. -;; Operand 1 is the register we want, operand 2 is the other one. +;; Extract the high part of a HI/LO value. See mips_hard_regno_mode_ok_p +;; for the reason why we can't just use (reg:GPR HI_REGNUM). ;; -;; When generating VR4120 or VR4130 code, we use macc{,hi} and -;; dmacc{,hi} instead of mfhi and mflo. This avoids both the normal -;; MIPS III hi/lo hazards and the errata related to -mfix-vr4130. - -(define_expand "mfhilo_" - [(set (match_operand:GPR 0 "register_operand") - (unspec:GPR [(match_operand:GPR 1 "register_operand") - (match_operand:GPR 2 "register_operand")] - UNSPEC_MFHILO))]) - -(define_insn "*mfhilo_" - [(set (match_operand:GPR 0 "register_operand" "=d,d") - (unspec:GPR [(match_operand:GPR 1 "register_operand" "h,l") - (match_operand:GPR 2 "register_operand" "l,h")] - UNSPEC_MFHILO))] - "!ISA_HAS_MACCHI" - "mf%1\t%0" +;; When generating VR4120 or VR4130 code, we use MACCHI and DMACCHI +;; instead of MFHI. This avoids both the normal MIPS III hi/lo hazards +;; and the errata related to -mfix-vr4130. +(define_insn "mfhi_" + [(set (match_operand:GPR 0 "register_operand" "=d") + (unspec:GPR [(match_operand:HILO 1 "register_operand" "x")] + UNSPEC_MFHI))] + "" + { return ISA_HAS_MACCHI ? "macchi\t%0,%.,%." : "mfhi\t%0"; } [(set_attr "type" "mfhilo") - (set_attr "mode" "")]) + (set_attr "mode" "")]) -(define_insn "*mfhilo__macc" - [(set (match_operand:GPR 0 "register_operand" "=d,d") - (unspec:GPR [(match_operand:GPR 1 "register_operand" "h,l") - (match_operand:GPR 2 "register_operand" "l,h")] - UNSPEC_MFHILO))] - "ISA_HAS_MACCHI" - "@ - macchi\t%0,%.,%. - macc\t%0,%.,%." - [(set_attr "type" "mfhilo") - (set_attr "mode" "")]) +;; Set the high part of a HI/LO value, given that the low part has +;; already been set. See mips_hard_regno_mode_ok_p for the reason +;; why we can't just use (reg:GPR HI_REGNUM). +(define_insn "mthi_" + [(set (match_operand:HILO 0 "register_operand" "=x") + (unspec:HILO [(match_operand:GPR 1 "reg_or_0_operand" "dJ") + (match_operand:GPR 2 "register_operand" "l")] + UNSPEC_MTHI))] + "" + "mthi\t%z1" + [(set_attr "type" "mthilo") + (set_attr "mode" "SI")]) ;; Emit a doubleword move in which exactly one of the operands is ;; a floating-point register. We can't just emit two normal moves @@ -5120,11 +5149,10 @@ ;; On the mips16, we can split a 4 byte shift into 2 2 byte shifts. (define_split - [(set (match_operand:GPR 0 "register_operand") - (any_shift:GPR (match_operand:GPR 1 "register_operand") + [(set (match_operand:GPR 0 "d_operand") + (any_shift:GPR (match_operand:GPR 1 "d_operand") (match_operand:GPR 2 "const_int_operand")))] "TARGET_MIPS16 && reload_completed && !TARGET_DEBUG_D_MODE - && GET_CODE (operands[2]) == CONST_INT && INTVAL (operands[2]) > 8 && INTVAL (operands[2]) <= 16" [(set (match_dup 0) (any_shift:GPR (match_dup 1) (const_int 8))) diff --git a/gcc/config/mips/predicates.md b/gcc/config/mips/predicates.md index 6c533e5e80f..73db0274936 100644 --- a/gcc/config/mips/predicates.md +++ b/gcc/config/mips/predicates.md @@ -76,9 +76,11 @@ (ior (match_test "op == CONST0_RTX (GET_MODE (op))") (match_test "op == CONST1_RTX (GET_MODE (op))")))) -(define_predicate "fpr_operand" +(define_predicate "d_operand" (and (match_code "reg") - (match_test "FP_REG_P (REGNO (op))"))) + (match_test "TARGET_MIPS16 + ? M16_REG_P (REGNO (op)) + : GP_REG_P (REGNO (op))"))) (define_predicate "lo_operand" (and (match_code "reg") diff --git a/gcc/doc/md.texi b/gcc/doc/md.texi index ba4b6ac95e3..8884d71a291 100644 --- a/gcc/doc/md.texi +++ b/gcc/doc/md.texi @@ -2469,13 +2469,15 @@ generating MIPS16 code. A floating-point register (if available). @item h -The @code{hi} register. +Formerly the @code{hi} register. This constraint is no longer supported. @item l -The @code{lo} register. +The @code{lo} register. Use this register to store values that are +no bigger than a word. @item x -The @code{hi} and @code{lo} registers. +The concatenated @code{hi} and @code{lo} registers. Use this register +to store doubleword values. @item c A register suitable for use in an indirect jump. This will always be diff --git a/gcc/longlong.h b/gcc/longlong.h index 6c24564bd3e..38b4c6fb221 100644 --- a/gcc/longlong.h +++ b/gcc/longlong.h @@ -623,12 +623,12 @@ UDItype __umulsidi3 (USItype, USItype); #endif /* __m88000__ */ #if defined (__mips__) && W_TYPE_SIZE == 32 -#define umul_ppmm(w1, w0, u, v) \ - __asm__ ("multu %2,%3" \ - : "=l" ((USItype) (w0)), \ - "=h" ((USItype) (w1)) \ - : "d" ((USItype) (u)), \ - "d" ((USItype) (v))) +#define umul_ppmm(w1, w0, u, v) \ + do { \ + UDItype __x = (UDItype) (USItype) (u) * (USItype) (v); \ + (w1) = (USItype) (__x >> 32); \ + (w0) = (USItype) (__x); \ + } while (0) #define UMUL_TIME 10 #define UDIV_TIME 100 diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index 4f7a5866505..824355caf63 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,26 @@ +2008-06-09 Richard Sandiford + + * gcc.dg/torture/mips-hilo-1.c: Delete. + * gcc.target/mips/pr35232.c: Likewise. + * gcc.target/mips/fix-vr4130-1.c: Use modulus to create an mfhi. + * gcc.target/mips/fix-vr4130-3.c: Likewise. + * gcc.target/mips/int-moves-1.c: New test. + * gcc.target/mips/int-moves-2.c: Likewise. + * gcc.target/mips/fix-r4000-1.c: Likewise. + * gcc.target/mips/fix-r4000-2.c: Likewise. + * gcc.target/mips/fix-r4000-3.c: Likewise. + * gcc.target/mips/fix-r4000-4.c: Likewise. + * gcc.target/mips/fix-r4000-5.c: Likewise. + * gcc.target/mips/fix-r4000-6.c: Likewise. + * gcc.target/mips/fix-r4000-7.c: Likewise. + * gcc.target/mips/fix-r4000-8.c: Likewise. + * gcc.target/mips/fix-r4000-9.c: Likewise. + * gcc.target/mips/fix-r4000-10.c: Likewise. + * gcc.target/mips/fix-r4000-11.c: Likewise. + * gcc.target/mips/fix-r4000-12.c: Likewise. + * gcc.target/mips/timode-1.c: Likewise. + * gcc.target/mips/timode-2.c: Likewise. + 2008-06-09 Eric Botcazou * gnat.dg/specs/pack3.ads: New test. diff --git a/gcc/testsuite/gcc.dg/torture/mips-hilo-1.c b/gcc/testsuite/gcc.dg/torture/mips-hilo-1.c deleted file mode 100644 index b7289666b7c..00000000000 --- a/gcc/testsuite/gcc.dg/torture/mips-hilo-1.c +++ /dev/null @@ -1,73 +0,0 @@ -/* f1 checks that an mtlo is not moved before an mfhi. f2 does the same - for an mthi and an mflo. */ -/* { dg-do run { target mips*-*-* } } */ -/* { dg-options "-mtune=rm7000" } */ - -extern void abort (void); -extern void exit (int); - -#define DECLARE(TYPE) \ - TYPE __attribute__ ((noinline)) __attribute__ ((nomips16)) \ - f1##TYPE (TYPE x1, TYPE x2, TYPE x3) \ - { \ - TYPE t1, t2; \ - \ - asm ("mult\t%1,%2" : "=h" (t1) : "d" (x1), "d" (x2) : "lo"); \ - asm ("mflo\t%0" : "=r" (t2) : "l" (x3) : "hi"); \ - return t1 + t2; \ - } \ - \ - TYPE __attribute__ ((noinline)) __attribute__ ((nomips16)) \ - f2##TYPE (TYPE x1, TYPE x2, TYPE x3) \ - { \ - TYPE t1, t2; \ - \ - asm ("mult\t%1,%2" : "=l" (t1) : "d" (x1), "d" (x2) : "hi"); \ - asm ("mfhi\t%0" : "=r" (t2) : "h" (x3) : "lo"); \ - return t1 + t2; \ - } - -#define TEST(TYPE) \ - if (f1##TYPE (1, 2, 10) != 10) \ - abort (); \ - if (f2##TYPE (1, 2, 40) != 42) \ - abort () - -typedef char c; -typedef signed char sc; -typedef unsigned char uc; -typedef short s; -typedef unsigned short us; -typedef int i; -typedef unsigned int ui; -typedef long long ll; -typedef unsigned long long ull; - -DECLARE (c) -DECLARE (sc) -DECLARE (uc) -DECLARE (s) -DECLARE (us) -DECLARE (i) -DECLARE (ui) -#if defined (__mips64) -DECLARE (ll) -DECLARE (ull) -#endif - -int -main () -{ - TEST (c); - TEST (sc); - TEST (uc); - TEST (s); - TEST (us); - TEST (i); - TEST (ui); -#if defined (__mips64) - TEST (ll); - TEST (ull); -#endif - exit (0); -} diff --git a/gcc/testsuite/gcc.target/mips/fix-r4000-1.c b/gcc/testsuite/gcc.target/mips/fix-r4000-1.c new file mode 100644 index 00000000000..adb32a2eed1 --- /dev/null +++ b/gcc/testsuite/gcc.target/mips/fix-r4000-1.c @@ -0,0 +1,6 @@ +/* { dg-mips-options "-march=r4000 -mfix-r4000 -O2 -dp" } */ +typedef int int32_t; +typedef int uint32_t; +int32_t foo (int32_t x, int32_t y) { return x * y; } +uint32_t bar (uint32_t x, uint32_t y) { return x * y; } +/* { dg-final { scan-assembler-times "[concat {\tmult\t\$[45],\$[45][^\n]+mulsi3_r4000[^\n]+\n\tmflo\t\$2\n}]" 2 } } */ diff --git a/gcc/testsuite/gcc.target/mips/fix-r4000-10.c b/gcc/testsuite/gcc.target/mips/fix-r4000-10.c new file mode 100644 index 00000000000..3c217b984cd --- /dev/null +++ b/gcc/testsuite/gcc.target/mips/fix-r4000-10.c @@ -0,0 +1,8 @@ +/* ??? At the moment, lower-subreg.c decomposes the copy of the multiplication + result to $2, which prevents the register allocators from storing the + multiplication result in $2. */ +/* { dg-mips-options "-mips3 -mfix-r4000 -mgp64 -O2 -fno-split-wide-types -dp -EL" } */ +typedef unsigned long long uint64_t; +typedef unsigned int uint128_t __attribute__((mode(TI))); +uint128_t foo (uint64_t x, uint64_t y) { return (uint128_t) x * y; } +/* { dg-final { scan-assembler "[concat {\tdmultu\t\$[45],\$[45][^\n]+umulditi3_r4000[^\n]+\n\tmflo\t\$2\n\tmfhi\t\$3\n}]" } } */ diff --git a/gcc/testsuite/gcc.target/mips/fix-r4000-11.c b/gcc/testsuite/gcc.target/mips/fix-r4000-11.c new file mode 100644 index 00000000000..528a30bbddd --- /dev/null +++ b/gcc/testsuite/gcc.target/mips/fix-r4000-11.c @@ -0,0 +1,4 @@ +/* { dg-mips-options "-march=r4000 -mfix-r4000 -mgp64 -O2 -dp" } */ +typedef long long int64_t; +int64_t foo (int64_t x) { return x / 11993; } +/* { dg-final { scan-assembler "[concat {\tdmult\t\$4,\$[0-9]+[^\n]+smuldi3_highpart[^\n]+\n\tmfhi\t\$[0-9]+\n}]" } } */ diff --git a/gcc/testsuite/gcc.target/mips/fix-r4000-12.c b/gcc/testsuite/gcc.target/mips/fix-r4000-12.c new file mode 100644 index 00000000000..f03a7a06147 --- /dev/null +++ b/gcc/testsuite/gcc.target/mips/fix-r4000-12.c @@ -0,0 +1,4 @@ +/* { dg-mips-options "-march=r4000 -mfix-r4000 -mgp64 -O2 -dp" } */ +typedef unsigned long long uint64_t; +uint64_t foo (uint64_t x) { return x / 11993; } +/* { dg-final { scan-assembler "[concat {\tdmultu\t\$4,\$[0-9]+[^\n]+umuldi3_highpart[^\n]+\n\tmfhi\t\$[0-9]+\n}]" } } */ diff --git a/gcc/testsuite/gcc.target/mips/fix-r4000-2.c b/gcc/testsuite/gcc.target/mips/fix-r4000-2.c new file mode 100644 index 00000000000..038dd5ecd49 --- /dev/null +++ b/gcc/testsuite/gcc.target/mips/fix-r4000-2.c @@ -0,0 +1,7 @@ +/* { dg-mips-options "-mips1 -mfix-r4000 -O2 -dp -EB" } */ +typedef int int32_t; +typedef long long int64_t; +int32_t foo (int32_t x, int32_t y) { return ((int64_t) x * y) >> 32; } +/* ??? A highpart pattern would be a better choice, but we currently + don't use them. */ +/* { dg-final { scan-assembler "[concat {\tmult\t\$[45],\$[45][^\n]+mulsidi3_32bit_r4000[^\n]+\n\tmflo\t\$3\n\tmfhi\t\$2\n}]" } } */ diff --git a/gcc/testsuite/gcc.target/mips/fix-r4000-3.c b/gcc/testsuite/gcc.target/mips/fix-r4000-3.c new file mode 100644 index 00000000000..43189430496 --- /dev/null +++ b/gcc/testsuite/gcc.target/mips/fix-r4000-3.c @@ -0,0 +1,7 @@ +/* { dg-mips-options "-mips1 -mfix-r4000 -O2 -dp -EB" } */ +typedef unsigned int uint32_t; +typedef unsigned long long uint64_t; +uint32_t foo (uint32_t x, uint32_t y) { return ((uint64_t) x * y) >> 32; } +/* ??? A highpart pattern would be a better choice, but we currently + don't use them. */ +/* { dg-final { scan-assembler "[concat {\tmultu\t\$[45],\$[45][^\n]+umulsidi3_32bit_r4000[^\n]+\n\tmflo\t\$3\n\tmfhi\t\$2\n}]" } } */ diff --git a/gcc/testsuite/gcc.target/mips/fix-r4000-4.c b/gcc/testsuite/gcc.target/mips/fix-r4000-4.c new file mode 100644 index 00000000000..7acb2374d5a --- /dev/null +++ b/gcc/testsuite/gcc.target/mips/fix-r4000-4.c @@ -0,0 +1,8 @@ +/* ??? At the moment, lower-subreg.c decomposes the copy of the multiplication + result to $2, which prevents the register allocators from storing the + multiplication result in $2. */ +/* { dg-mips-options "-mips1 -mfix-r4000 -O2 -fno-split-wide-types -dp -EL" } */ +typedef int int32_t; +typedef long long int64_t; +int64_t foo (int32_t x, int32_t y) { return (int64_t) x * y; } +/* { dg-final { scan-assembler "[concat {\tmult\t\$[45],\$[45][^\n]+mulsidi3_32bit_r4000[^\n]+\n\tmflo\t\$2\n\tmfhi\t\$3\n}]" } } */ diff --git a/gcc/testsuite/gcc.target/mips/fix-r4000-5.c b/gcc/testsuite/gcc.target/mips/fix-r4000-5.c new file mode 100644 index 00000000000..86ab8a26eea --- /dev/null +++ b/gcc/testsuite/gcc.target/mips/fix-r4000-5.c @@ -0,0 +1,8 @@ +/* ??? At the moment, lower-subreg.c decomposes the copy of the multiplication + result to $2, which prevents the register allocators from storing the + multiplication result in $2. */ +/* { dg-mips-options "-mips1 -mfix-r4000 -O2 -fno-split-wide-types -dp -EL" } */ +typedef unsigned int uint32_t; +typedef unsigned long long uint64_t; +uint64_t foo (uint32_t x, uint32_t y) { return (uint64_t) x * y; } +/* { dg-final { scan-assembler "[concat {\tmultu\t\$[45],\$[45][^\n]+umulsidi3_32bit_r4000[^\n]+\n\tmflo\t\$2\n\tmfhi\t\$3\n}]" } } */ diff --git a/gcc/testsuite/gcc.target/mips/fix-r4000-6.c b/gcc/testsuite/gcc.target/mips/fix-r4000-6.c new file mode 100644 index 00000000000..2c75deddeca --- /dev/null +++ b/gcc/testsuite/gcc.target/mips/fix-r4000-6.c @@ -0,0 +1,6 @@ +/* { dg-mips-options "-march=r4000 -mfix-r4000 -mgp64 -O2 -dp" } */ +typedef long long int64_t; +typedef unsigned long long uint64_t; +int64_t foo (int64_t x, int64_t y) { return x * y; } +uint64_t bar (uint64_t x, uint64_t y) { return x * y; } +/* { dg-final { scan-assembler-times "[concat {\tdmult\t\$[45],\$[45][^\n]+muldi3_r4000[^\n]+\n\tmflo\t\$2\n}]" 2 } } */ diff --git a/gcc/testsuite/gcc.target/mips/fix-r4000-7.c b/gcc/testsuite/gcc.target/mips/fix-r4000-7.c new file mode 100644 index 00000000000..e7b9251ceb4 --- /dev/null +++ b/gcc/testsuite/gcc.target/mips/fix-r4000-7.c @@ -0,0 +1,7 @@ +/* { dg-mips-options "-march=r4000 -mfix-r4000 -O2 -mgp64 -dp -EB" } */ +typedef long long int64_t; +typedef int int128_t __attribute__((mode(TI))); +int64_t foo (int64_t x, int64_t y) { return ((int128_t) x * y) >> 64; } +/* ??? A highpart pattern would be a better choice, but we currently + don't use them. */ +/* { dg-final { scan-assembler "[concat {\tdmult\t\$[45],\$[45][^\n]+mulditi3[^\n]+\n\tmflo\t\$3\n\tmfhi\t\$2\n}]" } } */ diff --git a/gcc/testsuite/gcc.target/mips/fix-r4000-8.c b/gcc/testsuite/gcc.target/mips/fix-r4000-8.c new file mode 100644 index 00000000000..5089b99e08d --- /dev/null +++ b/gcc/testsuite/gcc.target/mips/fix-r4000-8.c @@ -0,0 +1,7 @@ +/* { dg-mips-options "-march=r4000 -mfix-r4000 -O2 -mgp64 -dp -EB" } */ +typedef unsigned long long uint64_t; +typedef unsigned int uint128_t __attribute__((mode(TI))); +uint64_t foo (uint64_t x, uint64_t y) { return ((uint128_t) x * y) >> 64; } +/* ??? A highpart pattern would be a better choice, but we currently + don't use them. */ +/* { dg-final { scan-assembler "[concat {\tdmultu\t\$[45],\$[45][^\n]+umulditi3[^\n]+\n\tmflo\t\$3\n\tmfhi\t\$2\n}]" } } */ diff --git a/gcc/testsuite/gcc.target/mips/fix-r4000-9.c b/gcc/testsuite/gcc.target/mips/fix-r4000-9.c new file mode 100644 index 00000000000..55183396f07 --- /dev/null +++ b/gcc/testsuite/gcc.target/mips/fix-r4000-9.c @@ -0,0 +1,8 @@ +/* ??? At the moment, lower-subreg.c decomposes the copy of the multiplication + result to $2, which prevents the register allocators from storing the + multiplication result in $2. */ +/* { dg-mips-options "-mips3 -mfix-r4000 -mgp64 -O2 -fno-split-wide-types -dp -EL" } */ +typedef long long int64_t; +typedef int int128_t __attribute__((mode(TI))); +int128_t foo (int64_t x, int64_t y) { return (int128_t) x * y; } +/* { dg-final { scan-assembler "[concat {\tdmult\t\$[45],\$[45][^\n]+mulditi3_r4000[^\n]+\n\tmflo\t\$2\n\tmfhi\t\$3\n}]" } } */ diff --git a/gcc/testsuite/gcc.target/mips/fix-vr4130-1.c b/gcc/testsuite/gcc.target/mips/fix-vr4130-1.c index 27ef5ef06eb..48840accd62 100644 --- a/gcc/testsuite/gcc.target/mips/fix-vr4130-1.c +++ b/gcc/testsuite/gcc.target/mips/fix-vr4130-1.c @@ -1,4 +1,8 @@ /* { dg-do compile } */ /* { dg-mips-options "-march=vr4130 -mfix-vr4130" } */ -NOMIPS16 int foo (void) { int r; asm ("# foo" : "=h" (r)); return r; } +NOMIPS16 unsigned int +foo (unsigned int x, unsigned int y) +{ + return x % y; +} /* { dg-final { scan-assembler "\tmacchi\t" } } */ diff --git a/gcc/testsuite/gcc.target/mips/fix-vr4130-3.c b/gcc/testsuite/gcc.target/mips/fix-vr4130-3.c index 2f4f48689f6..5cc32cafe43 100644 --- a/gcc/testsuite/gcc.target/mips/fix-vr4130-3.c +++ b/gcc/testsuite/gcc.target/mips/fix-vr4130-3.c @@ -1,10 +1,8 @@ /* { dg-do compile } */ /* { dg-mips-options "-march=vr4130 -mgp64 -mfix-vr4130" } */ -NOMIPS16 long long -foo (void) +NOMIPS16 unsigned long long +foo (unsigned long long x, unsigned long long y) { - long long r; - asm ("# foo" : "=h" (r)); - return r; + return x % y; } /* { dg-final { scan-assembler "\tdmacchi\t" } } */ diff --git a/gcc/testsuite/gcc.target/mips/int-moves-1.c b/gcc/testsuite/gcc.target/mips/int-moves-1.c new file mode 100644 index 00000000000..62e659a93fe --- /dev/null +++ b/gcc/testsuite/gcc.target/mips/int-moves-1.c @@ -0,0 +1,40 @@ +/* { dg-do compile { target mips16_attribute } } */ +/* { dg-mips-options "-mgp64 -msoft-float -O2 -EL" } */ +/* { dg-add-options mips16_attribute } */ + +typedef unsigned uint128_t __attribute__((mode(TI))); + +extern uint128_t g[16]; +extern unsigned char gstuff[0x10000]; + +NOMIPS16 uint128_t +foo (uint128_t i1, uint128_t i2, uint128_t i3, uint128_t i4, + uint128_t *x, unsigned char *lstuff) +{ + g[0] = i1; + g[1] = i2; + g[2] = i3; + g[3] = i4; + x[0] = x[4]; + x[1] = 0; + x[2] = ((uint128_t) 0x123456789abcdefULL << 64) | 0xaabbccddeeff1122ULL; + x[3] = g[4]; + x[4] = *(uint128_t *) (lstuff + 0x7fff); + return *(uint128_t *) (gstuff + 0x7fff); +} + +MIPS16 uint128_t +bar (uint128_t i1, uint128_t i2, uint128_t i3, uint128_t i4, + uint128_t *x, unsigned char *lstuff) +{ + g[0] = i1; + g[1] = i2; + g[2] = i3; + g[3] = i4; + x[0] = x[4]; + x[1] = 0; + x[2] = ((uint128_t) 0x123456789abcdefULL << 64) | 0xaabbccddeeff1122ULL; + x[3] = g[4]; + x[4] = *(uint128_t *) (lstuff + 0x7fff); + return *(uint128_t *) (gstuff + 0x7fff); +} diff --git a/gcc/testsuite/gcc.target/mips/int-moves-2.c b/gcc/testsuite/gcc.target/mips/int-moves-2.c new file mode 100644 index 00000000000..325bfceb029 --- /dev/null +++ b/gcc/testsuite/gcc.target/mips/int-moves-2.c @@ -0,0 +1,40 @@ +/* { dg-do compile { target mips16_attribute } } */ +/* { dg-mips-options "-mgp64 -msoft-float -O2 -EB" } */ +/* { dg-add-options mips16_attribute } */ + +typedef unsigned uint128_t __attribute__((mode(TI))); + +extern uint128_t g[16]; +extern unsigned char gstuff[0x10000]; + +NOMIPS16 uint128_t +foo (uint128_t i1, uint128_t i2, uint128_t i3, uint128_t i4, + uint128_t *x, unsigned char *lstuff) +{ + g[0] = i1; + g[1] = i2; + g[2] = i3; + g[3] = i4; + x[0] = x[4]; + x[1] = 0; + x[2] = ((uint128_t) 0x123456789abcdefULL << 64) | 0xaabbccddeeff1122ULL; + x[3] = g[4]; + x[4] = *(uint128_t *) (lstuff + 0x7fff); + return *(uint128_t *) (gstuff + 0x7fff); +} + +MIPS16 uint128_t +bar (uint128_t i1, uint128_t i2, uint128_t i3, uint128_t i4, + uint128_t *x, unsigned char *lstuff) +{ + g[0] = i1; + g[1] = i2; + g[2] = i3; + g[3] = i4; + x[0] = x[4]; + x[1] = 0; + x[2] = ((uint128_t) 0x123456789abcdefULL << 64) | 0xaabbccddeeff1122ULL; + x[3] = g[4]; + x[4] = *(uint128_t *) (lstuff + 0x7fff); + return *(uint128_t *) (gstuff + 0x7fff); +} diff --git a/gcc/testsuite/gcc.target/mips/pr35232.c b/gcc/testsuite/gcc.target/mips/pr35232.c deleted file mode 100644 index c0e0649b52e..00000000000 --- a/gcc/testsuite/gcc.target/mips/pr35232.c +++ /dev/null @@ -1,17 +0,0 @@ -/* { dg-do run } */ -/* { dg-mips-options "-O" } */ - -NOMIPS16 unsigned int -f1 (unsigned long long x) -{ - unsigned int r; - asm ("# %0" : "=a" (r) : "0" (x)); - asm ("# %0" : "=h" (r) : "0" (r)); - return r; -} - -int -main (void) -{ - return f1 (4) != 4; -} diff --git a/gcc/testsuite/gcc.target/mips/timode-1.c b/gcc/testsuite/gcc.target/mips/timode-1.c new file mode 100644 index 00000000000..8f07db98559 --- /dev/null +++ b/gcc/testsuite/gcc.target/mips/timode-1.c @@ -0,0 +1,65 @@ +/* { dg-mips-options "-mgp64" } */ +typedef int int128_t __attribute__((mode(TI))); +typedef unsigned int uint128_t __attribute__((mode(TI))); + +#define UINT128_CONST(A, B) \ + (((uint128_t) (0x ## A ## ULL) << 64) | (0x ## B ## ULL)) + +volatile uint128_t a = UINT128_CONST (1111111111111111, a222222222222222); +volatile uint128_t b = UINT128_CONST (0000000000000005, 0000000000000003); +volatile uint128_t c = UINT128_CONST (5dddddddddddddde, e666666666666666); +volatile uint128_t d = UINT128_CONST (e612340000000000, 5000000000234500); +volatile uint128_t e = UINT128_CONST (43f011dddddddddf, 366666666689ab66); +volatile uint128_t f = UINT128_CONST (4210100000000000, 1000000000010100); +volatile uint128_t g = UINT128_CONST (a5e225dddddddddf, 6666666666aaee66); +volatile uint128_t h = UINT128_CONST (e7f235dddddddddf, 7666666666abef66); +volatile uint128_t i = UINT128_CONST (5e225dddddddddf6, 666666666aaee660); +volatile uint128_t j = UINT128_CONST (0a5e225ddddddddd, f6666666666aaee6); +volatile uint128_t k = UINT128_CONST (fa5e225ddddddddd, f6666666666aaee6); + +volatile int amount = 4; + +volatile uint128_t result; + +int +main (void) +{ + result = a * b; + if (result != c) + return 1; + + result = c + d; + if (result != e) + return 1; + + result = e - d; + if (result != c) + return 1; + + result = d & e; + if (result != f) + return 1; + + result = d ^ e; + if (result != g) + return 1; + + result = d | e; + if (result != h) + return 1; + + result = g << amount; + if (result != i) + return 1; + + result = g >> amount; + if (result != j) + return 1; + + result = (int128_t) g >> amount; + if (result != k) + return 1; + + return 0; +} +/* { dg-final { scan-assembler-not "\tjal" } } */ diff --git a/gcc/testsuite/gcc.target/mips/timode-2.c b/gcc/testsuite/gcc.target/mips/timode-2.c new file mode 100644 index 00000000000..025dc21810a --- /dev/null +++ b/gcc/testsuite/gcc.target/mips/timode-2.c @@ -0,0 +1,64 @@ +/* { dg-do run { target mips64 } } */ +typedef int int128_t __attribute__((mode(TI))); +typedef unsigned int uint128_t __attribute__((mode(TI))); + +#define UINT128_CONST(A, B) \ + (((uint128_t) (0x ## A ## ULL) << 64) | (0x ## B ## ULL)) + +volatile uint128_t a = UINT128_CONST (1111111111111111, a222222222222222); +volatile uint128_t b = UINT128_CONST (0000000000000005, 0000000000000003); +volatile uint128_t c = UINT128_CONST (5dddddddddddddde, e666666666666666); +volatile uint128_t d = UINT128_CONST (e612340000000000, 5000000000234500); +volatile uint128_t e = UINT128_CONST (43f011dddddddddf, 366666666689ab66); +volatile uint128_t f = UINT128_CONST (4210100000000000, 1000000000010100); +volatile uint128_t g = UINT128_CONST (a5e225dddddddddf, 6666666666aaee66); +volatile uint128_t h = UINT128_CONST (e7f235dddddddddf, 7666666666abef66); +volatile uint128_t i = UINT128_CONST (5e225dddddddddf6, 666666666aaee660); +volatile uint128_t j = UINT128_CONST (0a5e225ddddddddd, f6666666666aaee6); +volatile uint128_t k = UINT128_CONST (fa5e225ddddddddd, f6666666666aaee6); + +volatile int amount = 4; + +volatile uint128_t result; + +int +main (void) +{ + result = a * b; + if (result != c) + return 1; + + result = c + d; + if (result != e) + return 1; + + result = e - d; + if (result != c) + return 1; + + result = d & e; + if (result != f) + return 1; + + result = d ^ e; + if (result != g) + return 1; + + result = d | e; + if (result != h) + return 1; + + result = g << amount; + if (result != i) + return 1; + + result = g >> amount; + if (result != j) + return 1; + + result = (int128_t) g >> amount; + if (result != k) + return 1; + + return 0; +} -- 2.30.2