1;; Decimal Floating Point (DFP) patterns.
2;; Copyright (C) 2007-2020 Free Software Foundation, Inc.
3;; Contributed by Ben Elliston (bje@au.ibm.com) and Peter Bergner
4;; (bergner@vnet.ibm.com).
5
6;; This file is part of GCC.
7
8;; GCC is free software; you can redistribute it and/or modify it
9;; under the terms of the GNU General Public License as published
10;; by the Free Software Foundation; either version 3, or (at your
11;; option) any later version.
12
13;; GCC is distributed in the hope that it will be useful, but WITHOUT
14;; ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
15;; or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public
16;; 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;;
23;; UNSPEC usage
24;;
25
26(define_c_enum "unspec"
27  [UNSPEC_MOVSD_LOAD
28   UNSPEC_MOVSD_STORE
29  ])
30
31; Either of the two decimal modes.
32(define_mode_iterator DDTD [DD TD])
33
34(define_mode_attr q [(DD "") (TD "q")])
35
36
37(define_insn "movsd_store"
38  [(set (match_operand:DD 0 "nonimmediate_operand" "=m")
39	(unspec:DD [(match_operand:SD 1 "input_operand" "d")]
40		   UNSPEC_MOVSD_STORE))]
41  "(gpc_reg_operand (operands[0], DDmode)
42   || gpc_reg_operand (operands[1], SDmode))
43   && TARGET_HARD_FLOAT"
44  "stfd%U0%X0 %1,%0"
45  [(set_attr "type" "fpstore")])
46
47(define_insn "movsd_load"
48  [(set (match_operand:SD 0 "nonimmediate_operand" "=f")
49	(unspec:SD [(match_operand:DD 1 "input_operand" "m")]
50		   UNSPEC_MOVSD_LOAD))]
51  "(gpc_reg_operand (operands[0], SDmode)
52   || gpc_reg_operand (operands[1], DDmode))
53   && TARGET_HARD_FLOAT"
54  "lfd%U1%X1 %0,%1"
55  [(set_attr "type" "fpload")])
56
57;; Hardware support for decimal floating point operations.
58
59(define_insn "extendsddd2"
60  [(set (match_operand:DD 0 "gpc_reg_operand" "=d")
61	(float_extend:DD (match_operand:SD 1 "gpc_reg_operand" "f")))]
62  "TARGET_DFP"
63  "dctdp %0,%1"
64  [(set_attr "type" "dfp")])
65
66(define_expand "extendsdtd2"
67  [(set (match_operand:TD 0 "gpc_reg_operand" "=d")
68	(float_extend:TD (match_operand:SD 1 "gpc_reg_operand" "d")))]
69  "TARGET_DFP"
70{
71  rtx tmp = gen_reg_rtx (DDmode);
72  emit_insn (gen_extendsddd2 (tmp, operands[1]));
73  emit_insn (gen_extendddtd2 (operands[0], tmp));
74  DONE;
75})
76
77(define_insn "truncddsd2"
78  [(set (match_operand:SD 0 "gpc_reg_operand" "=f")
79	(float_truncate:SD (match_operand:DD 1 "gpc_reg_operand" "d")))]
80  "TARGET_DFP"
81  "drsp %0,%1"
82  [(set_attr "type" "dfp")])
83
84(define_insn "negdd2"
85  [(set (match_operand:DD 0 "gpc_reg_operand" "=d")
86	(neg:DD (match_operand:DD 1 "gpc_reg_operand" "d")))]
87  "TARGET_HARD_FLOAT"
88  "fneg %0,%1"
89  [(set_attr "type" "fpsimple")])
90
91(define_insn "absdd2"
92  [(set (match_operand:DD 0 "gpc_reg_operand" "=d")
93	(abs:DD (match_operand:DD 1 "gpc_reg_operand" "d")))]
94  "TARGET_HARD_FLOAT"
95  "fabs %0,%1"
96  [(set_attr "type" "fpsimple")])
97
98(define_insn "*nabsdd2_fpr"
99  [(set (match_operand:DD 0 "gpc_reg_operand" "=d")
100	(neg:DD (abs:DD (match_operand:DD 1 "gpc_reg_operand" "d"))))]
101  "TARGET_HARD_FLOAT"
102  "fnabs %0,%1"
103  [(set_attr "type" "fpsimple")])
104
105(define_insn "negtd2"
106  [(set (match_operand:TD 0 "gpc_reg_operand" "=d,d")
107	(neg:TD (match_operand:TD 1 "gpc_reg_operand" "0,d")))]
108  "TARGET_HARD_FLOAT"
109  "@
110   fneg %0,%1
111   fneg %0,%1\;fmr %L0,%L1"
112  [(set_attr "type" "fpsimple")
113   (set_attr "length" "4,8")])
114
115(define_insn "abstd2"
116  [(set (match_operand:TD 0 "gpc_reg_operand" "=d,d")
117	(abs:TD (match_operand:TD 1 "gpc_reg_operand" "0,d")))]
118  "TARGET_HARD_FLOAT"
119  "@
120   fabs %0,%1
121   fabs %0,%1\;fmr %L0,%L1"
122  [(set_attr "type" "fpsimple")
123   (set_attr "length" "4,8")])
124
125(define_insn "*nabstd2_fpr"
126  [(set (match_operand:TD 0 "gpc_reg_operand" "=d,d")
127	(neg:TD (abs:TD (match_operand:TD 1 "gpc_reg_operand" "0,d"))))]
128  "TARGET_HARD_FLOAT"
129  "@
130   fnabs %0,%1
131   fnabs %0,%1\;fmr %L0,%L1"
132  [(set_attr "type" "fpsimple")
133   (set_attr "length" "4,8")])
134
135;; Hardware support for decimal floating point operations.
136
137(define_insn "extendddtd2"
138  [(set (match_operand:TD 0 "gpc_reg_operand" "=d")
139	(float_extend:TD (match_operand:DD 1 "gpc_reg_operand" "d")))]
140  "TARGET_DFP"
141  "dctqpq %0,%1"
142  [(set_attr "type" "dfp")])
143
144;; The result of drdpq is an even/odd register pair with the converted
145;; value in the even register and zero in the odd register.
146;; FIXME: Avoid the register move by using a reload constraint to ensure
147;; that the result is the first of the pair receiving the result of drdpq.
148
149(define_insn "trunctddd2"
150  [(set (match_operand:DD 0 "gpc_reg_operand" "=d")
151	(float_truncate:DD (match_operand:TD 1 "gpc_reg_operand" "d")))
152   (clobber (match_scratch:TD 2 "=d"))]
153  "TARGET_DFP"
154  "drdpq %2,%1\;fmr %0,%2"
155  [(set_attr "type" "dfp")
156   (set_attr "length" "8")])
157
158(define_insn "add<mode>3"
159  [(set (match_operand:DDTD 0 "gpc_reg_operand" "=d")
160	(plus:DDTD (match_operand:DDTD 1 "gpc_reg_operand" "%d")
161		   (match_operand:DDTD 2 "gpc_reg_operand" "d")))]
162  "TARGET_DFP"
163  "dadd<q> %0,%1,%2"
164  [(set_attr "type" "dfp")])
165
166(define_insn "sub<mode>3"
167  [(set (match_operand:DDTD 0 "gpc_reg_operand" "=d")
168	(minus:DDTD (match_operand:DDTD 1 "gpc_reg_operand" "d")
169		    (match_operand:DDTD 2 "gpc_reg_operand" "d")))]
170  "TARGET_DFP"
171  "dsub<q> %0,%1,%2"
172  [(set_attr "type" "dfp")])
173
174(define_insn "mul<mode>3"
175  [(set (match_operand:DDTD 0 "gpc_reg_operand" "=d")
176	(mult:DDTD (match_operand:DDTD 1 "gpc_reg_operand" "%d")
177		   (match_operand:DDTD 2 "gpc_reg_operand" "d")))]
178  "TARGET_DFP"
179  "dmul<q> %0,%1,%2"
180  [(set_attr "type" "dfp")])
181
182(define_insn "div<mode>3"
183  [(set (match_operand:DDTD 0 "gpc_reg_operand" "=d")
184	(div:DDTD (match_operand:DDTD 1 "gpc_reg_operand" "d")
185		  (match_operand:DDTD 2 "gpc_reg_operand" "d")))]
186  "TARGET_DFP"
187  "ddiv<q> %0,%1,%2"
188  [(set_attr "type" "dfp")])
189
190(define_insn "*cmp<mode>_internal1"
191  [(set (match_operand:CCFP 0 "cc_reg_operand" "=y")
192	(compare:CCFP (match_operand:DDTD 1 "gpc_reg_operand" "d")
193		      (match_operand:DDTD 2 "gpc_reg_operand" "d")))]
194  "TARGET_DFP"
195  "dcmpu<q> %0,%1,%2"
196  [(set_attr "type" "dfp")])
197
198(define_insn "floatdidd2"
199  [(set (match_operand:DD 0 "gpc_reg_operand" "=d")
200	(float:DD (match_operand:DI 1 "gpc_reg_operand" "d")))]
201  "TARGET_DFP && TARGET_POPCNTD"
202  "dcffix %0,%1"
203  [(set_attr "type" "dfp")])
204
205(define_insn "floatditd2"
206  [(set (match_operand:TD 0 "gpc_reg_operand" "=d")
207	(float:TD (match_operand:DI 1 "gpc_reg_operand" "d")))]
208  "TARGET_DFP"
209  "dcffixq %0,%1"
210  [(set_attr "type" "dfp")])
211
212;; Convert a decimal64/128 to a decimal64/128 whose value is an integer.
213;; This is the first stage of converting it to an integer type.
214
215(define_insn "ftrunc<mode>2"
216  [(set (match_operand:DDTD 0 "gpc_reg_operand" "=d")
217	(fix:DDTD (match_operand:DDTD 1 "gpc_reg_operand" "d")))]
218  "TARGET_DFP"
219  "drintn<q>. 0,%0,%1,1"
220  [(set_attr "type" "dfp")])
221
222;; Convert a decimal64/128 whose value is an integer to an actual integer.
223;; This is the second stage of converting decimal float to integer type.
224
225(define_insn "fix<mode>di2"
226  [(set (match_operand:DI 0 "gpc_reg_operand" "=d")
227	(fix:DI (match_operand:DDTD 1 "gpc_reg_operand" "d")))]
228  "TARGET_DFP"
229  "dctfix<q> %0,%1"
230  [(set_attr "type" "dfp")])
231
232;; Decimal builtin support
233
234(define_c_enum "unspec"
235  [UNSPEC_DDEDPD
236   UNSPEC_DENBCD
237   UNSPEC_DXEX
238   UNSPEC_DIEX
239   UNSPEC_DSCLI
240   UNSPEC_DTSTSFI
241   UNSPEC_DSCRI])
242
243(define_code_iterator DFP_TEST [eq lt gt unordered])
244
245(define_insn "dfp_ddedpd_<mode>"
246  [(set (match_operand:DDTD 0 "gpc_reg_operand" "=d")
247	(unspec:DDTD [(match_operand:QI 1 "const_0_to_3_operand" "i")
248		      (match_operand:DDTD 2 "gpc_reg_operand" "d")]
249		     UNSPEC_DDEDPD))]
250  "TARGET_DFP"
251  "ddedpd<q> %1,%0,%2"
252  [(set_attr "type" "dfp")])
253
254(define_insn "dfp_denbcd_<mode>"
255  [(set (match_operand:DDTD 0 "gpc_reg_operand" "=d")
256	(unspec:DDTD [(match_operand:QI 1 "const_0_to_1_operand" "i")
257		      (match_operand:DDTD 2 "gpc_reg_operand" "d")]
258		     UNSPEC_DENBCD))]
259  "TARGET_DFP"
260  "denbcd<q> %1,%0,%2"
261  [(set_attr "type" "dfp")])
262
263(define_insn "dfp_dxex_<mode>"
264  [(set (match_operand:DI 0 "gpc_reg_operand" "=d")
265	(unspec:DI [(match_operand:DDTD 1 "gpc_reg_operand" "d")]
266		   UNSPEC_DXEX))]
267  "TARGET_DFP"
268  "dxex<q> %0,%1"
269  [(set_attr "type" "dfp")])
270
271(define_insn "dfp_diex_<mode>"
272  [(set (match_operand:DDTD 0 "gpc_reg_operand" "=d")
273	(unspec:DDTD [(match_operand:DI 1 "gpc_reg_operand" "d")
274		      (match_operand:DDTD 2 "gpc_reg_operand" "d")]
275		     UNSPEC_DXEX))]
276  "TARGET_DFP"
277  "diex<q> %0,%1,%2"
278  [(set_attr "type" "dfp")])
279
280(define_expand "dfptstsfi_<code>_<mode>"
281  [(set (match_dup 3)
282	(compare:CCFP (unspec:DDTD [(match_operand:SI 1 "const_int_operand")
283				    (match_operand:DDTD 2 "gpc_reg_operand")]
284				   UNSPEC_DTSTSFI)
285		      (const_int 0)))
286   (set (match_operand:SI 0 "register_operand")
287	(DFP_TEST:SI (match_dup 3)
288		     (const_int 0)))
289  ]
290  "TARGET_P9_MISC"
291{
292  if (<CODE> == UNORDERED && !HONOR_NANS (<MODE>mode))
293    {
294      emit_move_insn (operands[0], const0_rtx);
295      DONE;
296    }
297
298  operands[3] = gen_reg_rtx (CCFPmode);
299})
300
301(define_insn "*dfp_sgnfcnc_<mode>"
302  [(set (match_operand:CCFP 0 "" "=y")
303	(compare:CCFP
304	 (unspec:DDTD [(match_operand:SI 1 "const_int_operand" "n")
305		       (match_operand:DDTD 2 "gpc_reg_operand" "d")]
306		      UNSPEC_DTSTSFI)
307	 (match_operand:SI 3 "zero_constant" "j")))]
308  "TARGET_P9_MISC"
309{
310  /* If immediate operand is greater than 63, it will behave as if
311     the value had been 63.  The code generator does not support
312     immediate operand values greater than 63.  */
313  if (!(IN_RANGE (INTVAL (operands[1]), 0, 63)))
314    operands[1] = GEN_INT (63);
315  return "dtstsfi<q> %0,%1,%2";
316}
317  [(set_attr "type" "fp")])
318
319(define_insn "dfp_dscli_<mode>"
320  [(set (match_operand:DDTD 0 "gpc_reg_operand" "=d")
321	(unspec:DDTD [(match_operand:DDTD 1 "gpc_reg_operand" "d")
322		      (match_operand:QI 2 "immediate_operand" "i")]
323		     UNSPEC_DSCLI))]
324  "TARGET_DFP"
325  "dscli<q> %0,%1,%2"
326  [(set_attr "type" "dfp")])
327
328(define_insn "dfp_dscri_<mode>"
329  [(set (match_operand:DDTD 0 "gpc_reg_operand" "=d")
330	(unspec:DDTD [(match_operand:DDTD 1 "gpc_reg_operand" "d")
331		      (match_operand:QI 2 "immediate_operand" "i")]
332		     UNSPEC_DSCRI))]
333  "TARGET_DFP"
334  "dscri<q> %0,%1,%2"
335  [(set_attr "type" "dfp")])
336