1;; Machine description for Loongson-specific patterns, such as
2;; ST Microelectronics Loongson-2E/2F etc.
3;; Copyright (C) 2008-2015 Free Software Foundation, Inc.
4;; Contributed by CodeSourcery.
5;;
6;; This file is part of GCC.
7;;
8;; GCC is free software; you can redistribute it and/or modify
9;; it under the terms of the GNU General Public License as published by
10;; the Free Software Foundation; either version 3, or (at your option)
11;; any later version.
12
13;; GCC is distributed in the hope that it will be useful,
14;; but WITHOUT ANY WARRANTY; without even the implied warranty of
15;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16;; GNU General Public License for more details.
17
18;; You should have received a copy of the GNU General Public License
19;; along with GCC; see the file COPYING3.  If not see
20;; <http://www.gnu.org/licenses/>.
21
22(define_c_enum "unspec" [
23  UNSPEC_LOONGSON_PAVG
24  UNSPEC_LOONGSON_PCMPEQ
25  UNSPEC_LOONGSON_PCMPGT
26  UNSPEC_LOONGSON_PEXTR
27  UNSPEC_LOONGSON_PINSRH
28  UNSPEC_LOONGSON_VINIT
29  UNSPEC_LOONGSON_PMADD
30  UNSPEC_LOONGSON_PMOVMSK
31  UNSPEC_LOONGSON_PMULHU
32  UNSPEC_LOONGSON_PMULH
33  UNSPEC_LOONGSON_PMULU
34  UNSPEC_LOONGSON_PASUBUB
35  UNSPEC_LOONGSON_BIADD
36  UNSPEC_LOONGSON_PSADBH
37  UNSPEC_LOONGSON_PSHUFH
38  UNSPEC_LOONGSON_PUNPCKH
39  UNSPEC_LOONGSON_PUNPCKL
40  UNSPEC_LOONGSON_PADDD
41  UNSPEC_LOONGSON_PSUBD
42  UNSPEC_LOONGSON_DSLL
43  UNSPEC_LOONGSON_DSRL
44])
45
46;; Mode iterators and attributes.
47
48;; 64-bit vectors of bytes.
49(define_mode_iterator VB [V8QI])
50
51;; 64-bit vectors of halfwords.
52(define_mode_iterator VH [V4HI])
53
54;; 64-bit vectors of words.
55(define_mode_iterator VW [V2SI])
56
57;; 64-bit vectors of halfwords and bytes.
58(define_mode_iterator VHB [V4HI V8QI])
59
60;; 64-bit vectors of words and halfwords.
61(define_mode_iterator VWH [V2SI V4HI])
62
63;; 64-bit vectors of words and bytes
64(define_mode_iterator VWB [V2SI V8QI])
65
66;; 64-bit vectors of words, halfwords and bytes.
67(define_mode_iterator VWHB [V2SI V4HI V8QI])
68
69;; 64-bit vectors of words, halfwords and bytes; and DImode.
70(define_mode_iterator VWHBDI [V2SI V4HI V8QI DI])
71
72;; The Loongson instruction suffixes corresponding to the modes in the
73;; VWHBDI iterator.
74(define_mode_attr V_suffix [(V2SI "w") (V4HI "h") (V8QI "b") (DI "d")])
75
76;; Given a vector type T, the mode of a vector half the size of T
77;; and with the same number of elements.
78(define_mode_attr V_squash [(V2SI "V2HI") (V4HI "V4QI")])
79
80;; Given a vector type T, the mode of a vector the same size as T
81;; but with half as many elements.
82(define_mode_attr V_stretch_half [(V2SI "DI") (V4HI "V2SI") (V8QI "V4HI")])
83
84;; The Loongson instruction suffixes corresponding to the transformation
85;; expressed by V_stretch_half.
86(define_mode_attr V_stretch_half_suffix [(V2SI "wd") (V4HI "hw") (V8QI "bh")])
87
88;; Given a vector type T, the mode of a vector the same size as T
89;; but with twice as many elements.
90(define_mode_attr V_squash_double [(V2SI "V4HI") (V4HI "V8QI")])
91
92;; Given a vector type T, the inner mode.
93(define_mode_attr V_inner [(V8QI "QI") (V4HI "HI") (V2SI "SI")])
94
95;; The Loongson instruction suffixes corresponding to the conversions
96;; specified by V_half_width.
97(define_mode_attr V_squash_double_suffix [(V2SI "wh") (V4HI "hb")])
98
99;; Move patterns.
100
101;; Expander to legitimize moves involving values of vector modes.
102(define_expand "mov<mode>"
103  [(set (match_operand:VWHB 0)
104	(match_operand:VWHB 1))]
105  "TARGET_HARD_FLOAT && TARGET_LOONGSON_VECTORS"
106{
107  if (mips_legitimize_move (<MODE>mode, operands[0], operands[1]))
108    DONE;
109})
110
111;; Handle legitimized moves between values of vector modes.
112(define_insn "mov<mode>_internal"
113  [(set (match_operand:VWHB 0 "nonimmediate_operand" "=m,f,d,f,  d,  m,  d")
114	(match_operand:VWHB 1 "move_operand"          "f,m,f,dYG,dYG,dYG,m"))]
115  "TARGET_HARD_FLOAT && TARGET_LOONGSON_VECTORS"
116  { return mips_output_move (operands[0], operands[1]); }
117  [(set_attr "move_type" "fpstore,fpload,mfc,mtc,move,store,load")
118   (set_attr "mode" "DI")])
119
120;; Initialization of a vector.
121
122(define_expand "vec_init<mode>"
123  [(set (match_operand:VWHB 0 "register_operand")
124	(match_operand 1 ""))]
125  "TARGET_HARD_FLOAT && TARGET_LOONGSON_VECTORS"
126{
127  mips_expand_vector_init (operands[0], operands[1]);
128  DONE;
129})
130
131;; Helper for vec_init.  Initialize element 0 of the output from the input.
132;; All other elements are undefined.
133(define_insn "loongson_vec_init1_<mode>"
134  [(set (match_operand:VHB 0 "register_operand" "=f")
135	(unspec:VHB [(truncate:<V_inner>
136		       (match_operand:DI 1 "reg_or_0_operand" "Jd"))]
137		    UNSPEC_LOONGSON_VINIT))]
138  "TARGET_HARD_FLOAT && TARGET_LOONGSON_VECTORS"
139  "dmtc1\t%z1,%0"
140  [(set_attr "move_type" "mtc")
141   (set_attr "mode" "DI")])
142
143;; Helper for vec_initv2si.
144(define_insn "*vec_concatv2si"
145  [(set (match_operand:V2SI 0 "register_operand" "=f")
146	(vec_concat:V2SI
147	  (match_operand:SI 1 "register_operand" "f")
148	  (match_operand:SI 2 "register_operand" "f")))]
149  "TARGET_HARD_FLOAT && TARGET_LOONGSON_VECTORS"
150  "punpcklwd\t%0,%1,%2"
151  [(set_attr "type" "fcvt")])
152
153;; Instruction patterns for SIMD instructions.
154
155;; Pack with signed saturation.
156(define_insn "vec_pack_ssat_<mode>"
157  [(set (match_operand:<V_squash_double> 0 "register_operand" "=f")
158        (vec_concat:<V_squash_double>
159	 (ss_truncate:<V_squash>
160	  (match_operand:VWH 1 "register_operand" "f"))
161	 (ss_truncate:<V_squash>
162	  (match_operand:VWH 2 "register_operand" "f"))))]
163  "TARGET_HARD_FLOAT && TARGET_LOONGSON_VECTORS"
164  "packss<V_squash_double_suffix>\t%0,%1,%2"
165  [(set_attr "type" "fmul")])
166
167;; Pack with unsigned saturation.
168(define_insn "vec_pack_usat_<mode>"
169  [(set (match_operand:<V_squash_double> 0 "register_operand" "=f")
170        (vec_concat:<V_squash_double>
171	 (us_truncate:<V_squash>
172	  (match_operand:VH 1 "register_operand" "f"))
173	 (us_truncate:<V_squash>
174	  (match_operand:VH 2 "register_operand" "f"))))]
175  "TARGET_HARD_FLOAT && TARGET_LOONGSON_VECTORS"
176  "packus<V_squash_double_suffix>\t%0,%1,%2"
177  [(set_attr "type" "fmul")])
178
179;; Addition, treating overflow by wraparound.
180(define_insn "add<mode>3"
181  [(set (match_operand:VWHB 0 "register_operand" "=f")
182        (plus:VWHB (match_operand:VWHB 1 "register_operand" "f")
183		   (match_operand:VWHB 2 "register_operand" "f")))]
184  "TARGET_HARD_FLOAT && TARGET_LOONGSON_VECTORS"
185  "padd<V_suffix>\t%0,%1,%2"
186  [(set_attr "type" "fadd")])
187
188;; Addition of doubleword integers stored in FP registers.
189;; Overflow is treated by wraparound.
190;; We use 'unspec' instead of 'plus' here to avoid clash with
191;; mips.md::add<mode>3.  If 'plus' was used, then such instruction
192;; would be recognized as adddi3 and reload would make it use
193;; GPRs instead of FPRs.
194(define_insn "loongson_paddd"
195  [(set (match_operand:DI 0 "register_operand" "=f")
196        (unspec:DI [(match_operand:DI 1 "register_operand" "f")
197		    (match_operand:DI 2 "register_operand" "f")]
198		   UNSPEC_LOONGSON_PADDD))]
199  "TARGET_HARD_FLOAT && TARGET_LOONGSON_VECTORS"
200  "paddd\t%0,%1,%2"
201  [(set_attr "type" "fadd")])
202
203;; Addition, treating overflow by signed saturation.
204(define_insn "ssadd<mode>3"
205  [(set (match_operand:VHB 0 "register_operand" "=f")
206        (ss_plus:VHB (match_operand:VHB 1 "register_operand" "f")
207		     (match_operand:VHB 2 "register_operand" "f")))]
208  "TARGET_HARD_FLOAT && TARGET_LOONGSON_VECTORS"
209  "padds<V_suffix>\t%0,%1,%2"
210  [(set_attr "type" "fadd")])
211
212;; Addition, treating overflow by unsigned saturation.
213(define_insn "usadd<mode>3"
214  [(set (match_operand:VHB 0 "register_operand" "=f")
215        (us_plus:VHB (match_operand:VHB 1 "register_operand" "f")
216		     (match_operand:VHB 2 "register_operand" "f")))]
217  "TARGET_HARD_FLOAT && TARGET_LOONGSON_VECTORS"
218  "paddus<V_suffix>\t%0,%1,%2"
219  [(set_attr "type" "fadd")])
220
221;; Logical AND NOT.
222(define_insn "loongson_pandn_<V_suffix>"
223  [(set (match_operand:VWHBDI 0 "register_operand" "=f")
224        (and:VWHBDI
225	 (not:VWHBDI (match_operand:VWHBDI 1 "register_operand" "f"))
226	 (match_operand:VWHBDI 2 "register_operand" "f")))]
227  "TARGET_HARD_FLOAT && TARGET_LOONGSON_VECTORS"
228  "pandn\t%0,%1,%2"
229  [(set_attr "type" "fmul")])
230
231;; Logical AND.
232(define_insn "and<mode>3"
233  [(set (match_operand:VWHB 0 "register_operand" "=f")
234	(and:VWHB (match_operand:VWHB 1 "register_operand" "f")
235		  (match_operand:VWHB 2 "register_operand" "f")))]
236  "TARGET_HARD_FLOAT && TARGET_LOONGSON_VECTORS"
237  "and\t%0,%1,%2"
238  [(set_attr "type" "fmul")])
239
240;; Logical OR.
241(define_insn "ior<mode>3"
242  [(set (match_operand:VWHB 0 "register_operand" "=f")
243	(ior:VWHB (match_operand:VWHB 1 "register_operand" "f")
244		  (match_operand:VWHB 2 "register_operand" "f")))]
245  "TARGET_HARD_FLOAT && TARGET_LOONGSON_VECTORS"
246  "or\t%0,%1,%2"
247  [(set_attr "type" "fcvt")])
248
249;; Logical XOR.
250(define_insn "xor<mode>3"
251  [(set (match_operand:VWHB 0 "register_operand" "=f")
252	(xor:VWHB (match_operand:VWHB 1 "register_operand" "f")
253		  (match_operand:VWHB 2 "register_operand" "f")))]
254  "TARGET_HARD_FLOAT && TARGET_LOONGSON_VECTORS"
255  "xor\t%0,%1,%2"
256  [(set_attr "type" "fmul")])
257
258;; Logical NOR.
259(define_insn "*loongson_nor"
260  [(set (match_operand:VWHB 0 "register_operand" "=f")
261	(and:VWHB
262	  (not:VWHB (match_operand:VWHB 1 "register_operand" "f"))
263	  (not:VWHB (match_operand:VWHB 2 "register_operand" "f"))))]
264  "TARGET_HARD_FLOAT && TARGET_LOONGSON_VECTORS"
265  "nor\t%0,%1,%2"
266  [(set_attr "type" "fmul")])
267
268;; Logical NOT.
269(define_insn "one_cmpl<mode>2"
270  [(set (match_operand:VWHB 0 "register_operand" "=f")
271	(not:VWHB (match_operand:VWHB 1 "register_operand" "f")))]
272  "TARGET_HARD_FLOAT && TARGET_LOONGSON_VECTORS"
273  "nor\t%0,%1,%1"
274  [(set_attr "type" "fmul")])
275
276;; Average.
277(define_insn "loongson_pavg<V_suffix>"
278  [(set (match_operand:VHB 0 "register_operand" "=f")
279        (unspec:VHB [(match_operand:VHB 1 "register_operand" "f")
280		     (match_operand:VHB 2 "register_operand" "f")]
281		    UNSPEC_LOONGSON_PAVG))]
282  "TARGET_HARD_FLOAT && TARGET_LOONGSON_VECTORS"
283  "pavg<V_suffix>\t%0,%1,%2"
284  [(set_attr "type" "fadd")])
285
286;; Equality test.
287(define_insn "loongson_pcmpeq<V_suffix>"
288  [(set (match_operand:VWHB 0 "register_operand" "=f")
289        (unspec:VWHB [(match_operand:VWHB 1 "register_operand" "f")
290		      (match_operand:VWHB 2 "register_operand" "f")]
291		     UNSPEC_LOONGSON_PCMPEQ))]
292  "TARGET_HARD_FLOAT && TARGET_LOONGSON_VECTORS"
293  "pcmpeq<V_suffix>\t%0,%1,%2"
294  [(set_attr "type" "fadd")])
295
296;; Greater-than test.
297(define_insn "loongson_pcmpgt<V_suffix>"
298  [(set (match_operand:VWHB 0 "register_operand" "=f")
299        (unspec:VWHB [(match_operand:VWHB 1 "register_operand" "f")
300		      (match_operand:VWHB 2 "register_operand" "f")]
301		     UNSPEC_LOONGSON_PCMPGT))]
302  "TARGET_HARD_FLOAT && TARGET_LOONGSON_VECTORS"
303  "pcmpgt<V_suffix>\t%0,%1,%2"
304  [(set_attr "type" "fadd")])
305
306;; Extract halfword.
307(define_insn "loongson_pextrh"
308  [(set (match_operand:V4HI 0 "register_operand" "=f")
309        (unspec:V4HI [(match_operand:V4HI 1 "register_operand" "f")
310		      (match_operand:SI 2 "register_operand" "f")]
311		   UNSPEC_LOONGSON_PEXTR))]
312  "TARGET_HARD_FLOAT && TARGET_LOONGSON_VECTORS"
313  "pextrh\t%0,%1,%2"
314  [(set_attr "type" "fcvt")])
315
316;; Insert halfword.
317(define_insn "loongson_pinsrh_0"
318  [(set (match_operand:V4HI 0 "register_operand" "=f")
319	(vec_select:V4HI
320	  (vec_concat:V8HI
321	    (match_operand:V4HI 1 "register_operand" "f")
322	    (match_operand:V4HI 2 "register_operand" "f"))
323	  (parallel [(const_int 4) (const_int 1)
324		     (const_int 2) (const_int 3)])))]
325  "TARGET_HARD_FLOAT && TARGET_LOONGSON_VECTORS"
326  "pinsrh_0\t%0,%1,%2"
327  [(set_attr "type" "fdiv")])
328
329(define_insn "loongson_pinsrh_1"
330  [(set (match_operand:V4HI 0 "register_operand" "=f")
331	(vec_select:V4HI
332	  (vec_concat:V8HI
333	    (match_operand:V4HI 1 "register_operand" "f")
334	    (match_operand:V4HI 2 "register_operand" "f"))
335	  (parallel [(const_int 0) (const_int 4)
336		     (const_int 2) (const_int 3)])))]
337  "TARGET_HARD_FLOAT && TARGET_LOONGSON_VECTORS"
338  "pinsrh_1\t%0,%1,%2"
339  [(set_attr "type" "fdiv")])
340
341(define_insn "loongson_pinsrh_2"
342  [(set (match_operand:V4HI 0 "register_operand" "=f")
343	(vec_select:V4HI
344	  (vec_concat:V8HI
345	    (match_operand:V4HI 1 "register_operand" "f")
346	    (match_operand:V4HI 2 "register_operand" "f"))
347	  (parallel [(const_int 0) (const_int 1)
348		     (const_int 4) (const_int 3)])))]
349  "TARGET_HARD_FLOAT && TARGET_LOONGSON_VECTORS"
350  "pinsrh_2\t%0,%1,%2"
351  [(set_attr "type" "fdiv")])
352
353(define_insn "loongson_pinsrh_3"
354  [(set (match_operand:V4HI 0 "register_operand" "=f")
355	(vec_select:V4HI
356	  (vec_concat:V8HI
357	    (match_operand:V4HI 1 "register_operand" "f")
358	    (match_operand:V4HI 2 "register_operand" "f"))
359	  (parallel [(const_int 0) (const_int 1)
360		     (const_int 2) (const_int 4)])))]
361  "TARGET_HARD_FLOAT && TARGET_LOONGSON_VECTORS"
362  "pinsrh_3\t%0,%1,%2"
363  [(set_attr "type" "fdiv")])
364
365(define_insn "*vec_setv4hi"
366  [(set (match_operand:V4HI 0 "register_operand" "=f")
367	(unspec:V4HI [(match_operand:V4HI 1 "register_operand" "f")
368		      (match_operand:SI 2 "register_operand" "f")
369		      (match_operand:SI 3 "const_0_to_3_operand" "")]
370		     UNSPEC_LOONGSON_PINSRH))]
371  "TARGET_HARD_FLOAT && TARGET_LOONGSON_VECTORS"
372  "pinsrh_%3\t%0,%1,%2"
373  [(set_attr "type" "fdiv")])
374
375(define_expand "vec_setv4hi"
376  [(set (match_operand:V4HI 0 "register_operand" "=f")
377	(unspec:V4HI [(match_operand:V4HI 1 "register_operand" "f")
378		      (match_operand:HI 2 "register_operand" "f")
379		      (match_operand:SI 3 "const_0_to_3_operand" "")]
380		     UNSPEC_LOONGSON_PINSRH))]
381  "TARGET_HARD_FLOAT && TARGET_LOONGSON_VECTORS"
382{
383  rtx ext = gen_reg_rtx (SImode);
384  emit_move_insn (ext, gen_lowpart (SImode, operands[1]));
385  operands[1] = ext;
386})
387
388;; Multiply and add packed integers.
389(define_insn "loongson_pmaddhw"
390  [(set (match_operand:V2SI 0 "register_operand" "=f")
391        (unspec:V2SI [(match_operand:V4HI 1 "register_operand" "f")
392		      (match_operand:V4HI 2 "register_operand" "f")]
393		     UNSPEC_LOONGSON_PMADD))]
394  "TARGET_HARD_FLOAT && TARGET_LOONGSON_VECTORS"
395  "pmaddhw\t%0,%1,%2"
396  [(set_attr "type" "fmul")])
397
398(define_expand "sdot_prodv4hi"
399  [(match_operand:V2SI 0 "register_operand" "")
400   (match_operand:V4HI 1 "register_operand" "")
401   (match_operand:V4HI 2 "register_operand" "")
402   (match_operand:V2SI 3 "register_operand" "")]
403  "TARGET_HARD_FLOAT && TARGET_LOONGSON_VECTORS"
404{
405  rtx t = gen_reg_rtx (V2SImode);
406  emit_insn (gen_loongson_pmaddhw (t, operands[1], operands[2]));
407  emit_insn (gen_addv2si3 (operands[0], t, operands[3]));
408  DONE;
409})
410
411;; Maximum of signed halfwords.
412(define_insn "smaxv4hi3"
413  [(set (match_operand:V4HI 0 "register_operand" "=f")
414        (smax:V4HI (match_operand:V4HI 1 "register_operand" "f")
415		   (match_operand:V4HI 2 "register_operand" "f")))]
416  "TARGET_HARD_FLOAT && TARGET_LOONGSON_VECTORS"
417  "pmaxsh\t%0,%1,%2"
418  [(set_attr "type" "fadd")])
419
420(define_expand "smax<mode>3"
421  [(match_operand:VWB 0 "register_operand" "")
422   (match_operand:VWB 1 "register_operand" "")
423   (match_operand:VWB 2 "register_operand" "")]
424  "TARGET_HARD_FLOAT && TARGET_LOONGSON_VECTORS"
425{
426  mips_expand_vec_minmax (operands[0], operands[1], operands[2],
427			  gen_loongson_pcmpgt<V_suffix>, false);
428  DONE;
429})
430
431;; Maximum of unsigned bytes.
432(define_insn "umaxv8qi3"
433  [(set (match_operand:V8QI 0 "register_operand" "=f")
434        (umax:V8QI (match_operand:V8QI 1 "register_operand" "f")
435		   (match_operand:V8QI 2 "register_operand" "f")))]
436  "TARGET_HARD_FLOAT && TARGET_LOONGSON_VECTORS"
437  "pmaxub\t%0,%1,%2"
438  [(set_attr "type" "fadd")])
439
440;; Minimum of signed halfwords.
441(define_insn "sminv4hi3"
442  [(set (match_operand:V4HI 0 "register_operand" "=f")
443        (smin:V4HI (match_operand:V4HI 1 "register_operand" "f")
444		   (match_operand:V4HI 2 "register_operand" "f")))]
445  "TARGET_HARD_FLOAT && TARGET_LOONGSON_VECTORS"
446  "pminsh\t%0,%1,%2"
447  [(set_attr "type" "fadd")])
448
449(define_expand "smin<mode>3"
450  [(match_operand:VWB 0 "register_operand" "")
451   (match_operand:VWB 1 "register_operand" "")
452   (match_operand:VWB 2 "register_operand" "")]
453  "TARGET_HARD_FLOAT && TARGET_LOONGSON_VECTORS"
454{
455  mips_expand_vec_minmax (operands[0], operands[1], operands[2],
456			  gen_loongson_pcmpgt<V_suffix>, true);
457  DONE;
458})
459
460;; Minimum of unsigned bytes.
461(define_insn "uminv8qi3"
462  [(set (match_operand:V8QI 0 "register_operand" "=f")
463        (umin:V8QI (match_operand:V8QI 1 "register_operand" "f")
464		   (match_operand:V8QI 2 "register_operand" "f")))]
465  "TARGET_HARD_FLOAT && TARGET_LOONGSON_VECTORS"
466  "pminub\t%0,%1,%2"
467  [(set_attr "type" "fadd")])
468
469;; Move byte mask.
470(define_insn "loongson_pmovmsk<V_suffix>"
471  [(set (match_operand:VB 0 "register_operand" "=f")
472        (unspec:VB [(match_operand:VB 1 "register_operand" "f")]
473		   UNSPEC_LOONGSON_PMOVMSK))]
474  "TARGET_HARD_FLOAT && TARGET_LOONGSON_VECTORS"
475  "pmovmsk<V_suffix>\t%0,%1"
476  [(set_attr "type" "fabs")])
477
478;; Multiply unsigned integers and store high result.
479(define_insn "umul<mode>3_highpart"
480  [(set (match_operand:VH 0 "register_operand" "=f")
481        (unspec:VH [(match_operand:VH 1 "register_operand" "f")
482		    (match_operand:VH 2 "register_operand" "f")]
483		   UNSPEC_LOONGSON_PMULHU))]
484  "TARGET_HARD_FLOAT && TARGET_LOONGSON_VECTORS"
485  "pmulhu<V_suffix>\t%0,%1,%2"
486  [(set_attr "type" "fmul")])
487
488;; Multiply signed integers and store high result.
489(define_insn "smul<mode>3_highpart"
490  [(set (match_operand:VH 0 "register_operand" "=f")
491        (unspec:VH [(match_operand:VH 1 "register_operand" "f")
492		    (match_operand:VH 2 "register_operand" "f")]
493		   UNSPEC_LOONGSON_PMULH))]
494  "TARGET_HARD_FLOAT && TARGET_LOONGSON_VECTORS"
495  "pmulh<V_suffix>\t%0,%1,%2"
496  [(set_attr "type" "fmul")])
497
498;; Multiply signed integers and store low result.
499(define_insn "mul<mode>3"
500  [(set (match_operand:VH 0 "register_operand" "=f")
501        (mult:VH (match_operand:VH 1 "register_operand" "f")
502                 (match_operand:VH 2 "register_operand" "f")))]
503  "TARGET_HARD_FLOAT && TARGET_LOONGSON_VECTORS"
504  "pmull<V_suffix>\t%0,%1,%2"
505  [(set_attr "type" "fmul")])
506
507;; Multiply unsigned word integers.
508(define_insn "loongson_pmulu<V_suffix>"
509  [(set (match_operand:DI 0 "register_operand" "=f")
510        (unspec:DI [(match_operand:VW 1 "register_operand" "f")
511		    (match_operand:VW 2 "register_operand" "f")]
512		   UNSPEC_LOONGSON_PMULU))]
513  "TARGET_HARD_FLOAT && TARGET_LOONGSON_VECTORS"
514  "pmulu<V_suffix>\t%0,%1,%2"
515  [(set_attr "type" "fmul")])
516
517;; Absolute difference.
518(define_insn "loongson_pasubub"
519  [(set (match_operand:VB 0 "register_operand" "=f")
520        (unspec:VB [(match_operand:VB 1 "register_operand" "f")
521		    (match_operand:VB 2 "register_operand" "f")]
522		   UNSPEC_LOONGSON_PASUBUB))]
523  "TARGET_HARD_FLOAT && TARGET_LOONGSON_VECTORS"
524  "pasubub\t%0,%1,%2"
525  [(set_attr "type" "fadd")])
526
527;; Sum of unsigned byte integers.
528(define_insn "loongson_biadd"
529  [(set (match_operand:<V_stretch_half> 0 "register_operand" "=f")
530        (unspec:<V_stretch_half> [(match_operand:VB 1 "register_operand" "f")]
531				 UNSPEC_LOONGSON_BIADD))]
532  "TARGET_HARD_FLOAT && TARGET_LOONGSON_VECTORS"
533  "biadd\t%0,%1"
534  [(set_attr "type" "fabs")])
535
536(define_insn "reduc_uplus_v8qi"
537  [(set (match_operand:V8QI 0 "register_operand" "=f")
538	(unspec:V8QI [(match_operand:V8QI 1 "register_operand" "f")]
539		     UNSPEC_LOONGSON_BIADD))]
540  "TARGET_HARD_FLOAT && TARGET_LOONGSON_VECTORS"
541  "biadd\t%0,%1"
542  [(set_attr "type" "fabs")])
543
544;; Sum of absolute differences.
545(define_insn "loongson_psadbh"
546  [(set (match_operand:<V_stretch_half> 0 "register_operand" "=f")
547        (unspec:<V_stretch_half> [(match_operand:VB 1 "register_operand" "f")
548				  (match_operand:VB 2 "register_operand" "f")]
549				 UNSPEC_LOONGSON_PSADBH))]
550  "TARGET_HARD_FLOAT && TARGET_LOONGSON_VECTORS"
551  "pasubub\t%0,%1,%2;biadd\t%0,%0"
552  [(set_attr "type" "fadd")])
553
554;; Shuffle halfwords.
555(define_insn "loongson_pshufh"
556  [(set (match_operand:VH 0 "register_operand" "=f")
557        (unspec:VH [(match_operand:VH 1 "register_operand" "f")
558		    (match_operand:SI 2 "register_operand" "f")]
559		   UNSPEC_LOONGSON_PSHUFH))]
560  "TARGET_HARD_FLOAT && TARGET_LOONGSON_VECTORS"
561  "pshufh\t%0,%1,%2"
562  [(set_attr "type" "fmul")])
563
564;; Shift left logical.
565(define_insn "ashl<mode>3"
566  [(set (match_operand:VWH 0 "register_operand" "=f")
567        (ashift:VWH (match_operand:VWH 1 "register_operand" "f")
568		    (match_operand:SI 2 "register_operand" "f")))]
569  "TARGET_HARD_FLOAT && TARGET_LOONGSON_VECTORS"
570  "psll<V_suffix>\t%0,%1,%2"
571  [(set_attr "type" "fcvt")])
572
573;; Shift right arithmetic.
574(define_insn "ashr<mode>3"
575  [(set (match_operand:VWH 0 "register_operand" "=f")
576        (ashiftrt:VWH (match_operand:VWH 1 "register_operand" "f")
577		      (match_operand:SI 2 "register_operand" "f")))]
578  "TARGET_HARD_FLOAT && TARGET_LOONGSON_VECTORS"
579  "psra<V_suffix>\t%0,%1,%2"
580  [(set_attr "type" "fcvt")])
581
582;; Shift right logical.
583(define_insn "lshr<mode>3"
584  [(set (match_operand:VWH 0 "register_operand" "=f")
585        (lshiftrt:VWH (match_operand:VWH 1 "register_operand" "f")
586		      (match_operand:SI 2 "register_operand" "f")))]
587  "TARGET_HARD_FLOAT && TARGET_LOONGSON_VECTORS"
588  "psrl<V_suffix>\t%0,%1,%2"
589  [(set_attr "type" "fcvt")])
590
591;; Subtraction, treating overflow by wraparound.
592(define_insn "sub<mode>3"
593  [(set (match_operand:VWHB 0 "register_operand" "=f")
594        (minus:VWHB (match_operand:VWHB 1 "register_operand" "f")
595		    (match_operand:VWHB 2 "register_operand" "f")))]
596  "TARGET_HARD_FLOAT && TARGET_LOONGSON_VECTORS"
597  "psub<V_suffix>\t%0,%1,%2"
598  [(set_attr "type" "fadd")])
599
600;; Subtraction of doubleword integers stored in FP registers.
601;; Overflow is treated by wraparound.
602;; See loongson_paddd for the reason we use 'unspec' rather than
603;; 'minus' here.
604(define_insn "loongson_psubd"
605  [(set (match_operand:DI 0 "register_operand" "=f")
606        (unspec:DI [(match_operand:DI 1 "register_operand" "f")
607		    (match_operand:DI 2 "register_operand" "f")]
608		   UNSPEC_LOONGSON_PSUBD))]
609  "TARGET_HARD_FLOAT && TARGET_LOONGSON_VECTORS"
610  "psubd\t%0,%1,%2"
611  [(set_attr "type" "fadd")])
612
613;; Subtraction, treating overflow by signed saturation.
614(define_insn "sssub<mode>3"
615  [(set (match_operand:VHB 0 "register_operand" "=f")
616        (ss_minus:VHB (match_operand:VHB 1 "register_operand" "f")
617		      (match_operand:VHB 2 "register_operand" "f")))]
618  "TARGET_HARD_FLOAT && TARGET_LOONGSON_VECTORS"
619  "psubs<V_suffix>\t%0,%1,%2"
620  [(set_attr "type" "fadd")])
621
622;; Subtraction, treating overflow by unsigned saturation.
623(define_insn "ussub<mode>3"
624  [(set (match_operand:VHB 0 "register_operand" "=f")
625        (us_minus:VHB (match_operand:VHB 1 "register_operand" "f")
626		      (match_operand:VHB 2 "register_operand" "f")))]
627  "TARGET_HARD_FLOAT && TARGET_LOONGSON_VECTORS"
628  "psubus<V_suffix>\t%0,%1,%2"
629  [(set_attr "type" "fadd")])
630
631;; Unpack high data.  Recall that Loongson only runs in little-endian.
632(define_insn "loongson_punpckhbh"
633  [(set (match_operand:V8QI 0 "register_operand" "=f")
634	(vec_select:V8QI
635	  (vec_concat:V16QI
636	    (match_operand:V8QI 1 "register_operand" "f")
637	    (match_operand:V8QI 2 "register_operand" "f"))
638	  (parallel [(const_int 4) (const_int 12)
639		     (const_int 5) (const_int 13)
640		     (const_int 6) (const_int 14)
641		     (const_int 7) (const_int 15)])))]
642  "TARGET_HARD_FLOAT && TARGET_LOONGSON_VECTORS"
643  "punpckhbh\t%0,%1,%2"
644  [(set_attr "type" "fdiv")])
645
646(define_insn "loongson_punpckhhw"
647  [(set (match_operand:V4HI 0 "register_operand" "=f")
648	(vec_select:V4HI
649	  (vec_concat:V8HI
650	    (match_operand:V4HI 1 "register_operand" "f")
651	    (match_operand:V4HI 2 "register_operand" "f"))
652	  (parallel [(const_int 2) (const_int 6)
653		     (const_int 3) (const_int 7)])))]
654  "TARGET_HARD_FLOAT && TARGET_LOONGSON_VECTORS"
655  "punpckhhw\t%0,%1,%2"
656  [(set_attr "type" "fdiv")])
657
658(define_insn "loongson_punpckhhw_qi"
659  [(set (match_operand:V8QI 0 "register_operand" "=f")
660	(vec_select:V8QI
661	  (vec_concat:V16QI
662	    (match_operand:V8QI 1 "register_operand" "f")
663	    (match_operand:V8QI 2 "register_operand" "f"))
664	  (parallel [(const_int 4)  (const_int 5)
665		     (const_int 12) (const_int 13)
666		     (const_int 6)  (const_int 7)
667		     (const_int 14) (const_int 15)])))]
668  "TARGET_HARD_FLOAT && TARGET_LOONGSON_VECTORS"
669  "punpckhhw\t%0,%1,%2"
670  [(set_attr "type" "fdiv")])
671
672(define_insn "loongson_punpckhwd"
673  [(set (match_operand:V2SI 0 "register_operand" "=f")
674	(vec_select:V2SI
675	  (vec_concat:V4SI
676	    (match_operand:V2SI 1 "register_operand" "f")
677	    (match_operand:V2SI 2 "register_operand" "f"))
678	  (parallel [(const_int 1) (const_int 3)])))]
679  "TARGET_HARD_FLOAT && TARGET_LOONGSON_VECTORS"
680  "punpckhwd\t%0,%1,%2"
681  [(set_attr "type" "fcvt")])
682
683(define_insn "loongson_punpckhwd_qi"
684  [(set (match_operand:V8QI 0 "register_operand" "=f")
685	(vec_select:V8QI
686	  (vec_concat:V16QI
687	    (match_operand:V8QI 1 "register_operand" "f")
688	    (match_operand:V8QI 2 "register_operand" "f"))
689	  (parallel [(const_int 4) (const_int 5)
690		     (const_int 6) (const_int 7)
691		     (const_int 12) (const_int 13)
692		     (const_int 14) (const_int 15)])))]
693  "TARGET_HARD_FLOAT && TARGET_LOONGSON_VECTORS"
694  "punpckhwd\t%0,%1,%2"
695  [(set_attr "type" "fcvt")])
696
697(define_insn "loongson_punpckhwd_hi"
698  [(set (match_operand:V4HI 0 "register_operand" "=f")
699	(vec_select:V4HI
700	  (vec_concat:V8HI
701	    (match_operand:V4HI 1 "register_operand" "f")
702	    (match_operand:V4HI 2 "register_operand" "f"))
703	  (parallel [(const_int 2) (const_int 3)
704		     (const_int 6) (const_int 7)])))]
705  "TARGET_HARD_FLOAT && TARGET_LOONGSON_VECTORS"
706  "punpckhwd\t%0,%1,%2"
707  [(set_attr "type" "fcvt")])
708
709;; Unpack low data.
710(define_insn "loongson_punpcklbh"
711  [(set (match_operand:V8QI 0 "register_operand" "=f")
712	(vec_select:V8QI
713	  (vec_concat:V16QI
714	    (match_operand:V8QI 1 "register_operand" "f")
715	    (match_operand:V8QI 2 "register_operand" "f"))
716	  (parallel [(const_int 0) (const_int 8)
717		     (const_int 1) (const_int 9)
718		     (const_int 2) (const_int 10)
719		     (const_int 3) (const_int 11)])))]
720  "TARGET_HARD_FLOAT && TARGET_LOONGSON_VECTORS"
721  "punpcklbh\t%0,%1,%2"
722  [(set_attr "type" "fdiv")])
723
724(define_insn "loongson_punpcklhw"
725  [(set (match_operand:V4HI 0 "register_operand" "=f")
726	(vec_select:V4HI
727	  (vec_concat:V8HI
728	    (match_operand:V4HI 1 "register_operand" "f")
729	    (match_operand:V4HI 2 "register_operand" "f"))
730	  (parallel [(const_int 0) (const_int 4)
731		     (const_int 1) (const_int 5)])))]
732  "TARGET_HARD_FLOAT && TARGET_LOONGSON_VECTORS"
733  "punpcklhw\t%0,%1,%2"
734  [(set_attr "type" "fdiv")])
735
736(define_insn "*loongson_punpcklhw_qi"
737  [(set (match_operand:V8QI 0 "register_operand" "=f")
738	(vec_select:V8QI
739	  (vec_concat:V16QI
740	    (match_operand:V8QI 1 "register_operand" "f")
741	    (match_operand:V8QI 2 "register_operand" "f"))
742	  (parallel [(const_int 0)  (const_int 1)
743		     (const_int 8)  (const_int 9)
744		     (const_int 2)  (const_int 3)
745		     (const_int 10) (const_int 11)])))]
746  "TARGET_HARD_FLOAT && TARGET_LOONGSON_VECTORS"
747  "punpcklhw\t%0,%1,%2"
748  [(set_attr "type" "fdiv")])
749
750(define_insn "loongson_punpcklwd"
751  [(set (match_operand:V2SI 0 "register_operand" "=f")
752	(vec_select:V2SI
753	  (vec_concat:V4SI
754	    (match_operand:V2SI 1 "register_operand" "f")
755	    (match_operand:V2SI 2 "register_operand" "f"))
756	  (parallel [(const_int 0) (const_int 2)])))]
757  "TARGET_HARD_FLOAT && TARGET_LOONGSON_VECTORS"
758  "punpcklwd\t%0,%1,%2"
759  [(set_attr "type" "fcvt")])
760
761(define_insn "*loongson_punpcklwd_qi"
762  [(set (match_operand:V8QI 0 "register_operand" "=f")
763	(vec_select:V8QI
764	  (vec_concat:V16QI
765	    (match_operand:V8QI 1 "register_operand" "f")
766	    (match_operand:V8QI 2 "register_operand" "f"))
767	  (parallel [(const_int 0) (const_int 1)
768		     (const_int 2) (const_int 3)
769		     (const_int 8) (const_int 9)
770		     (const_int 10) (const_int 11)])))]
771  "TARGET_HARD_FLOAT && TARGET_LOONGSON_VECTORS"
772  "punpcklwd\t%0,%1,%2"
773  [(set_attr "type" "fcvt")])
774
775(define_insn "*loongson_punpcklwd_hi"
776  [(set (match_operand:V4HI 0 "register_operand" "=f")
777	(vec_select:V4HI
778	  (vec_concat:V8HI
779	    (match_operand:V4HI 1 "register_operand" "f")
780	    (match_operand:V4HI 2 "register_operand" "f"))
781	  (parallel [(const_int 0) (const_int 1)
782		     (const_int 4) (const_int 5)])))]
783  "TARGET_HARD_FLOAT && TARGET_LOONGSON_VECTORS"
784  "punpcklwd\t%0,%1,%2"
785  [(set_attr "type" "fcvt")])
786
787(define_expand "vec_perm_const<mode>"
788  [(match_operand:VWHB 0 "register_operand" "")
789   (match_operand:VWHB 1 "register_operand" "")
790   (match_operand:VWHB 2 "register_operand" "")
791   (match_operand:VWHB 3 "" "")]
792  "TARGET_HARD_FLOAT && TARGET_LOONGSON_VECTORS"
793{
794  if (mips_expand_vec_perm_const (operands))
795    DONE;
796  else
797    FAIL;
798})
799
800(define_expand "vec_unpacks_lo_<mode>"
801  [(match_operand:<V_stretch_half> 0 "register_operand" "")
802   (match_operand:VHB 1 "register_operand" "")]
803  "TARGET_HARD_FLOAT && TARGET_LOONGSON_VECTORS"
804{
805  mips_expand_vec_unpack (operands, false, false);
806  DONE;
807})
808
809(define_expand "vec_unpacks_hi_<mode>"
810  [(match_operand:<V_stretch_half> 0 "register_operand" "")
811   (match_operand:VHB 1 "register_operand" "")]
812  "TARGET_HARD_FLOAT && TARGET_LOONGSON_VECTORS"
813{
814  mips_expand_vec_unpack (operands, false, true);
815  DONE;
816})
817
818(define_expand "vec_unpacku_lo_<mode>"
819  [(match_operand:<V_stretch_half> 0 "register_operand" "")
820   (match_operand:VHB 1 "register_operand" "")]
821  "TARGET_HARD_FLOAT && TARGET_LOONGSON_VECTORS"
822{
823  mips_expand_vec_unpack (operands, true, false);
824  DONE;
825})
826
827(define_expand "vec_unpacku_hi_<mode>"
828  [(match_operand:<V_stretch_half> 0 "register_operand" "")
829   (match_operand:VHB 1 "register_operand" "")]
830  "TARGET_HARD_FLOAT && TARGET_LOONGSON_VECTORS"
831{
832  mips_expand_vec_unpack (operands, true, true);
833  DONE;
834})
835
836;; Whole vector shifts, used for reduction epilogues.
837(define_insn "vec_shl_<mode>"
838  [(set (match_operand:VWHBDI 0 "register_operand" "=f")
839        (unspec:VWHBDI [(match_operand:VWHBDI 1 "register_operand" "f")
840                        (match_operand:SI 2 "register_operand" "f")]
841                       UNSPEC_LOONGSON_DSLL))]
842  "TARGET_HARD_FLOAT && TARGET_LOONGSON_VECTORS"
843  "dsll\t%0,%1,%2"
844  [(set_attr "type" "fcvt")])
845
846(define_insn "vec_shr_<mode>"
847  [(set (match_operand:VWHBDI 0 "register_operand" "=f")
848        (unspec:VWHBDI [(match_operand:VWHBDI 1 "register_operand" "f")
849                        (match_operand:SI 2 "register_operand" "f")]
850                       UNSPEC_LOONGSON_DSRL))]
851  "TARGET_HARD_FLOAT && TARGET_LOONGSON_VECTORS"
852  "dsrl\t%0,%1,%2"
853  [(set_attr "type" "fcvt")])
854
855(define_expand "reduc_uplus_<mode>"
856  [(match_operand:VWH 0 "register_operand" "")
857   (match_operand:VWH 1 "register_operand" "")]
858  "TARGET_HARD_FLOAT && TARGET_LOONGSON_VECTORS"
859{
860  mips_expand_vec_reduc (operands[0], operands[1], gen_add<mode>3);
861  DONE;
862})
863
864; ??? Given that we're not describing a widening reduction, we should
865; not have separate optabs for signed and unsigned.
866(define_expand "reduc_splus_<mode>"
867  [(match_operand:VWHB 0 "register_operand" "")
868   (match_operand:VWHB 1 "register_operand" "")]
869  "TARGET_HARD_FLOAT && TARGET_LOONGSON_VECTORS"
870{
871  emit_insn (gen_reduc_uplus_<mode>(operands[0], operands[1]));
872  DONE;
873})
874
875(define_expand "reduc_smax_<mode>"
876  [(match_operand:VWHB 0 "register_operand" "")
877   (match_operand:VWHB 1 "register_operand" "")]
878  "TARGET_HARD_FLOAT && TARGET_LOONGSON_VECTORS"
879{
880  mips_expand_vec_reduc (operands[0], operands[1], gen_smax<mode>3);
881  DONE;
882})
883
884(define_expand "reduc_smin_<mode>"
885  [(match_operand:VWHB 0 "register_operand" "")
886   (match_operand:VWHB 1 "register_operand" "")]
887  "TARGET_HARD_FLOAT && TARGET_LOONGSON_VECTORS"
888{
889  mips_expand_vec_reduc (operands[0], operands[1], gen_smin<mode>3);
890  DONE;
891})
892
893(define_expand "reduc_umax_<mode>"
894  [(match_operand:VB 0 "register_operand" "")
895   (match_operand:VB 1 "register_operand" "")]
896  "TARGET_HARD_FLOAT && TARGET_LOONGSON_VECTORS"
897{
898  mips_expand_vec_reduc (operands[0], operands[1], gen_umax<mode>3);
899  DONE;
900})
901
902(define_expand "reduc_umin_<mode>"
903  [(match_operand:VB 0 "register_operand" "")
904   (match_operand:VB 1 "register_operand" "")]
905  "TARGET_HARD_FLOAT && TARGET_LOONGSON_VECTORS"
906{
907  mips_expand_vec_reduc (operands[0], operands[1], gen_umin<mode>3);
908  DONE;
909})
910