optabs.c (expand_float): Convert unsigned integer as signed only if it provides sufficient accuracy...

gcc/
	* optabs.c (expand_float): Convert unsigned integer as signed only
	if it provides sufficient accuracy; add mode argument to real_2expN.
	(expand_fix): Fix comment typos; extend binary float into mode
	wider than destination for converion to unsigned integer; add mode
	argument to real_2expN.
	* real.c (real_2expN): Add mode argument to special-case decimal
	float values.
	* real.h (real_2expN): Ditto.
	* fixed-value.c (check_real_for_fixed_mode): Add mode argument to
	real_2expN.
	(fixed_from_string): Ditto.
	(fixed_to_decimal): Ditto.
	(fixed_convert_from_real): Ditto.
	(real_convert_from_fixed): Ditto.
	* config/rs6000/rs6000.md (FP): Include DD and TD modes.
	* config/rs6000/dfp.md (extendddtd2, adddd3, addtd3, subdd3, subtd3,
	muldd3, multd3, divdd3, divtd3, cmpdd_internal1, cmptd_internal1,
	floatditd2, ftruncdd2, fixdddi2, ftrunctd2, fixddi2): New.

gcc/testsuite/
	* gcc.target/powerpc/dfp-dd.c: New test.
	* gcc.target/powerpc/dfp-td.c: New test.

From-SVN: r128156
This commit is contained in:
Janis Johnson 2007-09-05 22:16:33 +00:00 committed by Janis Johnson
parent 7336815f6f
commit be677dc12a
10 changed files with 268 additions and 19 deletions

View file

@ -1,3 +1,24 @@
2007-09-05 Janis Johnson <janis187@us.ibm.com>
* optabs.c (expand_float): Convert unsigned integer as signed only
if it provides sufficient accuracy; add mode argument to real_2expN.
(expand_fix): Fix comment typos; extend binary float into mode
wider than destination for converion to unsigned integer; add mode
argument to real_2expN.
* real.c (real_2expN): Add mode argument to special-case decimal
float values.
* real.h (real_2expN): Ditto.
* fixed-value.c (check_real_for_fixed_mode): Add mode argument to
real_2expN.
(fixed_from_string): Ditto.
(fixed_to_decimal): Ditto.
(fixed_convert_from_real): Ditto.
(real_convert_from_fixed): Ditto.
* config/rs6000/rs6000.md (FP): Include DD and TD modes.
* config/rs6000/dfp.md (extendddtd2, adddd3, addtd3, subdd3, subtd3,
muldd3, multd3, divdd3, divtd3, cmpdd_internal1, cmptd_internal1,
floatditd2, ftruncdd2, fixdddi2, ftrunctd2, fixddi2): New.
2007-09-05 Ian Lance Taylor <iant@google.com>
* init-regs.c (initialize_uninitialized_regs): Call

View file

