| ;; Machine description for Loongson MultiMedia extensions Instructions (MMI). |
| ;; Copyright (C) 2008-2021 Free Software Foundation, Inc. |
| ;; Contributed by CodeSourcery. |
| ;; |
| ;; This file is part of GCC. |
| ;; |
| ;; GCC is free software; you can redistribute it and/or modify |
| ;; it under the terms of the GNU General Public License as published by |
| ;; the Free Software Foundation; either version 3, or (at your option) |
| ;; any later version. |
| |
| ;; GCC is distributed in the hope that it will be useful, |
| ;; but WITHOUT ANY WARRANTY; without even the implied warranty of |
| ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| ;; GNU General Public License for more details. |
| |
| ;; You should have received a copy of the GNU General Public License |
| ;; along with GCC; see the file COPYING3. If not see |
| ;; <http://www.gnu.org/licenses/>. |
| |
| (define_c_enum "unspec" [ |
| UNSPEC_LOONGSON_PAVG |
| UNSPEC_LOONGSON_PCMPEQ |
| UNSPEC_LOONGSON_PCMPGT |
| UNSPEC_LOONGSON_PEXTR |
| UNSPEC_LOONGSON_PINSRH |
| UNSPEC_LOONGSON_VINIT |
| UNSPEC_LOONGSON_PMADD |
| UNSPEC_LOONGSON_PMOVMSK |
| UNSPEC_LOONGSON_PMULHU |
| UNSPEC_LOONGSON_PMULH |
| UNSPEC_LOONGSON_PMULU |
| UNSPEC_LOONGSON_PASUBUB |
| UNSPEC_LOONGSON_BIADD |
| UNSPEC_LOONGSON_PSADBH |
| UNSPEC_LOONGSON_PSHUFH |
| UNSPEC_LOONGSON_PUNPCKH |
| UNSPEC_LOONGSON_PUNPCKL |
| UNSPEC_LOONGSON_PADDD |
| UNSPEC_LOONGSON_PSUBD |
| UNSPEC_LOONGSON_DSLL |
| UNSPEC_LOONGSON_DSRL |
| ]) |
| |
| ;; Mode iterators and attributes. |
| |
| ;; 64-bit vectors of bytes. |
| (define_mode_iterator VB [V8QI]) |
| |
| ;; 64-bit vectors of halfwords. |
| (define_mode_iterator VH [V4HI]) |
| |
| ;; 64-bit vectors of words. |
| (define_mode_iterator VW [V2SI]) |
| |
| ;; 64-bit vectors of halfwords and bytes. |
| (define_mode_iterator VHB [V4HI V8QI]) |
| |
| ;; 64-bit vectors of words and halfwords. |
| (define_mode_iterator VWH [V2SI V4HI]) |
| |
| ;; 64-bit vectors of words and bytes |
| (define_mode_iterator VWB [V2SI V8QI]) |
| |
| ;; 64-bit vectors of words, halfwords and bytes. |
| (define_mode_iterator VWHB [V2SI V4HI V8QI]) |
| |
| ;; 64-bit vectors of words, halfwords and bytes; and DImode. |
| (define_mode_iterator VWHBDI [V2SI V4HI V8QI DI]) |
| |
| ;; The Loongson instruction suffixes corresponding to the modes in the |
| ;; VWHBDI iterator. |
| (define_mode_attr V_suffix [(V2SI "w") (V4HI "h") (V8QI "b") (DI "d")]) |
| |
| ;; Given a vector type T, the mode of a vector half the size of T |
| ;; and with the same number of elements. |
| (define_mode_attr V_squash [(V2SI "V2HI") (V4HI "V4QI")]) |
| |
| ;; Given a vector type T, the mode of a vector the same size as T |
| ;; but with half as many elements. |
| (define_mode_attr V_stretch_half [(V2SI "DI") (V4HI "V2SI") (V8QI "V4HI")]) |
| |
| ;; The Loongson instruction suffixes corresponding to the transformation |
| ;; expressed by V_stretch_half. |
| (define_mode_attr V_stretch_half_suffix [(V2SI "wd") (V4HI "hw") (V8QI "bh")]) |
| |
| ;; Given a vector type T, the mode of a vector the same size as T |
| ;; but with twice as many elements. |
| (define_mode_attr V_squash_double [(V2SI "V4HI") (V4HI "V8QI")]) |
| |
| ;; Given a vector type T, the inner mode. |
| (define_mode_attr V_inner [(V8QI "QI") (V4HI "HI") (V2SI "SI")]) |
| |
| ;; The Loongson instruction suffixes corresponding to the conversions |
| ;; specified by V_half_width. |
| (define_mode_attr V_squash_double_suffix [(V2SI "wh") (V4HI "hb")]) |
| |
| ;; Move patterns. |
| |
| ;; Expander to legitimize moves involving values of vector modes. |
| (define_expand "mov<mode>" |
| [(set (match_operand:VWHB 0) |
| (match_operand:VWHB 1))] |
| "TARGET_HARD_FLOAT && TARGET_LOONGSON_MMI" |
| { |
| if (mips_legitimize_move (<MODE>mode, operands[0], operands[1])) |
| DONE; |
| }) |
| |
| ;; Handle legitimized moves between values of vector modes. |
| (define_insn "mov<mode>_internal" |
| [(set (match_operand:VWHB 0 "nonimmediate_operand" "=m,f,d,f, d, m, d") |
| (match_operand:VWHB 1 "move_operand" "f,m,f,dYG,dYG,dYG,m"))] |
| "TARGET_HARD_FLOAT && TARGET_LOONGSON_MMI" |
| { return mips_output_move (operands[0], operands[1]); } |
| [(set_attr "move_type" "fpstore,fpload,mfc,mtc,move,store,load") |
| (set_attr "mode" "DI")]) |
| |
| ;; Initialization of a vector. |
| |
| (define_expand "vec_init<mode><unitmode>" |
| [(set (match_operand:VWHB 0 "register_operand") |
| (match_operand 1 ""))] |
| "TARGET_HARD_FLOAT && TARGET_LOONGSON_MMI" |
| { |
| mips_expand_vector_init (operands[0], operands[1]); |
| DONE; |
| }) |
| |
| ;; Helper for vec_init. Initialize element 0 of the output from the input. |
| ;; All other elements are undefined. |
| (define_insn "loongson_vec_init1_<mode>" |
| [(set (match_operand:VHB 0 "register_operand" "=f") |
| (unspec:VHB [(truncate:<V_inner> |
| (match_operand:DI 1 "reg_or_0_operand" "Jd"))] |
| UNSPEC_LOONGSON_VINIT))] |
| "TARGET_HARD_FLOAT && TARGET_LOONGSON_MMI" |
| "dmtc1\t%z1,%0" |
| [(set_attr "move_type" "mtc") |
| (set_attr "mode" "DI")]) |
| |
| ;; Helper for vec_initv2si. |
| (define_insn "*vec_concatv2si" |
| [(set (match_operand:V2SI 0 "register_operand" "=f") |
| (vec_concat:V2SI |
| (match_operand:SI 1 "register_operand" "f") |
| (match_operand:SI 2 "register_operand" "f")))] |
| "TARGET_HARD_FLOAT && TARGET_LOONGSON_MMI" |
| "punpcklwd\t%0,%1,%2" |
| [(set_attr "type" "fcvt")]) |
| |
| ;; Instruction patterns for SIMD instructions. |
| |
| ;; Pack with signed saturation. |
| (define_insn "vec_pack_ssat_<mode>" |
| [(set (match_operand:<V_squash_double> 0 "register_operand" "=f") |
| (vec_concat:<V_squash_double> |
| (ss_truncate:<V_squash> |
| (match_operand:VWH 1 "register_operand" "f")) |
| (ss_truncate:<V_squash> |
| (match_operand:VWH 2 "register_operand" "f"))))] |
| "TARGET_HARD_FLOAT && TARGET_LOONGSON_MMI" |
| "packss<V_squash_double_suffix>\t%0,%1,%2" |
| [(set_attr "type" "fmul")]) |
| |
| ;; Pack with unsigned saturation. |
| (define_insn "vec_pack_usat_<mode>" |
| [(set (match_operand:<V_squash_double> 0 "register_operand" "=f") |
| (vec_concat:<V_squash_double> |
| (us_truncate:<V_squash> |
| (match_operand:VH 1 "register_operand" "f")) |
| (us_truncate:<V_squash> |
| (match_operand:VH 2 "register_operand" "f"))))] |
| "TARGET_HARD_FLOAT && TARGET_LOONGSON_MMI" |
| "packus<V_squash_double_suffix>\t%0,%1,%2" |
| [(set_attr "type" "fmul")]) |
| |
| ;; Addition, treating overflow by wraparound. |
| (define_insn "add<mode>3" |
| [(set (match_operand:VWHB 0 "register_operand" "=f") |
| (plus:VWHB (match_operand:VWHB 1 "register_operand" "f") |
| (match_operand:VWHB 2 "register_operand" "f")))] |
| "TARGET_HARD_FLOAT && TARGET_LOONGSON_MMI" |
| "padd<V_suffix>\t%0,%1,%2" |
| [(set_attr "type" "fadd")]) |
| |
| ;; Addition of doubleword integers stored in FP registers. |
| ;; Overflow is treated by wraparound. |
| ;; We use 'unspec' instead of 'plus' here to avoid clash with |
| ;; mips.md::add<mode>3. If 'plus' was used, then such instruction |
| ;; would be recognized as adddi3 and reload would make it use |
| ;; GPRs instead of FPRs. |
| (define_insn "loongson_paddd" |
| [(set (match_operand:DI 0 "register_operand" "=f") |
| (unspec:DI [(match_operand:DI 1 "register_operand" "f") |
| (match_operand:DI 2 "register_operand" "f")] |
| UNSPEC_LOONGSON_PADDD))] |
| "TARGET_HARD_FLOAT && TARGET_LOONGSON_MMI" |
| "paddd\t%0,%1,%2" |
| [(set_attr "type" "fadd")]) |
| |
| ;; Addition, treating overflow by signed saturation. |
| (define_insn "ssadd<mode>3" |
| [(set (match_operand:VHB 0 "register_operand" "=f") |
| (ss_plus:VHB (match_operand:VHB 1 "register_operand" "f") |
| (match_operand:VHB 2 "register_operand" "f")))] |
| "TARGET_HARD_FLOAT && TARGET_LOONGSON_MMI" |
| "padds<V_suffix>\t%0,%1,%2" |
| [(set_attr "type" "fadd")]) |
| |
| ;; Addition, treating overflow by unsigned saturation. |
| (define_insn "usadd<mode>3" |
| [(set (match_operand:VHB 0 "register_operand" "=f") |
| (us_plus:VHB (match_operand:VHB 1 "register_operand" "f") |
| (match_operand:VHB 2 "register_operand" "f")))] |
| "TARGET_HARD_FLOAT && TARGET_LOONGSON_MMI" |
| "paddus<V_suffix>\t%0,%1,%2" |
| [(set_attr "type" "fadd")]) |
| |
| ;; Logical AND NOT. |
| (define_insn "loongson_pandn_<V_suffix>" |
| [(set (match_operand:VWHBDI 0 "register_operand" "=f") |
| (and:VWHBDI |
| (not:VWHBDI (match_operand:VWHBDI 1 "register_operand" "f")) |
| (match_operand:VWHBDI 2 "register_operand" "f")))] |
| "TARGET_HARD_FLOAT && TARGET_LOONGSON_MMI" |
| "pandn\t%0,%1,%2" |
| [(set_attr "type" "fmul")]) |
| |
| ;; Logical AND. |
| (define_insn "and<mode>3" |
| [(set (match_operand:VWHB 0 "register_operand" "=f") |
| (and:VWHB (match_operand:VWHB 1 "register_operand" "f") |
| (match_operand:VWHB 2 "register_operand" "f")))] |
| "TARGET_HARD_FLOAT && TARGET_LOONGSON_MMI" |
| "and\t%0,%1,%2" |
| [(set_attr "type" "fmul")]) |
| |
| ;; Logical OR. |
| (define_insn "ior<mode>3" |
| [(set (match_operand:VWHB 0 "register_operand" "=f") |
| (ior:VWHB (match_operand:VWHB 1 "register_operand" "f") |
| (match_operand:VWHB 2 "register_operand" "f")))] |
| "TARGET_HARD_FLOAT && TARGET_LOONGSON_MMI" |
| "or\t%0,%1,%2" |
| [(set_attr "type" "fcvt")]) |
| |
| ;; Logical XOR. |
| (define_insn "xor<mode>3" |
| [(set (match_operand:VWHB 0 "register_operand" "=f") |
| (xor:VWHB (match_operand:VWHB 1 "register_operand" "f") |
| (match_operand:VWHB 2 "register_operand" "f")))] |
| "TARGET_HARD_FLOAT && TARGET_LOONGSON_MMI" |
| "xor\t%0,%1,%2" |
| [(set_attr "type" "fmul")]) |
| |
| ;; Logical NOR. |
| (define_insn "*loongson_nor" |
| [(set (match_operand:VWHB 0 "register_operand" "=f") |
| (and:VWHB |
| (not:VWHB (match_operand:VWHB 1 "register_operand" "f")) |
| (not:VWHB (match_operand:VWHB 2 "register_operand" "f"))))] |
| "TARGET_HARD_FLOAT && TARGET_LOONGSON_MMI" |
| "nor\t%0,%1,%2" |
| [(set_attr "type" "fmul")]) |
| |
| ;; Logical NOT. |
| (define_insn "one_cmpl<mode>2" |
| [(set (match_operand:VWHB 0 "register_operand" "=f") |
| (not:VWHB (match_operand:VWHB 1 "register_operand" "f")))] |
| "TARGET_HARD_FLOAT && TARGET_LOONGSON_MMI" |
| "nor\t%0,%1,%1" |
| [(set_attr "type" "fmul")]) |
| |
| ;; Average. |
| (define_insn "loongson_pavg<V_suffix>" |
| [(set (match_operand:VHB 0 "register_operand" "=f") |
| (unspec:VHB [(match_operand:VHB 1 "register_operand" "f") |
| (match_operand:VHB 2 "register_operand" "f")] |
| UNSPEC_LOONGSON_PAVG))] |
| "TARGET_HARD_FLOAT && TARGET_LOONGSON_MMI" |
| "pavg<V_suffix>\t%0,%1,%2" |
| [(set_attr "type" "fadd")]) |
| |
| ;; Equality test. |
| (define_insn "loongson_pcmpeq<V_suffix>" |
| [(set (match_operand:VWHB 0 "register_operand" "=f") |
| (unspec:VWHB [(match_operand:VWHB 1 "register_operand" "f") |
| (match_operand:VWHB 2 "register_operand" "f")] |
| UNSPEC_LOONGSON_PCMPEQ))] |
| "TARGET_HARD_FLOAT && TARGET_LOONGSON_MMI" |
| "pcmpeq<V_suffix>\t%0,%1,%2" |
| [(set_attr "type" "fadd")]) |
| |
| ;; Greater-than test. |
| (define_insn "loongson_pcmpgt<V_suffix>" |
| [(set (match_operand:VWHB 0 "register_operand" "=f") |
| (unspec:VWHB [(match_operand:VWHB 1 "register_operand" "f") |
| (match_operand:VWHB 2 "register_operand" "f")] |
| UNSPEC_LOONGSON_PCMPGT))] |
| "TARGET_HARD_FLOAT && TARGET_LOONGSON_MMI" |
| "pcmpgt<V_suffix>\t%0,%1,%2" |
| [(set_attr "type" "fadd")]) |
| |
| ;; Extract halfword. |
| (define_insn "loongson_pextrh" |
| [(set (match_operand:V4HI 0 "register_operand" "=f") |
| (unspec:V4HI [(match_operand:V4HI 1 "register_operand" "f") |
| (match_operand:SI 2 "register_operand" "f")] |
| UNSPEC_LOONGSON_PEXTR))] |
| "TARGET_HARD_FLOAT && TARGET_LOONGSON_MMI" |
| "pextrh\t%0,%1,%2" |
| [(set_attr "type" "fcvt")]) |
| |
| ;; Insert halfword. |
| (define_insn "loongson_pinsrh_0" |
| [(set (match_operand:V4HI 0 "register_operand" "=f") |
| (vec_select:V4HI |
| (vec_concat:V8HI |
| (match_operand:V4HI 1 "register_operand" "f") |
| (match_operand:V4HI 2 "register_operand" "f")) |
| (parallel [(const_int 4) (const_int 1) |
| (const_int 2) (const_int 3)])))] |
| "TARGET_HARD_FLOAT && TARGET_LOONGSON_MMI" |
| "pinsrh_0\t%0,%1,%2" |
| [(set_attr "type" "fdiv")]) |
| |
| (define_insn "loongson_pinsrh_1" |
| [(set (match_operand:V4HI 0 "register_operand" "=f") |
| (vec_select:V4HI |
| (vec_concat:V8HI |
| (match_operand:V4HI 1 "register_operand" "f") |
| (match_operand:V4HI 2 "register_operand" "f")) |
| (parallel [(const_int 0) (const_int 4) |
| (const_int 2) (const_int 3)])))] |
| "TARGET_HARD_FLOAT && TARGET_LOONGSON_MMI" |
| "pinsrh_1\t%0,%1,%2" |
| [(set_attr "type" "fdiv")]) |
| |
| (define_insn "loongson_pinsrh_2" |
| [(set (match_operand:V4HI 0 "register_operand" "=f") |
| (vec_select:V4HI |
| (vec_concat:V8HI |
| (match_operand:V4HI 1 "register_operand" "f") |
| (match_operand:V4HI 2 "register_operand" "f")) |
| (parallel [(const_int 0) (const_int 1) |
| (const_int 4) (const_int 3)])))] |
| "TARGET_HARD_FLOAT && TARGET_LOONGSON_MMI" |
| "pinsrh_2\t%0,%1,%2" |
| [(set_attr "type" "fdiv")]) |
| |
| (define_insn "loongson_pinsrh_3" |
| [(set (match_operand:V4HI 0 "register_operand" "=f") |
| (vec_select:V4HI |
| (vec_concat:V8HI |
| (match_operand:V4HI 1 "register_operand" "f") |
| (match_operand:V4HI 2 "register_operand" "f")) |
| (parallel [(const_int 0) (const_int 1) |
| (const_int 2) (const_int 4)])))] |
| "TARGET_HARD_FLOAT && TARGET_LOONGSON_MMI" |
| "pinsrh_3\t%0,%1,%2" |
| [(set_attr "type" "fdiv")]) |
| |
| (define_insn "*vec_setv4hi" |
| [(set (match_operand:V4HI 0 "register_operand" "=f") |
| (unspec:V4HI [(match_operand:V4HI 1 "register_operand" "f") |
| (match_operand:SI 2 "register_operand" "f") |
| (match_operand:SI 3 "const_0_to_3_operand" "")] |
| UNSPEC_LOONGSON_PINSRH))] |
| "TARGET_HARD_FLOAT && TARGET_LOONGSON_MMI" |
| "pinsrh_%3\t%0,%1,%2" |
| [(set_attr "type" "fdiv")]) |
| |
| (define_expand "vec_setv4hi" |
| [(set (match_operand:V4HI 0 "register_operand" "=f") |
| (unspec:V4HI [(match_operand:V4HI 1 "register_operand" "f") |
| (match_operand:HI 2 "register_operand" "f") |
| (match_operand:SI 3 "const_0_to_3_operand" "")] |
| UNSPEC_LOONGSON_PINSRH))] |
| "TARGET_HARD_FLOAT && TARGET_LOONGSON_MMI" |
| { |
| rtx ext = gen_reg_rtx (SImode); |
| emit_move_insn (ext, gen_lowpart (SImode, operands[2])); |
| operands[2] = ext; |
| }) |
| |
| ;; Multiply and add packed integers. |
| (define_insn "loongson_pmaddhw" |
| [(set (match_operand:V2SI 0 "register_operand" "=f") |
| (unspec:V2SI [(match_operand:V4HI 1 "register_operand" "f") |
| (match_operand:V4HI 2 "register_operand" "f")] |
| UNSPEC_LOONGSON_PMADD))] |
| "TARGET_HARD_FLOAT && TARGET_LOONGSON_MMI" |
| "pmaddhw\t%0,%1,%2" |
| [(set_attr "type" "fmul")]) |
| |
| (define_expand "sdot_prodv4hi" |
| [(match_operand:V2SI 0 "register_operand" "") |
| (match_operand:V4HI 1 "register_operand" "") |
| (match_operand:V4HI 2 "register_operand" "") |
| (match_operand:V2SI 3 "register_operand" "")] |
| "TARGET_HARD_FLOAT && TARGET_LOONGSON_MMI" |
| { |
| rtx t = gen_reg_rtx (V2SImode); |
| emit_insn (gen_loongson_pmaddhw (t, operands[1], operands[2])); |
| emit_insn (gen_addv2si3 (operands[0], t, operands[3])); |
| DONE; |
| }) |
| |
| ;; Maximum of signed halfwords. |
| (define_insn "smaxv4hi3" |
| [(set (match_operand:V4HI 0 "register_operand" "=f") |
| (smax:V4HI (match_operand:V4HI 1 "register_operand" "f") |
| (match_operand:V4HI 2 "register_operand" "f")))] |
| "TARGET_HARD_FLOAT && TARGET_LOONGSON_MMI" |
| "pmaxsh\t%0,%1,%2" |
| [(set_attr "type" "fadd")]) |
| |
| (define_expand "smax<mode>3" |
| [(match_operand:VWB 0 "register_operand" "") |
| (match_operand:VWB 1 "register_operand" "") |
| (match_operand:VWB 2 "register_operand" "")] |
| "TARGET_HARD_FLOAT && TARGET_LOONGSON_MMI" |
| { |
| mips_expand_vec_minmax (operands[0], operands[1], operands[2], |
| gen_loongson_pcmpgt<V_suffix>, false); |
| DONE; |
| }) |
| |
| ;; Maximum of unsigned bytes. |
| (define_insn "umaxv8qi3" |
| [(set (match_operand:V8QI 0 "register_operand" "=f") |
| (umax:V8QI (match_operand:V8QI 1 "register_operand" "f") |
| (match_operand:V8QI 2 "register_operand" "f")))] |
| "TARGET_HARD_FLOAT && TARGET_LOONGSON_MMI" |
| "pmaxub\t%0,%1,%2" |
| [(set_attr "type" "fadd")]) |
| |
| ;; Minimum of signed halfwords. |
| (define_insn "sminv4hi3" |
| [(set (match_operand:V4HI 0 "register_operand" "=f") |
| (smin:V4HI (match_operand:V4HI 1 "register_operand" "f") |
| (match_operand:V4HI 2 "register_operand" "f")))] |
| "TARGET_HARD_FLOAT && TARGET_LOONGSON_MMI" |
| "pminsh\t%0,%1,%2" |
| [(set_attr "type" "fadd")]) |
| |
| (define_expand "smin<mode>3" |
| [(match_operand:VWB 0 "register_operand" "") |
| (match_operand:VWB 1 "register_operand" "") |
| (match_operand:VWB 2 "register_operand" "")] |
| "TARGET_HARD_FLOAT && TARGET_LOONGSON_MMI" |
| { |
| mips_expand_vec_minmax (operands[0], operands[1], operands[2], |
| gen_loongson_pcmpgt<V_suffix>, true); |
| DONE; |
| }) |
| |
| ;; Minimum of unsigned bytes. |
| (define_insn "uminv8qi3" |
| [(set (match_operand:V8QI 0 "register_operand" "=f") |
| (umin:V8QI (match_operand:V8QI 1 "register_operand" "f") |
| (match_operand:V8QI 2 "register_operand" "f")))] |
| "TARGET_HARD_FLOAT && TARGET_LOONGSON_MMI" |
| "pminub\t%0,%1,%2" |
| [(set_attr "type" "fadd")]) |
| |
| ;; Move byte mask. |
| (define_insn "loongson_pmovmsk<V_suffix>" |
| [(set (match_operand:VB 0 "register_operand" "=f") |
| (unspec:VB [(match_operand:VB 1 "register_operand" "f")] |
| UNSPEC_LOONGSON_PMOVMSK))] |
| "TARGET_HARD_FLOAT && TARGET_LOONGSON_MMI" |
| "pmovmsk<V_suffix>\t%0,%1" |
| [(set_attr "type" "fabs")]) |
| |
| ;; Multiply unsigned integers and store high result. |
| (define_insn "umul<mode>3_highpart" |
| [(set (match_operand:VH 0 "register_operand" "=f") |
| (unspec:VH [(match_operand:VH 1 "register_operand" "f") |
| (match_operand:VH 2 "register_operand" "f")] |
| UNSPEC_LOONGSON_PMULHU))] |
| "TARGET_HARD_FLOAT && TARGET_LOONGSON_MMI" |
| "pmulhu<V_suffix>\t%0,%1,%2" |
| [(set_attr "type" "fmul")]) |
| |
| ;; Multiply signed integers and store high result. |
| (define_insn "smul<mode>3_highpart" |
| [(set (match_operand:VH 0 "register_operand" "=f") |
| (unspec:VH [(match_operand:VH 1 "register_operand" "f") |
| (match_operand:VH 2 "register_operand" "f")] |
| UNSPEC_LOONGSON_PMULH))] |
| "TARGET_HARD_FLOAT && TARGET_LOONGSON_MMI" |
| "pmulh<V_suffix>\t%0,%1,%2" |
| [(set_attr "type" "fmul")]) |
| |
| ;; Multiply signed integers and store low result. |
| (define_insn "mul<mode>3" |
| [(set (match_operand:VH 0 "register_operand" "=f") |
| (mult:VH (match_operand:VH 1 "register_operand" "f") |
| (match_operand:VH 2 "register_operand" "f")))] |
| "TARGET_HARD_FLOAT && TARGET_LOONGSON_MMI" |
| "pmull<V_suffix>\t%0,%1,%2" |
| [(set_attr "type" "fmul")]) |
| |
| ;; Multiply unsigned word integers. |
| (define_insn "loongson_pmulu<V_suffix>" |
| [(set (match_operand:DI 0 "register_operand" "=f") |
| (unspec:DI [(match_operand:VW 1 "register_operand" "f") |
| (match_operand:VW 2 "register_operand" "f")] |
| UNSPEC_LOONGSON_PMULU))] |
| "TARGET_HARD_FLOAT && TARGET_LOONGSON_MMI" |
| "pmulu<V_suffix>\t%0,%1,%2" |
| [(set_attr "type" "fmul")]) |
| |
| ;; Absolute difference. |
| (define_insn "loongson_pasubub" |
| [(set (match_operand:VB 0 "register_operand" "=f") |
| (unspec:VB [(match_operand:VB 1 "register_operand" "f") |
| (match_operand:VB 2 "register_operand" "f")] |
| UNSPEC_LOONGSON_PASUBUB))] |
| "TARGET_HARD_FLOAT && TARGET_LOONGSON_MMI" |
| "pasubub\t%0,%1,%2" |
| [(set_attr "type" "fadd")]) |
| |
| ;; Sum of unsigned byte integers. |
| (define_insn "loongson_biadd" |
| [(set (match_operand:<V_stretch_half> 0 "register_operand" "=f") |
| (unspec:<V_stretch_half> [(match_operand:VB 1 "register_operand" "f")] |
| UNSPEC_LOONGSON_BIADD))] |
| "TARGET_HARD_FLOAT && TARGET_LOONGSON_MMI" |
| "biadd\t%0,%1" |
| [(set_attr "type" "fabs")]) |
| |
| (define_insn "reduc_uplus_v8qi" |
| [(set (match_operand:V8QI 0 "register_operand" "=f") |
| (unspec:V8QI [(match_operand:V8QI 1 "register_operand" "f")] |
| UNSPEC_LOONGSON_BIADD))] |
| "TARGET_HARD_FLOAT && TARGET_LOONGSON_MMI" |
| "biadd\t%0,%1" |
| [(set_attr "type" "fabs")]) |
| |
| ;; Sum of absolute differences. |
| (define_insn "loongson_psadbh" |
| [(set (match_operand:<V_stretch_half> 0 "register_operand" "=f") |
| (unspec:<V_stretch_half> [(match_operand:VB 1 "register_operand" "f") |
| (match_operand:VB 2 "register_operand" "f")] |
| UNSPEC_LOONGSON_PSADBH))] |
| "TARGET_HARD_FLOAT && TARGET_LOONGSON_MMI" |
| "pasubub\t%0,%1,%2;biadd\t%0,%0" |
| [(set_attr "type" "fadd")]) |
| |
| ;; Shuffle halfwords. |
| (define_insn "loongson_pshufh" |
| [(set (match_operand:VH 0 "register_operand" "=f") |
| (unspec:VH [(match_operand:VH 1 "register_operand" "f") |
| (match_operand:SI 2 "register_operand" "f")] |
| UNSPEC_LOONGSON_PSHUFH))] |
| "TARGET_HARD_FLOAT && TARGET_LOONGSON_MMI" |
| "pshufh\t%0,%1,%2" |
| [(set_attr "type" "fmul")]) |
| |
| ;; Shift left logical. |
| (define_insn "ashl<mode>3" |
| [(set (match_operand:VWH 0 "register_operand" "=f") |
| (ashift:VWH (match_operand:VWH 1 "register_operand" "f") |
| (match_operand:SI 2 "register_operand" "f")))] |
| "TARGET_HARD_FLOAT && TARGET_LOONGSON_MMI" |
| "psll<V_suffix>\t%0,%1,%2" |
| [(set_attr "type" "fcvt")]) |
| |
| ;; Shift right arithmetic. |
| (define_insn "ashr<mode>3" |
| [(set (match_operand:VWH 0 "register_operand" "=f") |
| (ashiftrt:VWH (match_operand:VWH 1 "register_operand" "f") |
| (match_operand:SI 2 "register_operand" "f")))] |
| "TARGET_HARD_FLOAT && TARGET_LOONGSON_MMI" |
| "psra<V_suffix>\t%0,%1,%2" |
| [(set_attr "type" "fcvt")]) |
| |
| ;; Shift right logical. |
| (define_insn "lshr<mode>3" |
| [(set (match_operand:VWH 0 "register_operand" "=f") |
| (lshiftrt:VWH (match_operand:VWH 1 "register_operand" "f") |
| (match_operand:SI 2 "register_operand" "f")))] |
| "TARGET_HARD_FLOAT && TARGET_LOONGSON_MMI" |
| "psrl<V_suffix>\t%0,%1,%2" |
| [(set_attr "type" "fcvt")]) |
| |
| ;; Subtraction, treating overflow by wraparound. |
| (define_insn "sub<mode>3" |
| [(set (match_operand:VWHB 0 "register_operand" "=f") |
| (minus:VWHB (match_operand:VWHB 1 "register_operand" "f") |
| (match_operand:VWHB 2 "register_operand" "f")))] |
| "TARGET_HARD_FLOAT && TARGET_LOONGSON_MMI" |
| "psub<V_suffix>\t%0,%1,%2" |
| [(set_attr "type" "fadd")]) |
| |
| ;; Subtraction of doubleword integers stored in FP registers. |
| ;; Overflow is treated by wraparound. |
| ;; See loongson_paddd for the reason we use 'unspec' rather than |
| ;; 'minus' here. |
| (define_insn "loongson_psubd" |
| [(set (match_operand:DI 0 "register_operand" "=f") |
| (unspec:DI [(match_operand:DI 1 "register_operand" "f") |
| (match_operand:DI 2 "register_operand" "f")] |
| UNSPEC_LOONGSON_PSUBD))] |
| "TARGET_HARD_FLOAT && TARGET_LOONGSON_MMI" |
| "psubd\t%0,%1,%2" |
| [(set_attr "type" "fadd")]) |
| |
| ;; Subtraction, treating overflow by signed saturation. |
| (define_insn "sssub<mode>3" |
| [(set (match_operand:VHB 0 "register_operand" "=f") |
| (ss_minus:VHB (match_operand:VHB 1 "register_operand" "f") |
| (match_operand:VHB 2 "register_operand" "f")))] |
| "TARGET_HARD_FLOAT && TARGET_LOONGSON_MMI" |
| "psubs<V_suffix>\t%0,%1,%2" |
| [(set_attr "type" "fadd")]) |
| |
| ;; Subtraction, treating overflow by unsigned saturation. |
| (define_insn "ussub<mode>3" |
| [(set (match_operand:VHB 0 "register_operand" "=f") |
| (us_minus:VHB (match_operand:VHB 1 "register_operand" "f") |
| (match_operand:VHB 2 "register_operand" "f")))] |
| "TARGET_HARD_FLOAT && TARGET_LOONGSON_MMI" |
| "psubus<V_suffix>\t%0,%1,%2" |
| [(set_attr "type" "fadd")]) |
| |
| ;; Unpack high data. Recall that Loongson only runs in little-endian. |
| (define_insn "loongson_punpckhbh" |
| [(set (match_operand:V8QI 0 "register_operand" "=f") |
| (vec_select:V8QI |
| (vec_concat:V16QI |
| (match_operand:V8QI 1 "register_operand" "f") |
| (match_operand:V8QI 2 "register_operand" "f")) |
| (parallel [(const_int 4) (const_int 12) |
| (const_int 5) (const_int 13) |
| (const_int 6) (const_int 14) |
| (const_int 7) (const_int 15)])))] |
| "TARGET_HARD_FLOAT && TARGET_LOONGSON_MMI" |
| "punpckhbh\t%0,%1,%2" |
| [(set_attr "type" "fdiv")]) |
| |
| (define_insn "loongson_punpckhhw" |
| [(set (match_operand:V4HI 0 "register_operand" "=f") |
| (vec_select:V4HI |
| (vec_concat:V8HI |
| (match_operand:V4HI 1 "register_operand" "f") |
| (match_operand:V4HI 2 "register_operand" "f")) |
| (parallel [(const_int 2) (const_int 6) |
| (const_int 3) (const_int 7)])))] |
| "TARGET_HARD_FLOAT && TARGET_LOONGSON_MMI" |
| "punpckhhw\t%0,%1,%2" |
| [(set_attr "type" "fdiv")]) |
| |
| (define_insn "loongson_punpckhhw_qi" |
| [(set (match_operand:V8QI 0 "register_operand" "=f") |
| (vec_select:V8QI |
| (vec_concat:V16QI |
| (match_operand:V8QI 1 "register_operand" "f") |
| (match_operand:V8QI 2 "register_operand" "f")) |
| (parallel [(const_int 4) (const_int 5) |
| (const_int 12) (const_int 13) |
| (const_int 6) (const_int 7) |
| (const_int 14) (const_int 15)])))] |
| "TARGET_HARD_FLOAT && TARGET_LOONGSON_MMI" |
| "punpckhhw\t%0,%1,%2" |
| [(set_attr "type" "fdiv")]) |
| |
| (define_insn "loongson_punpckhwd" |
| [(set (match_operand:V2SI 0 "register_operand" "=f") |
| (vec_select:V2SI |
| (vec_concat:V4SI |
| (match_operand:V2SI 1 "register_operand" "f") |
| (match_operand:V2SI 2 "register_operand" "f")) |
| (parallel [(const_int 1) (const_int 3)])))] |
| "TARGET_HARD_FLOAT && TARGET_LOONGSON_MMI" |
| "punpckhwd\t%0,%1,%2" |
| [(set_attr "type" "fcvt")]) |
| |
| (define_insn "loongson_punpckhwd_qi" |
| [(set (match_operand:V8QI 0 "register_operand" "=f") |
| (vec_select:V8QI |
| (vec_concat:V16QI |
| (match_operand:V8QI 1 "register_operand" "f") |
| (match_operand:V8QI 2 "register_operand" "f")) |
| (parallel [(const_int 4) (const_int 5) |
| (const_int 6) (const_int 7) |
| (const_int 12) (const_int 13) |
| (const_int 14) (const_int 15)])))] |
| "TARGET_HARD_FLOAT && TARGET_LOONGSON_MMI" |
| "punpckhwd\t%0,%1,%2" |
| [(set_attr "type" "fcvt")]) |
| |
| (define_insn "loongson_punpckhwd_hi" |
| [(set (match_operand:V4HI 0 "register_operand" "=f") |
| (vec_select:V4HI |
| (vec_concat:V8HI |
| (match_operand:V4HI 1 "register_operand" "f") |
| (match_operand:V4HI 2 "register_operand" "f")) |
| (parallel [(const_int 2) (const_int 3) |
| (const_int 6) (const_int 7)])))] |
| "TARGET_HARD_FLOAT && TARGET_LOONGSON_MMI" |
| "punpckhwd\t%0,%1,%2" |
| [(set_attr "type" "fcvt")]) |
| |
| ;; Unpack low data. |
| (define_insn "loongson_punpcklbh" |
| [(set (match_operand:V8QI 0 "register_operand" "=f") |
| (vec_select:V8QI |
| (vec_concat:V16QI |
| (match_operand:V8QI 1 "register_operand" "f") |
| (match_operand:V8QI 2 "register_operand" "f")) |
| (parallel [(const_int 0) (const_int 8) |
| (const_int 1) (const_int 9) |
| (const_int 2) (const_int 10) |
| (const_int 3) (const_int 11)])))] |
| "TARGET_HARD_FLOAT && TARGET_LOONGSON_MMI" |
| "punpcklbh\t%0,%1,%2" |
| [(set_attr "type" "fdiv")]) |
| |
| (define_insn "loongson_punpcklhw" |
| [(set (match_operand:V4HI 0 "register_operand" "=f") |
| (vec_select:V4HI |
| (vec_concat:V8HI |
| (match_operand:V4HI 1 "register_operand" "f") |
| (match_operand:V4HI 2 "register_operand" "f")) |
| (parallel [(const_int 0) (const_int 4) |
| (const_int 1) (const_int 5)])))] |
| "TARGET_HARD_FLOAT && TARGET_LOONGSON_MMI" |
| "punpcklhw\t%0,%1,%2" |
| [(set_attr "type" "fdiv")]) |
| |
| (define_insn "*loongson_punpcklhw_qi" |
| [(set (match_operand:V8QI 0 "register_operand" "=f") |
| (vec_select:V8QI |
| (vec_concat:V16QI |
| (match_operand:V8QI 1 "register_operand" "f") |
| (match_operand:V8QI 2 "register_operand" "f")) |
| (parallel [(const_int 0) (const_int 1) |
| (const_int 8) (const_int 9) |
| (const_int 2) (const_int 3) |
| (const_int 10) (const_int 11)])))] |
| "TARGET_HARD_FLOAT && TARGET_LOONGSON_MMI" |
| "punpcklhw\t%0,%1,%2" |
| [(set_attr "type" "fdiv")]) |
| |
| (define_insn "loongson_punpcklwd" |
| [(set (match_operand:V2SI 0 "register_operand" "=f") |
| (vec_select:V2SI |
| (vec_concat:V4SI |
| (match_operand:V2SI 1 "register_operand" "f") |
| (match_operand:V2SI 2 "register_operand" "f")) |
| (parallel [(const_int 0) (const_int 2)])))] |
| "TARGET_HARD_FLOAT && TARGET_LOONGSON_MMI" |
| "punpcklwd\t%0,%1,%2" |
| [(set_attr "type" "fcvt")]) |
| |
| (define_insn "*loongson_punpcklwd_qi" |
| [(set (match_operand:V8QI 0 "register_operand" "=f") |
| (vec_select:V8QI |
| (vec_concat:V16QI |
| (match_operand:V8QI 1 "register_operand" "f") |
| (match_operand:V8QI 2 "register_operand" "f")) |
| (parallel [(const_int 0) (const_int 1) |
| (const_int 2) (const_int 3) |
| (const_int 8) (const_int 9) |
| (const_int 10) (const_int 11)])))] |
| "TARGET_HARD_FLOAT && TARGET_LOONGSON_MMI" |
| "punpcklwd\t%0,%1,%2" |
| [(set_attr "type" "fcvt")]) |
| |
| (define_insn "*loongson_punpcklwd_hi" |
| [(set (match_operand:V4HI 0 "register_operand" "=f") |
| (vec_select:V4HI |
| (vec_concat:V8HI |
| (match_operand:V4HI 1 "register_operand" "f") |
| (match_operand:V4HI 2 "register_operand" "f")) |
| (parallel [(const_int 0) (const_int 1) |
| (const_int 4) (const_int 5)])))] |
| "TARGET_HARD_FLOAT && TARGET_LOONGSON_MMI" |
| "punpcklwd\t%0,%1,%2" |
| [(set_attr "type" "fcvt")]) |
| |
| (define_expand "vec_unpacks_lo_<mode>" |
| [(match_operand:<V_stretch_half> 0 "register_operand" "") |
| (match_operand:VHB 1 "register_operand" "")] |
| "TARGET_HARD_FLOAT && TARGET_LOONGSON_MMI" |
| { |
| mips_expand_vec_unpack (operands, false, false); |
| DONE; |
| }) |
| |
| (define_expand "vec_unpacks_hi_<mode>" |
| [(match_operand:<V_stretch_half> 0 "register_operand" "") |
| (match_operand:VHB 1 "register_operand" "")] |
| "TARGET_HARD_FLOAT && TARGET_LOONGSON_MMI" |
| { |
| mips_expand_vec_unpack (operands, false, true); |
| DONE; |
| }) |
| |
| (define_expand "vec_unpacku_lo_<mode>" |
| [(match_operand:<V_stretch_half> 0 "register_operand" "") |
| (match_operand:VHB 1 "register_operand" "")] |
| "TARGET_HARD_FLOAT && TARGET_LOONGSON_MMI" |
| { |
| mips_expand_vec_unpack (operands, true, false); |
| DONE; |
| }) |
| |
| (define_expand "vec_unpacku_hi_<mode>" |
| [(match_operand:<V_stretch_half> 0 "register_operand" "") |
| (match_operand:VHB 1 "register_operand" "")] |
| "TARGET_HARD_FLOAT && TARGET_LOONGSON_MMI" |
| { |
| mips_expand_vec_unpack (operands, true, true); |
| DONE; |
| }) |
| |
| ;; Whole vector shifts, used for reduction epilogues. |
| (define_insn "vec_shl_<mode>" |
| [(set (match_operand:VWHBDI 0 "register_operand" "=f") |
| (unspec:VWHBDI [(match_operand:VWHBDI 1 "register_operand" "f") |
| (match_operand:SI 2 "register_operand" "f")] |
| UNSPEC_LOONGSON_DSLL))] |
| "TARGET_HARD_FLOAT && TARGET_LOONGSON_MMI" |
| "dsll\t%0,%1,%2" |
| [(set_attr "type" "fcvt")]) |
| |
| (define_insn "vec_shr_<mode>" |
| [(set (match_operand:VWHBDI 0 "register_operand" "=f") |
| (unspec:VWHBDI [(match_operand:VWHBDI 1 "register_operand" "f") |
| (match_operand:SI 2 "register_operand" "f")] |
| UNSPEC_LOONGSON_DSRL))] |
| "TARGET_HARD_FLOAT && TARGET_LOONGSON_MMI" |
| "dsrl\t%0,%1,%2" |
| [(set_attr "type" "fcvt")]) |
| |
| (define_insn "vec_loongson_extract_lo_<mode>" |
| [(set (match_operand:<V_inner> 0 "register_operand" "=r") |
| (vec_select:<V_inner> |
| (match_operand:VWHB 1 "register_operand" "f") |
| (parallel [(const_int 0)])))] |
| "TARGET_HARD_FLOAT && TARGET_LOONGSON_MMI" |
| "mfc1\t%0,%1" |
| [(set_attr "type" "mfc")]) |
| |
| (define_expand "reduc_plus_scal_<mode>" |
| [(match_operand:<V_inner> 0 "register_operand" "") |
| (match_operand:VWHB 1 "register_operand" "")] |
| "TARGET_HARD_FLOAT && TARGET_LOONGSON_MMI" |
| { |
| rtx tmp = gen_reg_rtx (GET_MODE (operands[1])); |
| mips_expand_vec_reduc (tmp, operands[1], gen_add<mode>3); |
| emit_insn (gen_vec_loongson_extract_lo_<mode> (operands[0], tmp)); |
| DONE; |
| }) |
| |
| (define_expand "reduc_smax_scal_<mode>" |
| [(match_operand:<V_inner> 0 "register_operand" "") |
| (match_operand:VWHB 1 "register_operand" "")] |
| "TARGET_HARD_FLOAT && TARGET_LOONGSON_MMI" |
| { |
| rtx tmp = gen_reg_rtx (GET_MODE (operands[1])); |
| mips_expand_vec_reduc (tmp, operands[1], gen_smax<mode>3); |
| emit_insn (gen_vec_loongson_extract_lo_<mode> (operands[0], tmp)); |
| DONE; |
| }) |
| |
| (define_expand "reduc_smin_scal_<mode>" |
| [(match_operand:<V_inner> 0 "register_operand" "") |
| (match_operand:VWHB 1 "register_operand" "")] |
| "TARGET_HARD_FLOAT && TARGET_LOONGSON_MMI" |
| { |
| rtx tmp = gen_reg_rtx (GET_MODE (operands[1])); |
| mips_expand_vec_reduc (tmp, operands[1], gen_smin<mode>3); |
| emit_insn (gen_vec_loongson_extract_lo_<mode> (operands[0], tmp)); |
| DONE; |
| }) |
| |
| (define_expand "reduc_umax_scal_<mode>" |
| [(match_operand:<V_inner> 0 "register_operand" "") |
| (match_operand:VB 1 "register_operand" "")] |
| "TARGET_HARD_FLOAT && TARGET_LOONGSON_MMI" |
| { |
| rtx tmp = gen_reg_rtx (GET_MODE (operands[1])); |
| mips_expand_vec_reduc (tmp, operands[1], gen_umax<mode>3); |
| emit_insn (gen_vec_loongson_extract_lo_<mode> (operands[0], tmp)); |
| DONE; |
| }) |
| |
| (define_expand "reduc_umin_scal_<mode>" |
| [(match_operand:<V_inner> 0 "register_operand" "") |
| (match_operand:VB 1 "register_operand" "")] |
| "TARGET_HARD_FLOAT && TARGET_LOONGSON_MMI" |
| { |
| rtx tmp = gen_reg_rtx (GET_MODE (operands[1])); |
| mips_expand_vec_reduc (tmp, operands[1], gen_umin<mode>3); |
| emit_insn (gen_vec_loongson_extract_lo_<mode> (operands[0], tmp)); |
| DONE; |
| }) |