This is the mail archive of the
gcc-patches@gcc.gnu.org
mailing list for the GCC project.
reversing of FP conditions infrastructure
- To: patches at x86-64 dot org, rth at cygnus dot com, gcc-patches at gcc dot gnu dot org
- Subject: reversing of FP conditions infrastructure
- From: Jan Hubicka <jh at suse dot cz>
- Date: Sat, 6 Jan 2001 22:49:12 +0100
Hi
This patch adds another important infrastructure bit to handle properly IEEE
comparisons.
Currently when compiler wants to reverse condition, it first calls
can_reverse_comparison_p, that verifies if INSN is integer comparison and then
reverse_condition to reverse the code.
The reverse_condition can't be teached about the IEEE arithmetics, since it
don't knows the mode comparison is done it, while this is known to
can_reverse_comparison_p. So I propose to replace both by
reversed_comparison_code function that gets all necesary information and does
the reversal if possible and returns UNKNOWN otherwise.
The code of function is based on can_reverse_p, but contains improvements
and fixes.
1) While it searches for the COMPARE insn,
it don't skip sets of condition code it don't understands and give up
instead.
2) It does use knowledge of current condition code to determine if it
can be float (if it already is unordered, we know we are dealing with
float, while if it is unsigned we know we are not)
3) It adds support for new target macro REVERSE_CONDITION that may implement
proper reversing of CC_MODEs w/o searching back.
I don't document it yet, since it assumes REVERSIBLE_CC_MODE to return
true for such mode, but this macro is used at another place in combine.c
so I need to convert combine to this infrastructure first.
While I assume that in future each port will define REVERSIBLE_CC_MODE
to be true for all modes and REVERSE_CONDITION to call reverse_condition
or reverse_condition_maybe_unordered depending on the mode, the
current "search backwards" algorithm seems to work surprisingly well -
it don't give up once during the i386 testsuite except for cases where
i386 backend generates improper insn stream setting flags in one mode
and using in another (it is fixed by my fcomi patch).
Honza
So led 6 20:48:29 CET 2001 Jan Hubicka <jh@suse.cz>
* jump.c (reversed_comparison_code_parts, reversed_comparison_code):
New.
(can_reverse_comparison_p): Rewrite to use reversed_comparison_code.
(reverse_condition_maybe_unordered): Abort on unsigned comparisons.
* rtl.h (reversed_comparison_code_parts, reversed_comparison_code):
Declare.
*** /p1/gcc/jump.c Sat Jan 6 17:04:05 2001
--- jump.c Sat Jan 6 20:25:46 2001
*************** jump_back_p (insn, target)
*** 1681,1760 ****
&& rtx_renumbered_equal_p (XEXP (cinsn, 1), XEXP (ctarget, 1)));
}
! /* Given a comparison, COMPARISON, inside a conditional jump insn, INSN,
! return non-zero if it is safe to reverse this comparison. It is if our
! floating-point is not IEEE, if this is an NE or EQ comparison, or if
! this is known to be an integer comparison. */
!
! int
! can_reverse_comparison_p (comparison, insn)
! rtx comparison;
! rtx insn;
{
! rtx arg0;
/* If this is not actually a comparison, we can't reverse it. */
! if (GET_RTX_CLASS (GET_CODE (comparison)) != '<')
! return 0;
! if (TARGET_FLOAT_FORMAT != IEEE_FLOAT_FORMAT
! /* If this is an NE comparison, it is safe to reverse it to an EQ
! comparison and vice versa, even for floating point. If no operands
! are NaNs, the reversal is valid. If some operand is a NaN, EQ is
! always false and NE is always true, so the reversal is also valid. */
! || flag_fast_math
! || GET_CODE (comparison) == NE
! || GET_CODE (comparison) == EQ)
! return 1;
! arg0 = XEXP (comparison, 0);
! /* Make sure ARG0 is one of the actual objects being compared. If we
! can't do this, we can't be sure the comparison can be reversed.
! Handle cc0 and a MODE_CC register. */
! if ((GET_CODE (arg0) == REG && GET_MODE_CLASS (GET_MODE (arg0)) == MODE_CC)
#ifdef HAVE_cc0
|| arg0 == cc0_rtx
#endif
)
{
! rtx prev, set;
!
! /* First see if the condition code mode alone if enough to say we can
! reverse the condition. If not, then search backwards for a set of
! ARG0. We do not need to check for an insn clobbering it since valid
! code will contain set a set with no intervening clobber. But
! stop when we reach a label. */
! #ifdef REVERSIBLE_CC_MODE
! if (GET_MODE_CLASS (GET_MODE (arg0)) == MODE_CC
! && REVERSIBLE_CC_MODE (GET_MODE (arg0)))
! return 1;
! #endif
!
if (! insn)
! return 0;
for (prev = prev_nonnote_insn (insn);
prev != 0 && GET_CODE (prev) != CODE_LABEL;
prev = prev_nonnote_insn (prev))
! if ((set = single_set (prev)) != 0
! && rtx_equal_p (SET_DEST (set), arg0))
! {
! arg0 = SET_SRC (set);
! if (GET_CODE (arg0) == COMPARE)
! arg0 = XEXP (arg0, 0);
! break;
! }
}
! /* We can reverse this if ARG0 is a CONST_INT or if its mode is
! not VOIDmode and neither a MODE_CC nor MODE_FLOAT type. */
! return (GET_CODE (arg0) == CONST_INT
! || (GET_MODE (arg0) != VOIDmode
! && GET_MODE_CLASS (GET_MODE (arg0)) != MODE_CC
! && GET_MODE_CLASS (GET_MODE (arg0)) != MODE_FLOAT));
}
/* Given an rtx-code for a comparison, return the code for the negated
--- 1683,1859 ----
&& rtx_renumbered_equal_p (XEXP (cinsn, 1), XEXP (ctarget, 1)));
}
! /* Given a comparison (CODE ARG0 ARG1), inside a insn, INSN, return an code
! of reversed comparison if it is possible to do so. Otherwise return UNKNOWN.
! UNKNOWN may be returned in case we are having CC_MODE compare and we don't
! know whether it's source is floating point or integer comparison. Machine
! description should define REVERSIBLE_CC_MODE and REVERSE_CONDITION macros
! to help this function avoid overhead in these cases. */
! enum rtx_code
! reversed_comparison_code_parts (code, arg0, arg1, insn)
! rtx insn, arg0, arg1;
! enum rtx_code code;
{
! enum machine_mode mode;
/* If this is not actually a comparison, we can't reverse it. */
! if (GET_RTX_CLASS (code) != '<')
! return UNKNOWN;
! mode = GET_MODE (arg0);
! if (mode == VOIDmode)
! mode = GET_MODE (arg1);
!
! /* First see if machine description supply us way to reverse the comparison.
! Give it priority over everything else to allow machine description to do
! tricks. */
! #ifdef REVERSIBLE_CC_MODE
! if (GET_MODE_CLASS (mode) == MODE_CC)
! && REVERSIBLE_CC_MODE (mode))
! {
! #ifdef REVERSE_CONDITION
! return REVERSE_CONDITION (code, mode);
! #endif
! return reverse_condition (code);
! }
! #endif
! /* Try few special cases based on the comparison code. */
! switch (code)
! {
! case GEU:
! case GTU:
! case LEU:
! case LTU:
! case NE:
! case EQ:
! /* It is always safe to reverse EQ and NE, even for the floating
! point. Similary the unsigned comparisons are never used for
! floating point so we can reverse them in the default way. */
! return reverse_condition (code);
! case ORDERED:
! case UNORDERED:
! case UNLT:
! case UNLE:
! case UNGT:
! case UNGE:
! case UNEQ:
! case LTGT:
! /* In case we already see unordered comparison, we can be sure to
! be dealing with floating point so we don't need any more tests. */
! return reverse_condition_maybe_unordered (code);
! default:
! break;
! }
! /* In case we give up IEEE compatibility, all comparisons are reversible. */
! if (TARGET_FLOAT_FORMAT != IEEE_FLOAT_FORMAT
! || flag_fast_math)
! return reverse_condition (code);
! if (GET_MODE_CLASS (mode) == MODE_CC
#ifdef HAVE_cc0
|| arg0 == cc0_rtx
#endif
)
{
! rtx prev;
! /* Try to search for the comparison to determine the real mode.
! This code is expensive, but with sane machine description it
! will be never used, since REVERSIBLE_CC_MODE will return true
! in all cases. */
if (! insn)
! return UNKNOWN;
for (prev = prev_nonnote_insn (insn);
prev != 0 && GET_CODE (prev) != CODE_LABEL;
prev = prev_nonnote_insn (prev))
! {
! rtx set = set_of (arg0, prev);
! if (set && GET_CODE (set) == SET
! && rtx_equal_p (SET_DEST (set), arg0))
! {
! rtx src = SET_SRC (set);
! if (GET_CODE (src) == COMPARE)
! {
! rtx comparison = src;
! arg0 = XEXP (src, 0);
! mode = GET_MODE (arg0);
! if (mode == VOIDmode)
! mode = GET_MODE (XEXP (comparison, 1));
! break;
! }
! /* We can get past reg-reg moves. This may be usefull for model
! of i387 comparisons that first move flag registers around. */
! if (REG_P (src))
! {
! arg0 = src;
! continue;
! }
! }
! /* If register is clobbered in some ununderstandable way,
! give up. */
! if (set)
! return UNKNOWN;
! }
}
!
! /* An floating point condition. */
! if (GET_MODE_CLASS (mode) == MODE_FLOAT)
! return reverse_condition_maybe_unordered (code);
!
! /* An integer condition. */
! if (GET_CODE (arg0) == CONST_INT
! || (GET_MODE (arg0) != VOIDmode
! && GET_MODE_CLASS (mode) != MODE_CC
! && ! FLOAT_MODE_P (mode)))
! return reverse_condition (code);
!
! return UNKNOWN;
! }
!
! /* An wrapper around the previous function to take COMPARISON as rtx
! expression. This simplifies many callers. */
! enum rtx_code
! reversed_comparison_code (comparison, insn)
! rtx comparison, insn;
! {
! if (GET_RTX_CLASS (GET_CODE (comparison)) != '<')
! return UNKNOWN;
! return reversed_comparison_code_parts (GET_CODE (comparison),
! XEXP (comparison, 0),
! XEXP (comparison, 1), insn);
! }
!
! /* Given a comparison, COMPARISON, inside a conditional jump insn, INSN,
! return non-zero if it is safe to reverse this comparison. It is if our
! floating-point is not IEEE, if this is an NE or EQ comparison, or if
! this is known to be an integer comparison.
!
! Use of this function is depreached and you should use
! REVERSED_COMPARISON_CODE bits instead.
! */
!
! int
! can_reverse_comparison_p (comparison, insn)
! rtx comparison;
! rtx insn;
! {
! enum rtx_code code;
!
! /* If this is not actually a comparison, we can't reverse it. */
! if (GET_RTX_CLASS (GET_CODE (comparison)) != '<')
! return 0;
!
! code = reversed_comparison_code (comparison, insn);
! if (code == UNKNOWN)
! return 0;
!
! /* The code will follow can_reverse_comparison_p with reverse_condition,
! so see if it will get proper result. */
! return (code == reverse_condition (GET_CODE (comparison)));
}
/* Given an rtx-code for a comparison, return the code for the negated
*************** can_reverse_comparison_p (comparison, in
*** 1763,1769 ****
WATCH OUT! reverse_condition is not safe to use on a jump that might
be acting on the results of an IEEE floating point comparison, because
of the special treatment of non-signaling nans in comparisons.
! Use can_reverse_comparison_p to be sure. */
enum rtx_code
reverse_condition (code)
--- 1862,1868 ----
WATCH OUT! reverse_condition is not safe to use on a jump that might
be acting on the results of an IEEE floating point comparison, because
of the special treatment of non-signaling nans in comparisons.
! Use reversed_comparison_code instead. */
enum rtx_code
reverse_condition (code)
*************** reverse_condition_maybe_unordered (code)
*** 1837,1850 ****
return UNGT;
case LTGT:
return UNEQ;
- case GTU:
- return LEU;
- case GEU:
- return LTU;
- case LTU:
- return GEU;
- case LEU:
- return GTU;
case UNORDERED:
return ORDERED;
case ORDERED:
--- 1936,1941 ----
*** /p1/gcc/rtl.h Sat Jan 6 17:04:08 2001
--- rtl.h Sat Jan 6 19:38:11 2001
*************** extern void rebuild_jump_labels PARAMS
*** 1700,1705 ****
--- 1701,1709 ----
extern void thread_jumps PARAMS ((rtx, int, int));
extern int rtx_equal_for_thread_p PARAMS ((rtx, rtx, rtx));
extern int can_reverse_comparison_p PARAMS ((rtx, rtx));
+ extern enum rtx_code reversed_comparison_code PARAMS ((rtx, rtx));
+ extern enum rtx_code reversed_comparison_code_parts PARAMS ((enum rtx_code,
+ rtx, rtx, rtx));
extern void delete_for_peephole PARAMS ((rtx, rtx));
extern int condjump_in_parallel_p PARAMS ((rtx));
extern void never_reached_warning PARAMS ((rtx));