@ -405,3 +405,151 @@
{ rs6000_split_multireg_move (operands[0], operands[1]); DONE; }
[(set_attr "length" "8,8,8,20,20,16")])
;; Hardware support for decimal floating point operations.
(define_insn "extendddtd2"
[(set (match_operand:TD 0 "gpc_reg_operand" "=f")
(float_extend:TD (match_operand:DD 1 "gpc_reg_operand" "f")))]
"TARGET_DFP"
"dctqpq %0,%1"
[(set_attr "type" "fp")])
;; The result of drdpq is an even/odd register pair with the converted
;; value in the even register and zero in the odd register.
;; FIXME: Avoid the register move by using a reload constraint to ensure
;; that the result is the first of the pair receiving the result of drdpq.
(define_insn "trunctddd2"
[(set (match_operand:DD 0 "gpc_reg_operand" "=f")
(float_truncate:DD (match_operand:TD 1 "gpc_reg_operand" "f")))
(clobber (match_scratch:TD 2 "=f"))]
"TARGET_DFP"
"drdpq %2,%1\;fmr %0,%2"
[(set_attr "type" "fp")])
(define_insn "adddd3"
[(set (match_operand:DD 0 "gpc_reg_operand" "=f")
(plus:DD (match_operand:DD 1 "gpc_reg_operand" "%f")
(match_operand:DD 2 "gpc_reg_operand" "f")))]
"TARGET_DFP"
"dadd %0,%1,%2"
[(set_attr "type" "fp")])
(define_insn "addtd3"
[(set (match_operand:TD 0 "gpc_reg_operand" "=f")
(plus:TD (match_operand:TD 1 "gpc_reg_operand" "%f")
(match_operand:TD 2 "gpc_reg_operand" "f")))]
"TARGET_DFP"
"daddq %0,%1,%2"
[(set_attr "type" "fp")])
(define_insn "subdd3"
[(set (match_operand:DD 0 "gpc_reg_operand" "=f")
(minus:DD (match_operand:DD 1 "gpc_reg_operand" "f")
(match_operand:DD 2 "gpc_reg_operand" "f")))]
"TARGET_DFP"
"dsub %0,%1,%2"
[(set_attr "type" "fp")])
(define_insn "subtd3"
[(set (match_operand:TD 0 "gpc_reg_operand" "=f")
(minus:TD (match_operand:TD 1 "gpc_reg_operand" "f")
(match_operand:TD 2 "gpc_reg_operand" "f")))]
"TARGET_DFP"
"dsubq %0,%1,%2"
[(set_attr "type" "fp")])
(define_insn "muldd3"
[(set (match_operand:DD 0 "gpc_reg_operand" "=f")
(mult:DD (match_operand:DD 1 "gpc_reg_operand" "%f")
(match_operand:DD 2 "gpc_reg_operand" "f")))]
"TARGET_DFP"
"dmul %0,%1,%2"
[(set_attr "type" "fp")])
(define_insn "multd3"
[(set (match_operand:TD 0 "gpc_reg_operand" "=f")
(mult:TD (match_operand:TD 1 "gpc_reg_operand" "%f")
(match_operand:TD 2 "gpc_reg_operand" "f")))]
"TARGET_DFP"
"dmulq %0,%1,%2"
[(set_attr "type" "fp")])
(define_insn "divdd3"
[(set (match_operand:DD 0 "gpc_reg_operand" "=f")
(div:DD (match_operand:DD 1 "gpc_reg_operand" "f")
(match_operand:DD 2 "gpc_reg_operand" "f")))]
"TARGET_DFP"
"ddiv %0,%1,%2"
[(set_attr "type" "fp")])
(define_insn "divtd3"
[(set (match_operand:TD 0 "gpc_reg_operand" "=f")
(div:TD (match_operand:TD 1 "gpc_reg_operand" "f")
(match_operand:TD 2 "gpc_reg_operand" "f")))]
"TARGET_DFP"
"ddivq %0,%1,%2"
[(set_attr "type" "fp")])
(define_insn "*cmpdd_internal1"
[(set (match_operand:CCFP 0 "cc_reg_operand" "=y")
(compare:CCFP (match_operand:DD 1 "gpc_reg_operand" "f")
(match_operand:DD 2 "gpc_reg_operand" "f")))]
"TARGET_DFP"
"dcmpu %0,%1,%2"
[(set_attr "type" "fpcompare")])
(define_insn "*cmptd_internal1"
[(set (match_operand:CCFP 0 "cc_reg_operand" "=y")
(compare:CCFP (match_operand:TD 1 "gpc_reg_operand" "f")
(match_operand:TD 2 "gpc_reg_operand" "f")))]
"TARGET_DFP"
"dcmpuq %0,%1,%2"
[(set_attr "type" "fpcompare")])
(define_insn "floatditd2"
[(set (match_operand:TD 0 "gpc_reg_operand" "=f")
(float:TD (match_operand:DI 1 "gpc_reg_operand" "f")))]
"TARGET_DFP"
"dcffixq %0,%1"
[(set_attr "type" "fp")])
;; Convert a decimal64 to a decimal64 whose value is an integer.
;; This is the first stage of converting it to an integer type.
(define_insn "ftruncdd2"
[(set (match_operand:DD 0 "gpc_reg_operand" "=f")
(fix:DD (match_operand:DD 1 "gpc_reg_operand" "f")))]
"TARGET_DFP"
"drintn. 0,%0,%1,1"
[(set_attr "type" "fp")])
;; Convert a decimal64 whose value is an integer to an actual integer.
;; This is the second stage of converting decimal float to integer type.
(define_insn "fixdddi2"
[(set (match_operand:DI 0 "gpc_reg_operand" "=f")
(fix:DI (match_operand:DD 1 "gpc_reg_operand" "f")))]
"TARGET_DFP"
"dctfix %0,%1"
[(set_attr "type" "fp")])
;; Convert a decimal128 to a decimal128 whose value is an integer.
;; This is the first stage of converting it to an integer type.
(define_insn "ftrunctd2"
[(set (match_operand:TD 0 "gpc_reg_operand" "=f")
(fix:TD (match_operand:TD 1 "gpc_reg_operand" "f")))]
"TARGET_DFP"
"drintnq. 0,%0,%1,1"
[(set_attr "type" "fp")])
;; Convert a decimal128 whose value is an integer to an actual integer.
;; This is the second stage of converting decimal float to integer type.
(define_insn "fixtddi2"
[(set (match_operand:DI 0 "gpc_reg_operand" "=f")
(fix:DI (match_operand:TD 1 "gpc_reg_operand" "f")))]
"TARGET_DFP"
"dctfixq %0,%1"
[(set_attr "type" "fp")])

