1 ;; Decimal Floating Point (DFP) patterns.
2 ;; Copyright (C) 2007-2012 Free Software Foundation, Inc.
3 ;; Contributed by Ben Elliston (bje@au.ibm.com) and Peter Bergner
4 ;; (bergner@vnet.ibm.com).
6 ;; This file is part of GCC.
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.
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.
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/>.
26 (define_c_enum "unspec"
32 (define_expand "movsd"
33 [(set (match_operand:SD 0 "nonimmediate_operand" "")
34 (match_operand:SD 1 "any_operand" ""))]
35 "TARGET_HARD_FLOAT && TARGET_FPRS"
36 "{ rs6000_emit_move (operands[0], operands[1], SDmode); DONE; }")
39 [(set (match_operand:SD 0 "gpc_reg_operand" "")
40 (match_operand:SD 1 "const_double_operand" ""))]
42 && ((GET_CODE (operands[0]) == REG && REGNO (operands[0]) <= 31)
43 || (GET_CODE (operands[0]) == SUBREG
44 && GET_CODE (SUBREG_REG (operands[0])) == REG
45 && REGNO (SUBREG_REG (operands[0])) <= 31))"
46 [(set (match_dup 2) (match_dup 3))]
52 REAL_VALUE_FROM_CONST_DOUBLE (rv, operands[1]);
53 REAL_VALUE_TO_TARGET_DECIMAL32 (rv, l);
55 if (! TARGET_POWERPC64)
56 operands[2] = operand_subword (operands[0], 0, 0, SDmode);
58 operands[2] = gen_lowpart (SImode, operands[0]);
60 operands[3] = gen_int_mode (l, SImode);
63 (define_insn "movsd_hardfloat"
64 [(set (match_operand:SD 0 "nonimmediate_operand" "=r,r,m,f,*c*l,!r,*h,!r,!r")
65 (match_operand:SD 1 "input_operand" "r,m,r,f,r,h,0,G,Fn"))]
66 "(gpc_reg_operand (operands[0], SDmode)
67 || gpc_reg_operand (operands[1], SDmode))
68 && (TARGET_HARD_FLOAT && TARGET_FPRS)"
79 [(set_attr "type" "*,load,store,fp,mtjmpr,mfjmpr,*,*,*")
80 (set_attr "length" "4,4,4,4,4,4,4,4,8")])
82 (define_insn "movsd_softfloat"
83 [(set (match_operand:SD 0 "nonimmediate_operand" "=r,cl,r,r,m,r,r,r,r,r,*h")
84 (match_operand:SD 1 "input_operand" "r,r,h,m,r,I,L,R,G,Fn,0"))]
85 "(gpc_reg_operand (operands[0], SDmode)
86 || gpc_reg_operand (operands[1], SDmode))
87 && (TARGET_SOFT_FLOAT || !TARGET_FPRS)"
100 [(set_attr "type" "*,mtjmpr,mfjmpr,load,store,*,*,*,*,*,*")
101 (set_attr "length" "4,4,4,4,4,4,4,4,4,8,4")])
103 (define_insn "movsd_store"
104 [(set (match_operand:DD 0 "nonimmediate_operand" "=m")
105 (unspec:DD [(match_operand:SD 1 "input_operand" "d")]
106 UNSPEC_MOVSD_STORE))]
107 "(gpc_reg_operand (operands[0], DDmode)
108 || gpc_reg_operand (operands[1], SDmode))
109 && TARGET_HARD_FLOAT && TARGET_FPRS"
111 [(set_attr "type" "fpstore")
112 (set_attr "length" "4")])
114 (define_insn "movsd_load"
115 [(set (match_operand:SD 0 "nonimmediate_operand" "=f")
116 (unspec:SD [(match_operand:DD 1 "input_operand" "m")]
118 "(gpc_reg_operand (operands[0], SDmode)
119 || gpc_reg_operand (operands[1], DDmode))
120 && TARGET_HARD_FLOAT && TARGET_FPRS"
122 [(set_attr "type" "fpload")
123 (set_attr "length" "4")])
125 ;; Hardware support for decimal floating point operations.
127 (define_insn "extendsddd2"
128 [(set (match_operand:DD 0 "gpc_reg_operand" "=d")
129 (float_extend:DD (match_operand:SD 1 "gpc_reg_operand" "f")))]
132 [(set_attr "type" "fp")])
134 (define_expand "extendsdtd2"
135 [(set (match_operand:TD 0 "gpc_reg_operand" "=d")
136 (float_extend:TD (match_operand:SD 1 "gpc_reg_operand" "d")))]
139 rtx tmp = gen_reg_rtx (DDmode);
140 emit_insn (gen_extendsddd2 (tmp, operands[1]));
141 emit_insn (gen_extendddtd2 (operands[0], tmp));
145 (define_insn "truncddsd2"
146 [(set (match_operand:SD 0 "gpc_reg_operand" "=f")
147 (float_truncate:SD (match_operand:DD 1 "gpc_reg_operand" "d")))]
150 [(set_attr "type" "fp")])
152 (define_expand "negdd2"
153 [(set (match_operand:DD 0 "gpc_reg_operand" "")
154 (neg:DD (match_operand:DD 1 "gpc_reg_operand" "")))]
155 "TARGET_HARD_FLOAT && TARGET_FPRS"
158 (define_insn "*negdd2_fpr"
159 [(set (match_operand:DD 0 "gpc_reg_operand" "=d")
160 (neg:DD (match_operand:DD 1 "gpc_reg_operand" "d")))]
161 "TARGET_HARD_FLOAT && TARGET_FPRS"
163 [(set_attr "type" "fp")])
165 (define_expand "absdd2"
166 [(set (match_operand:DD 0 "gpc_reg_operand" "")
167 (abs:DD (match_operand:DD 1 "gpc_reg_operand" "")))]
168 "TARGET_HARD_FLOAT && TARGET_FPRS"
171 (define_insn "*absdd2_fpr"
172 [(set (match_operand:DD 0 "gpc_reg_operand" "=d")
173 (abs:DD (match_operand:DD 1 "gpc_reg_operand" "d")))]
174 "TARGET_HARD_FLOAT && TARGET_FPRS"
176 [(set_attr "type" "fp")])
178 (define_insn "*nabsdd2_fpr"
179 [(set (match_operand:DD 0 "gpc_reg_operand" "=d")
180 (neg:DD (abs:DD (match_operand:DD 1 "gpc_reg_operand" "d"))))]
181 "TARGET_HARD_FLOAT && TARGET_FPRS"
183 [(set_attr "type" "fp")])
185 (define_expand "movdd"
186 [(set (match_operand:DD 0 "nonimmediate_operand" "")
187 (match_operand:DD 1 "any_operand" ""))]
189 "{ rs6000_emit_move (operands[0], operands[1], DDmode); DONE; }")
192 [(set (match_operand:DD 0 "gpc_reg_operand" "")
193 (match_operand:DD 1 "const_int_operand" ""))]
194 "! TARGET_POWERPC64 && reload_completed
195 && ((GET_CODE (operands[0]) == REG && REGNO (operands[0]) <= 31)
196 || (GET_CODE (operands[0]) == SUBREG
197 && GET_CODE (SUBREG_REG (operands[0])) == REG
198 && REGNO (SUBREG_REG (operands[0])) <= 31))"
199 [(set (match_dup 2) (match_dup 4))
200 (set (match_dup 3) (match_dup 1))]
203 int endian = (WORDS_BIG_ENDIAN == 0);
204 HOST_WIDE_INT value = INTVAL (operands[1]);
206 operands[2] = operand_subword (operands[0], endian, 0, DDmode);
207 operands[3] = operand_subword (operands[0], 1 - endian, 0, DDmode);
208 #if HOST_BITS_PER_WIDE_INT == 32
209 operands[4] = (value & 0x80000000) ? constm1_rtx : const0_rtx;
211 operands[4] = GEN_INT (value >> 32);
212 operands[1] = GEN_INT (((value & 0xffffffff) ^ 0x80000000) - 0x80000000);
217 [(set (match_operand:DD 0 "gpc_reg_operand" "")
218 (match_operand:DD 1 "const_double_operand" ""))]
219 "! TARGET_POWERPC64 && reload_completed
220 && ((GET_CODE (operands[0]) == REG && REGNO (operands[0]) <= 31)
221 || (GET_CODE (operands[0]) == SUBREG
222 && GET_CODE (SUBREG_REG (operands[0])) == REG
223 && REGNO (SUBREG_REG (operands[0])) <= 31))"
224 [(set (match_dup 2) (match_dup 4))
225 (set (match_dup 3) (match_dup 5))]
228 int endian = (WORDS_BIG_ENDIAN == 0);
232 REAL_VALUE_FROM_CONST_DOUBLE (rv, operands[1]);
233 REAL_VALUE_TO_TARGET_DECIMAL64 (rv, l);
235 operands[2] = operand_subword (operands[0], endian, 0, DDmode);
236 operands[3] = operand_subword (operands[0], 1 - endian, 0, DDmode);
237 operands[4] = gen_int_mode (l[endian], SImode);
238 operands[5] = gen_int_mode (l[1 - endian], SImode);
242 [(set (match_operand:DD 0 "gpc_reg_operand" "")
243 (match_operand:DD 1 "const_double_operand" ""))]
244 "TARGET_POWERPC64 && reload_completed
245 && ((GET_CODE (operands[0]) == REG && REGNO (operands[0]) <= 31)
246 || (GET_CODE (operands[0]) == SUBREG
247 && GET_CODE (SUBREG_REG (operands[0])) == REG
248 && REGNO (SUBREG_REG (operands[0])) <= 31))"
249 [(set (match_dup 2) (match_dup 3))]
252 int endian = (WORDS_BIG_ENDIAN == 0);
255 #if HOST_BITS_PER_WIDE_INT >= 64
259 REAL_VALUE_FROM_CONST_DOUBLE (rv, operands[1]);
260 REAL_VALUE_TO_TARGET_DECIMAL64 (rv, l);
262 operands[2] = gen_lowpart (DImode, operands[0]);
263 /* HIGHPART is lower memory address when WORDS_BIG_ENDIAN. */
264 #if HOST_BITS_PER_WIDE_INT >= 64
265 val = ((HOST_WIDE_INT)(unsigned long)l[endian] << 32
266 | ((HOST_WIDE_INT)(unsigned long)l[1 - endian]));
268 operands[3] = gen_int_mode (val, DImode);
270 operands[3] = immed_double_const (l[1 - endian], l[endian], DImode);
274 ;; Don't have reload use general registers to load a constant. First,
275 ;; it might not work if the output operand is the equivalent of
276 ;; a non-offsettable memref, but also it is less efficient than loading
277 ;; the constant into an FP register, since it will probably be used there.
278 ;; The "??" is a kludge until we can figure out a more reasonable way
279 ;; of handling these non-offsettable values.
280 (define_insn "*movdd_hardfloat32"
281 [(set (match_operand:DD 0 "nonimmediate_operand" "=!r,??r,m,d,d,m,!r,!r,!r")
282 (match_operand:DD 1 "input_operand" "r,m,r,d,m,d,G,H,F"))]
283 "! TARGET_POWERPC64 && TARGET_HARD_FLOAT && TARGET_FPRS
284 && (gpc_reg_operand (operands[0], DDmode)
285 || gpc_reg_operand (operands[1], DDmode))"
288 switch (which_alternative)
297 return \"fmr %0,%1\";
299 return \"lfd%U1%X1 %0,%1\";
301 return \"stfd%U0%X0 %1,%0\";
308 [(set_attr "type" "two,load,store,fp,fpload,fpstore,*,*,*")
309 (set_attr "length" "8,16,16,4,4,4,8,12,16")])
311 (define_insn "*movdd_softfloat32"
312 [(set (match_operand:DD 0 "nonimmediate_operand" "=r,r,m,r,r,r")
313 (match_operand:DD 1 "input_operand" "r,m,r,G,H,F"))]
314 "! TARGET_POWERPC64 && (TARGET_SOFT_FLOAT || !TARGET_FPRS)
315 && (gpc_reg_operand (operands[0], DDmode)
316 || gpc_reg_operand (operands[1], DDmode))"
318 [(set_attr "type" "two,load,store,*,*,*")
319 (set_attr "length" "8,8,8,8,12,16")])
321 ; ld/std require word-aligned displacements -> 'Y' constraint.
322 ; List Y->r and r->Y before r->r for reload.
323 (define_insn "*movdd_hardfloat64_mfpgpr"
324 [(set (match_operand:DD 0 "nonimmediate_operand" "=Y,r,!r,d,d,m,*c*l,!r,*h,!r,!r,!r,r,d")
325 (match_operand:DD 1 "input_operand" "r,Y,r,d,m,d,r,h,0,G,H,F,d,r"))]
326 "TARGET_POWERPC64 && TARGET_MFPGPR && TARGET_HARD_FLOAT && TARGET_FPRS
327 && (gpc_reg_operand (operands[0], DDmode)
328 || gpc_reg_operand (operands[1], DDmode))"
344 [(set_attr "type" "store,load,*,fp,fpload,fpstore,mtjmpr,mfjmpr,*,*,*,*,mftgpr,mffgpr")
345 (set_attr "length" "4,4,4,4,4,4,4,4,4,8,12,16,4,4")])
347 ; ld/std require word-aligned displacements -> 'Y' constraint.
348 ; List Y->r and r->Y before r->r for reload.
349 (define_insn "*movdd_hardfloat64"
350 [(set (match_operand:DD 0 "nonimmediate_operand" "=Y,r,!r,d,d,m,*c*l,!r,*h,!r,!r,!r")
351 (match_operand:DD 1 "input_operand" "r,Y,r,d,m,d,r,h,0,G,H,F"))]
352 "TARGET_POWERPC64 && !TARGET_MFPGPR && TARGET_HARD_FLOAT && TARGET_FPRS
353 && (gpc_reg_operand (operands[0], DDmode)
354 || gpc_reg_operand (operands[1], DDmode))"
368 [(set_attr "type" "store,load,*,fp,fpload,fpstore,mtjmpr,mfjmpr,*,*,*,*")
369 (set_attr "length" "4,4,4,4,4,4,4,4,4,8,12,16")])
371 (define_insn "*movdd_softfloat64"
372 [(set (match_operand:DD 0 "nonimmediate_operand" "=r,Y,r,cl,r,r,r,r,*h")
373 (match_operand:DD 1 "input_operand" "Y,r,r,r,h,G,H,F,0"))]
374 "TARGET_POWERPC64 && (TARGET_SOFT_FLOAT || !TARGET_FPRS)
375 && (gpc_reg_operand (operands[0], DDmode)
376 || gpc_reg_operand (operands[1], DDmode))"
387 [(set_attr "type" "load,store,*,mtjmpr,mfjmpr,*,*,*,*")
388 (set_attr "length" "4,4,4,4,4,8,12,16,4")])
390 (define_expand "negtd2"
391 [(set (match_operand:TD 0 "gpc_reg_operand" "")
392 (neg:TD (match_operand:TD 1 "gpc_reg_operand" "")))]
393 "TARGET_HARD_FLOAT && TARGET_FPRS"
396 (define_insn "*negtd2_fpr"
397 [(set (match_operand:TD 0 "gpc_reg_operand" "=d")
398 (neg:TD (match_operand:TD 1 "gpc_reg_operand" "d")))]
399 "TARGET_HARD_FLOAT && TARGET_FPRS"
401 [(set_attr "type" "fp")])
403 (define_expand "abstd2"
404 [(set (match_operand:TD 0 "gpc_reg_operand" "")
405 (abs:TD (match_operand:TD 1 "gpc_reg_operand" "")))]
406 "TARGET_HARD_FLOAT && TARGET_FPRS"
409 (define_insn "*abstd2_fpr"
410 [(set (match_operand:TD 0 "gpc_reg_operand" "=d")
411 (abs:TD (match_operand:TD 1 "gpc_reg_operand" "d")))]
412 "TARGET_HARD_FLOAT && TARGET_FPRS"
414 [(set_attr "type" "fp")])
416 (define_insn "*nabstd2_fpr"
417 [(set (match_operand:TD 0 "gpc_reg_operand" "=d")
418 (neg:TD (abs:TD (match_operand:TD 1 "gpc_reg_operand" "d"))))]
419 "TARGET_HARD_FLOAT && TARGET_FPRS"
421 [(set_attr "type" "fp")])
423 (define_expand "movtd"
424 [(set (match_operand:TD 0 "general_operand" "")
425 (match_operand:TD 1 "any_operand" ""))]
426 "TARGET_HARD_FLOAT && TARGET_FPRS"
427 "{ rs6000_emit_move (operands[0], operands[1], TDmode); DONE; }")
429 ; It's important to list the Y->r and r->Y moves before r->r because
430 ; otherwise reload, given m->r, will try to pick r->r and reload it,
431 ; which doesn't make progress.
432 (define_insn_and_split "*movtd_internal"
433 [(set (match_operand:TD 0 "nonimmediate_operand" "=m,d,d,Y,r,r")
434 (match_operand:TD 1 "input_operand" "d,m,d,r,YGHF,r"))]
435 "TARGET_HARD_FLOAT && TARGET_FPRS
436 && (gpc_reg_operand (operands[0], TDmode)
437 || gpc_reg_operand (operands[1], TDmode))"
439 "&& reload_completed"
441 { rs6000_split_multireg_move (operands[0], operands[1]); DONE; }
442 [(set_attr "length" "8,8,8,20,20,16")])
444 ;; Hardware support for decimal floating point operations.
446 (define_insn "extendddtd2"
447 [(set (match_operand:TD 0 "gpc_reg_operand" "=d")
448 (float_extend:TD (match_operand:DD 1 "gpc_reg_operand" "d")))]
451 [(set_attr "type" "fp")])
453 ;; The result of drdpq is an even/odd register pair with the converted
454 ;; value in the even register and zero in the odd register.
455 ;; FIXME: Avoid the register move by using a reload constraint to ensure
456 ;; that the result is the first of the pair receiving the result of drdpq.
458 (define_insn "trunctddd2"
459 [(set (match_operand:DD 0 "gpc_reg_operand" "=d")
460 (float_truncate:DD (match_operand:TD 1 "gpc_reg_operand" "d")))
461 (clobber (match_scratch:TD 2 "=d"))]
463 "drdpq %2,%1\;fmr %0,%2"
464 [(set_attr "type" "fp")])
466 (define_insn "adddd3"
467 [(set (match_operand:DD 0 "gpc_reg_operand" "=d")
468 (plus:DD (match_operand:DD 1 "gpc_reg_operand" "%d")
469 (match_operand:DD 2 "gpc_reg_operand" "d")))]
472 [(set_attr "type" "fp")])
474 (define_insn "addtd3"
475 [(set (match_operand:TD 0 "gpc_reg_operand" "=d")
476 (plus:TD (match_operand:TD 1 "gpc_reg_operand" "%d")
477 (match_operand:TD 2 "gpc_reg_operand" "d")))]
480 [(set_attr "type" "fp")])
482 (define_insn "subdd3"
483 [(set (match_operand:DD 0 "gpc_reg_operand" "=d")
484 (minus:DD (match_operand:DD 1 "gpc_reg_operand" "d")
485 (match_operand:DD 2 "gpc_reg_operand" "d")))]
488 [(set_attr "type" "fp")])
490 (define_insn "subtd3"
491 [(set (match_operand:TD 0 "gpc_reg_operand" "=d")
492 (minus:TD (match_operand:TD 1 "gpc_reg_operand" "d")
493 (match_operand:TD 2 "gpc_reg_operand" "d")))]
496 [(set_attr "type" "fp")])
498 (define_insn "muldd3"
499 [(set (match_operand:DD 0 "gpc_reg_operand" "=d")
500 (mult:DD (match_operand:DD 1 "gpc_reg_operand" "%d")
501 (match_operand:DD 2 "gpc_reg_operand" "d")))]
504 [(set_attr "type" "fp")])
506 (define_insn "multd3"
507 [(set (match_operand:TD 0 "gpc_reg_operand" "=d")
508 (mult:TD (match_operand:TD 1 "gpc_reg_operand" "%d")
509 (match_operand:TD 2 "gpc_reg_operand" "d")))]
512 [(set_attr "type" "fp")])
514 (define_insn "divdd3"
515 [(set (match_operand:DD 0 "gpc_reg_operand" "=d")
516 (div:DD (match_operand:DD 1 "gpc_reg_operand" "d")
517 (match_operand:DD 2 "gpc_reg_operand" "d")))]
520 [(set_attr "type" "fp")])
522 (define_insn "divtd3"
523 [(set (match_operand:TD 0 "gpc_reg_operand" "=d")
524 (div:TD (match_operand:TD 1 "gpc_reg_operand" "d")
525 (match_operand:TD 2 "gpc_reg_operand" "d")))]
528 [(set_attr "type" "fp")])
530 (define_insn "*cmpdd_internal1"
531 [(set (match_operand:CCFP 0 "cc_reg_operand" "=y")
532 (compare:CCFP (match_operand:DD 1 "gpc_reg_operand" "d")
533 (match_operand:DD 2 "gpc_reg_operand" "d")))]
536 [(set_attr "type" "fpcompare")])
538 (define_insn "*cmptd_internal1"
539 [(set (match_operand:CCFP 0 "cc_reg_operand" "=y")
540 (compare:CCFP (match_operand:TD 1 "gpc_reg_operand" "d")
541 (match_operand:TD 2 "gpc_reg_operand" "d")))]
544 [(set_attr "type" "fpcompare")])
546 (define_insn "floatdidd2"
547 [(set (match_operand:DD 0 "gpc_reg_operand" "=d")
548 (float:DD (match_operand:DI 1 "gpc_reg_operand" "d")))]
549 "TARGET_DFP && TARGET_POPCNTD"
551 [(set_attr "type" "fp")])
553 (define_insn "floatditd2"
554 [(set (match_operand:TD 0 "gpc_reg_operand" "=d")
555 (float:TD (match_operand:DI 1 "gpc_reg_operand" "d")))]
558 [(set_attr "type" "fp")])
560 ;; Convert a decimal64 to a decimal64 whose value is an integer.
561 ;; This is the first stage of converting it to an integer type.
563 (define_insn "ftruncdd2"
564 [(set (match_operand:DD 0 "gpc_reg_operand" "=d")
565 (fix:DD (match_operand:DD 1 "gpc_reg_operand" "d")))]
568 [(set_attr "type" "fp")])
570 ;; Convert a decimal64 whose value is an integer to an actual integer.
571 ;; This is the second stage of converting decimal float to integer type.
573 (define_insn "fixdddi2"
574 [(set (match_operand:DI 0 "gpc_reg_operand" "=d")
575 (fix:DI (match_operand:DD 1 "gpc_reg_operand" "d")))]
578 [(set_attr "type" "fp")])
580 ;; Convert a decimal128 to a decimal128 whose value is an integer.
581 ;; This is the first stage of converting it to an integer type.
583 (define_insn "ftrunctd2"
584 [(set (match_operand:TD 0 "gpc_reg_operand" "=d")
585 (fix:TD (match_operand:TD 1 "gpc_reg_operand" "d")))]
588 [(set_attr "type" "fp")])
590 ;; Convert a decimal128 whose value is an integer to an actual integer.
591 ;; This is the second stage of converting decimal float to integer type.
593 (define_insn "fixtddi2"
594 [(set (match_operand:DI 0 "gpc_reg_operand" "=d")
595 (fix:DI (match_operand:TD 1 "gpc_reg_operand" "d")))]
598 [(set_attr "type" "fp")])