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