View file

@ -204,7 +204,9 @@
(TF "!TARGET_IEEEQUAD
&& TARGET_HARD_FLOAT
&& (TARGET_FPRS || TARGET_E500_DOUBLE)
&& TARGET_LONG_DOUBLE_128")])
&& TARGET_LONG_DOUBLE_128")
(DD "TARGET_DFP")
(TD "TARGET_DFP")])
; Various instructions that come in SI and DI forms.
; A generic w/d attribute, for things like cmpw/cmpd.

View file

@ -64,8 +64,8 @@ check_real_for_fixed_mode (REAL_VALUE_TYPE *real_value, enum machine_mode mode)
{
REAL_VALUE_TYPE max_value, min_value, epsilon_value;
real_2expN (&max_value, GET_MODE_IBIT (mode));
real_2expN (&epsilon_value, -GET_MODE_FBIT (mode));
real_2expN (&max_value, GET_MODE_IBIT (mode), mode);
real_2expN (&epsilon_value, -GET_MODE_FBIT (mode), mode);
if (SIGNED_FIXED_POINT_MODE_P (mode))
min_value = REAL_VALUE_NEGATE (max_value);
@ -102,7 +102,7 @@ fixed_from_string (FIXED_VALUE_TYPE *f, const char *str, enum machine_mode mode)
|| (temp == FIXED_MAX_EPS && ALL_ACCUM_MODE_P (f->mode)))
warning (OPT_Woverflow,
"large fixed-point constant implicitly truncated to fixed-point type");
real_2expN (&base_value, fbit);
real_2expN (&base_value, fbit, mode);
real_arithmetic (&fixed_value, MULT_EXPR, &real_value, &base_value);
real_to_integer2 ((HOST_WIDE_INT *)&f->data.low, &f->data.high,
&fixed_value);
@ -132,7 +132,7 @@ fixed_to_decimal (char *str, const FIXED_VALUE_TYPE *f_orig,
{
REAL_VALUE_TYPE real_value, base_value, fixed_value;
real_2expN (&base_value, GET_MODE_FBIT (f_orig->mode));
real_2expN (&base_value, GET_MODE_FBIT (f_orig->mode), f_orig->mode);
real_from_integer (&real_value, VOIDmode, f_orig->data.low, f_orig->data.high,
UNSIGNED_FIXED_POINT_MODE_P (f_orig->mode));
real_arithmetic (&fixed_value, RDIV_EXPR, &real_value, &base_value);
@ -1067,7 +1067,7 @@ fixed_convert_from_real (FIXED_VALUE_TYPE *f, enum machine_mode mode,
real_value = *a;
f->mode = mode;
real_2expN (&base_value, fbit);
real_2expN (&base_value, fbit, mode);
real_arithmetic (&fixed_value, MULT_EXPR, &real_value, &base_value);
real_to_integer2 ((HOST_WIDE_INT *)&f->data.low, &f->data.high, &fixed_value);
temp = check_real_for_fixed_mode (&real_value, mode);
@ -1116,7 +1116,7 @@ real_convert_from_fixed (REAL_VALUE_TYPE *r, enum machine_mode mode,
{
REAL_VALUE_TYPE base_value, fixed_value, real_value;
real_2expN (&base_value, GET_MODE_FBIT (f->mode));
real_2expN (&base_value, GET_MODE_FBIT (f->mode), f->mode);
real_from_integer (&fixed_value, VOIDmode, f->data.low, f->data.high,
UNSIGNED_FIXED_POINT_MODE_P (f->mode));
real_arithmetic (&real_value, RDIV_EXPR, &fixed_value, &base_value);

View file

@ -5120,10 +5120,11 @@ expand_float (rtx to, rtx from, int unsignedp)
}
}
/* Unsigned integer, and no way to convert directly. For binary
floating point modes, convert as signed, then conditionally adjust
the result. */
if (unsignedp && can_do_signed && !DECIMAL_FLOAT_MODE_P (GET_MODE (to)))
/* Unsigned integer, and no way to convert directly. Convert as signed,
then unconditionally adjust the result. For decimal float values we
do this only if we have already determined that a signed conversion
provides sufficient accuracy. */
if (unsignedp && (can_do_signed || !DECIMAL_FLOAT_MODE_P (GET_MODE (to))))
{
rtx label = gen_label_rtx ();
rtx temp;
@ -5214,7 +5215,7 @@ expand_float (rtx to, rtx from, int unsignedp)
0, label);
real_2expN (&offset, GET_MODE_BITSIZE (GET_MODE (from)));
real_2expN (&offset, GET_MODE_BITSIZE (GET_MODE (from)), fmode);
temp = expand_binop (fmode, add_optab, target,
CONST_DOUBLE_FROM_REAL_VALUE (offset, fmode),
target, 0, OPTAB_LIB_WIDEN);
@ -5325,14 +5326,16 @@ expand_fix (rtx to, rtx from, int unsignedp)
anything with a wider integer mode.
This code used to extend FP value into mode wider than the destination.
This is not needed. Consider, for instance conversion from SFmode
This is needed for decimal float modes which cannot accurately
represent one plus the highest signed number of the same size, but
not for binary modes. Consider, for instance conversion from SFmode
into DImode.
The hot path through the code is dealing with inputs smaller than 2^63
and doing just the conversion, so there is no bits to lose.
In the other path we know the value is positive in the range 2^63..2^64-1
inclusive. (as for other imput overflow happens and result is undefined)
inclusive. (as for other input overflow happens and result is undefined)
So we know that the most important bit set in mantissa corresponds to
2^63. The subtraction of 2^63 should not generate any rounding as it
simply clears out that bit. The rest is trivial. */
@ -5340,15 +5343,16 @@ expand_fix (rtx to, rtx from, int unsignedp)
if (unsignedp && GET_MODE_BITSIZE (GET_MODE (to)) <= HOST_BITS_PER_WIDE_INT)
for (fmode = GET_MODE (from); fmode != VOIDmode;
fmode = GET_MODE_WIDER_MODE (fmode))
if (CODE_FOR_nothing != can_fix_p (GET_MODE (to), fmode, 0,
&must_trunc))
if (CODE_FOR_nothing != can_fix_p (GET_MODE (to), fmode, 0, &must_trunc)
&& (!DECIMAL_FLOAT_MODE_P (fmode)
|| GET_MODE_BITSIZE (fmode) > GET_MODE_BITSIZE (GET_MODE (to))))
{
int bitsize;
REAL_VALUE_TYPE offset;
rtx limit, lab1, lab2, insn;
bitsize = GET_MODE_BITSIZE (GET_MODE (to));
real_2expN (&offset, bitsize - 1);
real_2expN (&offset, bitsize - 1, fmode);
limit = CONST_DOUBLE_FROM_REAL_VALUE (offset, fmode);
lab1 = gen_label_rtx ();
lab2 = gen_label_rtx ();

View file

@ -2304,7 +2304,7 @@ real_maxval (REAL_VALUE_TYPE *r, int sign, enum machine_mode mode)
/* Fills R with 2**N. */
void
real_2expN (REAL_VALUE_TYPE *r, int n)
real_2expN (REAL_VALUE_TYPE *r, int n, enum machine_mode fmode)
{
memset (r, 0, sizeof (*r));
@ -2319,6 +2319,9 @@ real_2expN (REAL_VALUE_TYPE *r, int n)
SET_REAL_EXP (r, n);
r->sig[SIGSZ-1] = SIG_MSB;
}
if (DECIMAL_FLOAT_MODE_P (fmode))
decimal_real_convert (r, fmode, r);
}

View file

@ -248,7 +248,7 @@ extern bool real_nan (REAL_VALUE_TYPE *, const char *, int, enum machine_mode);
extern void real_maxval (REAL_VALUE_TYPE *, int, enum machine_mode);
extern void real_2expN (REAL_VALUE_TYPE *, int);
extern void real_2expN (REAL_VALUE_TYPE *, int, enum machine_mode);
extern unsigned int real_hash (const REAL_VALUE_TYPE *);

View file

@ -1,3 +1,8 @@
2007-09-05 Janis Johnson <janis187@us.ibm.com>
* gcc.target/powerpc/dfp-dd.c: New test.
* gcc.target/powerpc/dfp-td.c: New test.
2007-09-05 Jakub Jelinek <jakub@redhat.com>
* gcc.c-torture/execute/va-arg-pack-1.c: New test.

View file

@ -0,0 +1,33 @@
/* Test generation of DFP instructions for POWER6. */
/* Origin: Janis Johnson <janis187@us.ibm.com> */
/* { dg-do compile { target powerpc*-*-linux* } } */
/* { dg-options "-std=gnu99 -mcpu=power6" } */
/* { dg-final { scan-assembler "dadd" } } */
/* { dg-final { scan-assembler "ddiv" } } */
/* { dg-final { scan-assembler "dmul" } } */
/* { dg-final { scan-assembler "dsub" } } */
/* { dg-final { scan-assembler-times "dcmpu" 6 } } */
/* { dg-final { scan-assembler-times "dctfix" 2 } } */
/* { dg-final { scan-assembler-times "drintn" 2 } } */
/* { dg-final { scan-assembler-times "dcffixq" 2 } } */
extern _Decimal64 a, b, c;
extern int result;
extern int si;
extern long long di;
void add (void) { a = b + c; }
void div (void) { a = b / c; }
void mul (void) { a = b * c; }
void sub (void) { a = b - c; }
void eq (void) { result = a == b; }
void ne (void) { result = a != b; }
void lt (void) { result = a < b; }
void le (void) { result = a <= b; }
void gt (void) { result = a > b; }
void ge (void) { result = a >= b; }
void ddsi (void) { si = a; }
void dddi (void) { di = a; }
void sidd (void) { a = si; }
void didd (void) { a = di; }

View file

@ -0,0 +1,33 @@
/* Test generation of DFP instructions for POWER6. */
/* Origin: Janis Johnson <janis187@us.ibm.com> */
/* { dg-do compile { target powerpc*-*-linux* } } */
/* { dg-options "-std=gnu99 -mcpu=power6" } */
/* { dg-final { scan-assembler "daddq" } } */
/* { dg-final { scan-assembler "ddivq" } } */
/* { dg-final { scan-assembler "dmulq" } } */
/* { dg-final { scan-assembler "dsubq" } } */
/* { dg-final { scan-assembler-times "dcmpuq" 6 } } */
/* { dg-final { scan-assembler-times "dctfixq" 2 } } */
/* { dg-final { scan-assembler-times "drintnq" 2 } } */
/* { dg-final { scan-assembler-times "dcffixq" 2 } } */
extern _Decimal128 a, b, c;
extern int result;
extern int si;
extern long long di;
void add (void) { a = b + c; }
void div (void) { a = b / c; }
void mul (void) { a = b * c; }
void sub (void) { a = b - c; }
void eq (void) { result = a == b; }
void ne (void) { result = a != b; }
void lt (void) { result = a < b; }
void le (void) { result = a <= b; }
void gt (void) { result = a > b; }
void ge (void) { result = a >= b; }
void tdsi (void) { si = a; }
void tddi (void) { di = a; }
void sitd (void) { a = si; }
void ditd (void) { a = di; }