This is the mail archive of the
gcc-patches@gcc.gnu.org
mailing list for the GCC project.
RFA: fix PR tree-optimization/28144/27394
- From: Joern RENNECKE <joern dot rennecke at st dot com>
- To: GCC Patches <gcc-patches at gcc dot gnu dot org>
- Cc: Andrew Haley <aph at redhat dot com>
- Date: Mon, 17 Jul 2006 16:56:40 +0100
- Subject: RFA: fix PR tree-optimization/28144/27394
As Andrew has clarified that the Java frontend handles the two-step
conversion for
floating point -> narrow integers, the remaining problem for PR28144 was
that the
comment in fold-const.c was wrong.
In order to allow people to debug their programs meaningfully at -O0,
I've broken
out the code that determines what mode to use to do a run-time
conversion from
floating point to integer, and made fold-const.c use it to determine the
type that
the conversion is done in.
I've put the expand_fix_1 prototype in rtl.h rather than optabs.h to
avoid a gratuitous
dependency of fold-const.c on optabs.h.
:ADDPATCH tree-optimization:
regression tested on i686-pc-linux-gnu native and X sh-elf in Revision
115417
2006-07-16 J"orn Rennecke <joern.rennecke@st.com>
gcc:
PR tree-optimization/28144/27394
* rtl.h (expand_fix_1): Declare.
* optabs.c (expand_fix_1): New function, broken out of:
(expand_fix).
* fold-const.c (fold_convert_const_int_from_real): Fix comment
wrt. implementing Java conversions.
Perform conversion in same mode as optabs.c would do it.
testsuite:
PR tree-optimization/27394
gcc.c-torture/execute/pr27394.c: New test.
Index: optabs.c
===================================================================
/usr/bin/diff -p -d -F^( -u -L optabs.c (revision 115417) -L optabs.c (working copy) .svn/text-base/optabs.c.svn-base optabs.c
--- optabs.c (revision 115417)
+++ optabs.c (working copy)
@@ -4684,6 +4684,18 @@ expand_float (rtx to, rtx from, int unsi
void
expand_fix (rtx to, rtx from, int unsignedp)
{
+ expand_fix_1 (to, GET_MODE (to), from, GET_MODE (from), &unsignedp);
+}
+
+/* As above, but don't actually emit any code if FROM and TO are NULL_RTX.
+ Return the mode that is actuallyu the target of the floating
+ point -> integer conversion. Reset *UNSIGNEDPP if we use a widened
+ signed conversion to implement an unsigned conversion. */
+enum machine_mode
+expand_fix_1 (rtx to, enum machine_mode to_mode, rtx from,
+ enum machine_mode from_mode, int *unsignedpp)
+{
+ int unsignedp = *unsignedpp;
enum insn_code icode;
rtx target = to;
enum machine_mode fmode, imode;
@@ -4694,37 +4706,37 @@ expand_fix (rtx to, rtx from, int unsign
this conversion. If the integer mode is wider than the mode of TO,
we can do the conversion either signed or unsigned. */
- for (fmode = GET_MODE (from); fmode != VOIDmode;
+ for (fmode = from_mode; fmode != VOIDmode;
fmode = GET_MODE_WIDER_MODE (fmode))
- for (imode = GET_MODE (to); imode != VOIDmode;
+ for (imode = to_mode; imode != VOIDmode;
imode = GET_MODE_WIDER_MODE (imode))
{
- int doing_unsigned = unsignedp;
-
icode = can_fix_p (imode, fmode, unsignedp, &must_trunc);
- if (icode == CODE_FOR_nothing && imode != GET_MODE (to) && unsignedp)
- icode = can_fix_p (imode, fmode, 0, &must_trunc), doing_unsigned = 0;
+ if (icode == CODE_FOR_nothing && imode != to_mode && unsignedp)
+ icode = can_fix_p (imode, fmode, 0, &must_trunc), *unsignedpp = 0;
if (icode != CODE_FOR_nothing)
{
- if (fmode != GET_MODE (from))
+ if (!to)
+ return imode;
+
+ if (fmode != from_mode)
from = convert_to_mode (fmode, from, 0);
if (must_trunc)
{
- rtx temp = gen_reg_rtx (GET_MODE (from));
- from = expand_unop (GET_MODE (from), ftrunc_optab, from,
- temp, 0);
+ rtx temp = gen_reg_rtx (fmode);
+ from = expand_unop (fmode, ftrunc_optab, from, temp, 0);
}
if (imode != GET_MODE (to))
target = gen_reg_rtx (imode);
emit_unop_insn (icode, target, from,
- doing_unsigned ? UNSIGNED_FIX : FIX);
+ *unsignedpp ? UNSIGNED_FIX : FIX);
if (target != to)
convert_move (to, target, unsignedp);
- return;
+ return imode;
}
}
@@ -4750,29 +4762,31 @@ expand_fix (rtx to, rtx from, int unsign
2^63. The subtraction of 2^63 should not generate any rounding as it
simply clears out that bit. The rest is trivial. */
- if (unsignedp && GET_MODE_BITSIZE (GET_MODE (to)) <= HOST_BITS_PER_WIDE_INT)
- for (fmode = GET_MODE (from); fmode != VOIDmode;
+ if (unsignedp && GET_MODE_BITSIZE (to_mode) <= HOST_BITS_PER_WIDE_INT)
+ for (fmode = from_mode; 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 (to_mode, fmode, 0, &must_trunc))
{
int bitsize;
REAL_VALUE_TYPE offset;
rtx limit, lab1, lab2, insn;
+ /* The net effect will still be an unsigned conversion to TO_MODE. */
+ if (!to)
+ return to_mode;
+
bitsize = GET_MODE_BITSIZE (GET_MODE (to));
real_2expN (&offset, bitsize - 1);
limit = CONST_DOUBLE_FROM_REAL_VALUE (offset, fmode);
lab1 = gen_label_rtx ();
lab2 = gen_label_rtx ();
- if (fmode != GET_MODE (from))
+ if (fmode != from_mode)
from = convert_to_mode (fmode, from, 0);
/* See if we need to do the subtraction. */
do_pending_stack_adjust ();
- emit_cmp_and_jump_insns (from, limit, GE, NULL_RTX, GET_MODE (from),
- 0, lab1);
+ emit_cmp_and_jump_insns (from, limit, GE, NULL_RTX, fmode, 0, lab1);
/* If not, do the signed "fix" and branch around fixup code. */
expand_fix (to, from, 0);
@@ -4783,13 +4797,12 @@ expand_fix (rtx to, rtx from, int unsign
then add 2**(N-1). Do the addition using XOR since this
will often generate better code. */
emit_label (lab1);
- target = expand_binop (GET_MODE (from), sub_optab, from, limit,
+ target = expand_binop (fmode, sub_optab, from, limit,
NULL_RTX, 0, OPTAB_LIB_WIDEN);
expand_fix (to, target, 0);
- target = expand_binop (GET_MODE (to), xor_optab, to,
+ target = expand_binop (to_mode, xor_optab, to,
gen_int_mode
- ((HOST_WIDE_INT) 1 << (bitsize - 1),
- GET_MODE (to)),
+ ((HOST_WIDE_INT) 1 << (bitsize - 1), to_mode),
to, 1, OPTAB_LIB_WIDEN);
if (target != to)
@@ -4809,15 +4822,19 @@ expand_fix (rtx to, rtx from, int unsign
copy_rtx (from)));
}
- return;
+ return to_mode;
}
/* We can't do it with an insn, so use a library call. But first ensure
that the mode of TO is at least as wide as SImode, since those are the
only library calls we know about. */
- if (GET_MODE_SIZE (GET_MODE (to)) < GET_MODE_SIZE (SImode))
+ if (GET_MODE_SIZE (to_mode) < GET_MODE_SIZE (SImode))
{
+ imode = SImode;
+ if (!to)
+ return imode;
+
target = gen_reg_rtx (SImode);
expand_fix (target, from, unsignedp);
@@ -4827,31 +4844,36 @@ expand_fix (rtx to, rtx from, int unsign
rtx insns;
rtx value;
rtx libfunc;
+ convert_optab tab;
- convert_optab tab = unsignedp ? ufix_optab : sfix_optab;
- libfunc = tab->handlers[GET_MODE (to)][GET_MODE (from)].libfunc;
+ imode = to_mode;
+ if (!to)
+ return imode;
+
+ tab = unsignedp ? ufix_optab : sfix_optab;
+ libfunc = tab->handlers[GET_MODE (to)][from_mode].libfunc;
gcc_assert (libfunc);
start_sequence ();
value = emit_library_call_value (libfunc, NULL_RTX, LCT_CONST,
- GET_MODE (to), 1, from,
- GET_MODE (from));
+ to_mode, 1, from, from_mode);
insns = get_insns ();
end_sequence ();
emit_libcall_block (insns, target, value,
gen_rtx_fmt_e (unsignedp ? UNSIGNED_FIX : FIX,
- GET_MODE (to), from));
+ to_mode, from));
}
if (target != to)
{
- if (GET_MODE (to) == GET_MODE (target))
+ if (to_mode == GET_MODE (target))
emit_move_insn (to, target);
else
convert_move (to, target, 0);
}
+ return imode;
}
/* Report whether we have an instruction to perform the operation
Index: fold-const.c
===================================================================
/usr/bin/diff -p -d -F^( -u -L fold-const.c (revision 115417) -L fold-const.c (working copy) .svn/text-base/fold-const.c.svn-base fold-const.c
--- fold-const.c (revision 115417)
+++ fold-const.c (working copy)
@@ -1836,11 +1836,16 @@ fold_convert_const_int_from_real (enum t
INT_MAX are mapped to INT_MAX, and values less than INT_MIN
are mapped to INT_MIN. These semantics are allowed by the
C and C++ standards that simply state that the behavior of
- FP-to-integer conversion is unspecified upon overflow. */
+ FP-to-integer conversion is unspecified upon overflow.
+ The Java two-step conversion from floating point to byte / char /
+ short is handled in the front end. */
HOST_WIDE_INT high, low;
REAL_VALUE_TYPE r;
REAL_VALUE_TYPE x = TREE_REAL_CST (arg1);
+ enum machine_mode fix_mode;
+ tree fix_type;
+ int unsignedp = TYPE_UNSIGNED (type);
switch (code)
{
@@ -1872,12 +1877,25 @@ fold_convert_const_int_from_real (enum t
low = 0;
}
+ /* Getting different results for different optimization levels makes
+ debugging of faulty programs harder. Therefore, use the same logic
+ as optabs.c:expand_fix to determine what the target mode of the
+ conversion will be, to avoid gratuitous differences between
+ compile-time and run-time conversions. */
+ fix_mode = expand_fix_1 (NULL_RTX, TYPE_MODE (type), NULL_RTX,
+ TYPE_MODE (TREE_TYPE (arg1)), &unsignedp);
+ fix_type = NULL_TREE;
+ if (fix_mode != TYPE_MODE (type))
+ fix_type = lang_hooks.types.type_for_mode (fix_mode, unsignedp);
+ if (!fix_type)
+ fix_type = type;
+
/* See if R is less than the lower bound or greater than the
upper bound. */
if (! overflow)
{
- tree lt = TYPE_MIN_VALUE (type);
+ tree lt = TYPE_MIN_VALUE (fix_type);
REAL_VALUE_TYPE l = real_value_from_int_cst (NULL_TREE, lt);
if (REAL_VALUES_LESS (r, l))
{
@@ -1889,7 +1907,7 @@ fold_convert_const_int_from_real (enum t
if (! overflow)
{
- tree ut = TYPE_MAX_VALUE (type);
+ tree ut = TYPE_MAX_VALUE (fix_type);
if (ut)
{
REAL_VALUE_TYPE u = real_value_from_int_cst (NULL_TREE, ut);
Index: rtl.h
===================================================================
/usr/bin/diff -p -d -F^( -u -L rtl.h (revision 115417) -L rtl.h (working copy) .svn/text-base/rtl.h.svn-base rtl.h
--- rtl.h (revision 115417)
+++ rtl.h (working copy)
@@ -2263,6 +2263,9 @@ extern unsigned int variable_tracking_ma
/* In stor-layout.c. */
extern void get_mode_bounds (enum machine_mode, int, enum machine_mode,
rtx *, rtx *);
+/* In optabs.c */
+extern enum machine_mode expand_fix_1 (rtx, enum machine_mode, rtx,
+ enum machine_mode, int *);
/* In loop-unswitch.c */
extern rtx reversed_condition (rtx);
Index: testsuite/gcc.c-torture/execute/pr27394.c
===================================================================
/usr/bin/diff -p -d -F^( -u -L testsuite/gcc.c-torture/execute/pr27394.c (revision 0) -L testsuite/gcc.c-torture/execute/pr27394.c (revision 0) testsuite/gcc.c-torture/execute/.svn/empty-file testsuite/gcc.c-torture/execute/pr27394.c
--- testsuite/gcc.c-torture/execute/pr27394.c (revision 0)
+++ testsuite/gcc.c-torture/execute/pr27394.c (revision 0)
@@ -0,0 +1,18 @@
+char __attribute__ ((noinline))
+d2c (double d)
+{
+ return d;
+}
+
+char d2c_const (void)
+{
+ return 300.;
+}
+
+int
+main ()
+{
+ if (d2c (300.) != d2c_const ())
+ abort ();
+ exit (0);
+}