;; Machine description for Loongson-specific patterns, such as ;; ST Microelectronics Loongson-2E/2F etc. ;; Copyright (C) 2008-2015 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" [(set (match_operand:VWHB 0)
(match_operand:VWHB 1))]
"TARGET_HARD_FLOAT && TARGET_LOONGSON_VECTORS" { if (mips_legitimize_move (mode, operands[0], operands[1]))
DONE;
})
;; Handle legitimized moves between values of vector modes. (define_insn "mov_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_VECTORS" { 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" [(set (match_operand:VWHB 0 "register_operand")
(match_operand 1 ""))]
"TARGET_HARD_FLOAT && TARGET_LOONGSON_VECTORS" { 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_vecinit1" [(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_VECTORS" "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_VECTORS" "punpcklwd\t%0,%1,%2" [(set_attr "type" "fcvt")])
;; Instruction patterns for SIMD instructions.
;; Pack with signed saturation. (define_insn "vec_packssat" [(set (match_operand: 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_VECTORS" "packss\t%0,%1,%2" [(set_attr "type" "fmul")])
;; Pack with unsigned saturation. (define_insn "vec_packusat" [(set (match_operand: 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_VECTORS" "packus\t%0,%1,%2" [(set_attr "type" "fmul")])
;; Addition, treating overflow by wraparound. (define_insn "add3" [(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_VECTORS" "padd\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::add3. 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_VECTORS" "paddd\t%0,%1,%2" [(set_attr "type" "fadd")])
;; Addition, treating overflow by signed saturation. (define_insn "ssadd3" [(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_VECTORS" "padds\t%0,%1,%2" [(set_attr "type" "fadd")])
;; Addition, treating overflow by unsigned saturation. (define_insn "usadd3" [(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_VECTORS" "paddus\t%0,%1,%2" [(set_attr "type" "fadd")])
;; Logical AND NOT. (define_insn "loongsonpandn" [(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_VECTORS" "pandn\t%0,%1,%2" [(set_attr "type" "fmul")])
;; Logical AND. (define_insn "and3" [(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_VECTORS" "and\t%0,%1,%2" [(set_attr "type" "fmul")])
;; Logical OR. (define_insn "ior3" [(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_VECTORS" "or\t%0,%1,%2" [(set_attr "type" "fcvt")])
;; Logical XOR. (define_insn "xor3" [(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_VECTORS" "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_VECTORS" "nor\t%0,%1,%2" [(set_attr "type" "fmul")])
;; Logical NOT. (define_insn "one_cmpl2" [(set (match_operand:VWHB 0 "register_operand" "=f")
(not:VWHB (match_operand:VWHB 1 "register_operand" "f")))]
"TARGET_HARD_FLOAT && TARGET_LOONGSON_VECTORS" "nor\t%0,%1,%1" [(set_attr "type" "fmul")])
;; Average. (define_insn "loongson_pavg" [(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_VECTORS" "pavg\t%0,%1,%2" [(set_attr "type" "fadd")])
;; Equality test. (define_insn "loongson_pcmpeq" [(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_VECTORS" "pcmpeq\t%0,%1,%2" [(set_attr "type" "fadd")])
;; Greater-than test. (define_insn "loongson_pcmpgt" [(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_VECTORS" "pcmpgt\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_VECTORS" "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_VECTORS" "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_VECTORS" "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_VECTORS" "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_VECTORS" "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_LOONGSONVECTORS" "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_VECTORS" { rtx ext = gen_reg_rtx (SImode); emit_move_insn (ext, gen_lowpart (SImode, operands[1])); operands[1] = 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_VECTORS" "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_VECTORS" { 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_VECTORS" "pmaxsh\t%0,%1,%2" [(set_attr "type" "fadd")])
(define_expand "smax3" [(match_operand:VWB 0 "register_operand" "") (match_operand:VWB 1 "register_operand" "") (match_operand:VWB 2 "register_operand" "")] "TARGET_HARD_FLOAT && TARGET_LOONGSON_VECTORS" { 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_VECTORS" "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_VECTORS" "pminsh\t%0,%1,%2" [(set_attr "type" "fadd")])
(define_expand "smin3" [(match_operand:VWB 0 "register_operand" "") (match_operand:VWB 1 "register_operand" "") (match_operand:VWB 2 "register_operand" "")] "TARGET_HARD_FLOAT && TARGET_LOONGSON_VECTORS" { 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_VECTORS" "pminub\t%0,%1,%2" [(set_attr "type" "fadd")])
;; Move byte mask. (define_insn "loongson_pmovmsk" [(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_VECTORS" "pmovmsk\t%0,%1" [(set_attr "type" "fabs")])
;; Multiply unsigned integers and store high result. (define_insn "umul3_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_VECTORS" "pmulhu\t%0,%1,%2" [(set_attr "type" "fmul")])
;; Multiply signed integers and store high result. (define_insn "smul3_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_VECTORS" "pmulh\t%0,%1,%2" [(set_attr "type" "fmul")])
;; Multiply signed integers and store low result. (define_insn "mul3" [(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_VECTORS" "pmull\t%0,%1,%2" [(set_attr "type" "fmul")])
;; Multiply unsigned word integers. (define_insn "loongson_pmulu" [(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_VECTORS" "pmulu\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_VECTORS" "pasubub\t%0,%1,%2" [(set_attr "type" "fadd")])
;; Sum of unsigned byte integers. (define_insn "loongson_biadd" [(set (match_operand: 0 "register_operand" "=f")
(unspec:<V_stretch_half> [(match_operand:VB 1 "register_operand" "f")]
UNSPEC_LOONGSON_BIADD))]
"TARGET_HARD_FLOAT && TARGET_LOONGSON_VECTORS" "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_VECTORS" "biadd\t%0,%1" [(set_attr "type" "fabs")])
;; Sum of absolute differences. (define_insn "loongson_psadbh" [(set (match_operand: 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_VECTORS" "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_VECTORS" "pshufh\t%0,%1,%2" [(set_attr "type" "fmul")])
;; Shift left logical. (define_insn "ashl3" [(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_VECTORS" "psll\t%0,%1,%2" [(set_attr "type" "fcvt")])
;; Shift right arithmetic. (define_insn "ashr3" [(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_VECTORS" "psra\t%0,%1,%2" [(set_attr "type" "fcvt")])
;; Shift right logical. (define_insn "lshr3" [(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_VECTORS" "psrl\t%0,%1,%2" [(set_attr "type" "fcvt")])
;; Subtraction, treating overflow by wraparound. (define_insn "sub3" [(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_VECTORS" "psub\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_VECTORS" "psubd\t%0,%1,%2" [(set_attr "type" "fadd")])
;; Subtraction, treating overflow by signed saturation. (define_insn "sssub3" [(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_VECTORS" "psubs\t%0,%1,%2" [(set_attr "type" "fadd")])
;; Subtraction, treating overflow by unsigned saturation. (define_insn "ussub3" [(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_VECTORS" "psubus\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_VECTORS" "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_VECTORS" "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_VECTORS" "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_VECTORS" "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_VECTORS" "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_VECTORS" "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_VECTORS" "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_VECTORS" "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_VECTORS" "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_VECTORS" "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_VECTORS" "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_VECTORS" "punpcklwd\t%0,%1,%2" [(set_attr "type" "fcvt")])
(define_expand "vec_perm_const" [(match_operand:VWHB 0 "register_operand" "") (match_operand:VWHB 1 "register_operand" "") (match_operand:VWHB 2 "register_operand" "") (match_operand:VWHB 3 "" "")] "TARGET_HARD_FLOAT && TARGET_LOONGSON_VECTORS" { if (mips_expand_vec_perm_const (operands))
DONE;
else
FAIL;
})
(define_expand "vec_unpackslo" [(match_operand: 0 "register_operand" "") (match_operand:VHB 1 "register_operand" "")] "TARGET_HARD_FLOAT && TARGET_LOONGSON_VECTORS" { mips_expand_vec_unpack (operands, false, false); DONE; })
(define_expand "vec_unpackshi" [(match_operand: 0 "register_operand" "") (match_operand:VHB 1 "register_operand" "")] "TARGET_HARD_FLOAT && TARGET_LOONGSON_VECTORS" { mips_expand_vec_unpack (operands, false, true); DONE; })
(define_expand "vec_unpackulo" [(match_operand: 0 "register_operand" "") (match_operand:VHB 1 "register_operand" "")] "TARGET_HARD_FLOAT && TARGET_LOONGSON_VECTORS" { mips_expand_vec_unpack (operands, true, false); DONE; })
(define_expand "vec_unpackuhi" [(match_operand: 0 "register_operand" "") (match_operand:VHB 1 "register_operand" "")] "TARGET_HARD_FLOAT && TARGET_LOONGSON_VECTORS" { mips_expand_vec_unpack (operands, true, true); DONE; })
;; Whole vector shifts, used for reduction epilogues. (define_insn "vecshl" [(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_VECTORS" "dsll\t%0,%1,%2" [(set_attr "type" "fcvt")])
(define_insn "vecshr" [(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_VECTORS" "dsrl\t%0,%1,%2" [(set_attr "type" "fcvt")])
(define_expand "reducuplus" [(match_operand:VWH 0 "register_operand" "") (match_operand:VWH 1 "register_operand" "")] "TARGET_HARD_FLOAT && TARGET_LOONGSON_VECTORS" { mips_expand_vec_reduc (operands[0], operands[1], gen_add3); DONE; })
; ??? Given that we're not describing a widening reduction, we should ; not have separate optabs for signed and unsigned. (define_expand "reducsplus" [(match_operand:VWHB 0 "register_operand" "") (match_operand:VWHB 1 "register_operand" "")] "TARGET_HARD_FLOAT && TARGET_LOONGSON_VECTORS" { emit_insn (gen_reducuplus(operands[0], operands[1])); DONE; })
(define_expand "reducsmax" [(match_operand:VWHB 0 "register_operand" "") (match_operand:VWHB 1 "register_operand" "")] "TARGET_HARD_FLOAT && TARGET_LOONGSON_VECTORS" { mips_expand_vec_reduc (operands[0], operands[1], gen_smax3); DONE; })
(define_expand "reducsmin" [(match_operand:VWHB 0 "register_operand" "") (match_operand:VWHB 1 "register_operand" "")] "TARGET_HARD_FLOAT && TARGET_LOONGSON_VECTORS" { mips_expand_vec_reduc (operands[0], operands[1], gen_smin3); DONE; })
(define_expand "reducumax" [(match_operand:VB 0 "register_operand" "") (match_operand:VB 1 "register_operand" "")] "TARGET_HARD_FLOAT && TARGET_LOONGSON_VECTORS" { mips_expand_vec_reduc (operands[0], operands[1], gen_umax3); DONE; })
(define_expand "reducumin" [(match_operand:VB 0 "register_operand" "") (match_operand:VB 1 "register_operand" "")] "TARGET_HARD_FLOAT && TARGET_LOONGSON_VECTORS" { mips_expand_vec_reduc (operands[0], operands[1], gen_umin3); DONE; })