[PATCH] Fold isnan to UNORDERED_EXPR

Roger Sayle roger@eyesopen.com
Mon Jun 28 18:11:00 GMT 2004


On Mon, 28 Jun 2004, Paolo Bonzini wrote:
> These (especially isinf) are quite harder.  For example, finite can be
> defined as !isnan (x - x), but this maybe uselessly expensive.  Apart
> from cnstant folding, I don't easily see special expansions of isinf.

Just adding them to builtins.def, will mark them with const and nothrow
attributes, so we'll get some benefit just from that.  Adding folding
for constant arguments is also a win.  Its true that there's currently
little we can do to improve code generation but these steps are a clear
win.  Indeed, the same with "isnan", the optimizations above are
obviously an improvement, its how we affect code generation thats the
issue.

> > Finally, I'm still a bit unsure about canonicalizing isnan(x) to
> > unordered(x,x).  Not only am I not a fan of SAVE_EXPRs, but on platforms
> > without UNORDERED instructions, we'll be replacing a call to libm's
> > "isnan" which takes a single argument with a call to libgcc's __unord?f2
> > which takes two, increasing code size and degrading performance.
>
> Are there any, apart from maybe Alphas, which however are in not-IEEE
> mode by default?

Most of the embedded architectures, and for example even x86 with the
-msoft-float command line option.


> > I'd prefer, at the tree-level atleast to go the other way, and canonicalize
> > unordered(x,x) as isnan(x), and then at RTL expansion time decide whether
> > we can use the unord_optab to implement this functionality or not.
>
> I see.  Though this prevents from optimizing isnan (x) || isnan (y) to a
> single UNORDERED_EXPR.


It shouldn't.  In the FOLD_ORIF_EXPR, we simply use builtin_mathfn_code
to identify the operands as calls to isnan, and then perform the
optimization to convert them into a single expression.  You'd have to
to something similar with operand_equal_p to convince yourself that
both operands to UNORDERED_EXPR were identical.  All that we're changing
is the tree codes that we use to represent equivalent expressions.

A related possibility is introducing a ISNAN_EXPR tree code, and using
this to represent calls to "isnan", and UNORDERED_EXPR with identical
operands.  I've often considered that we could benefit from DOUBLE_EXPR
expr to represent "x+x", and SQUARE_EXPR to represent "x*x".  These would
avoid a major users of SAVE_EXPR in the middle-end/constant folding.


> What about recognizing the idiom UNORDERED_EXPR (x, x) in the RTL
> optimizers and expanding it to an isnan libcall?  rth objected "surely
> the other way" when you proposed folding UNORDERED_EXPR (x, x) to isnan
> (x), so I'm unsure about what to do.

I'll admit that I'm a bit conflicted about this.  On most platforms, the
use of UNORDERED_EXPR is the best way to implement "isnan", so lowering
to this form is the intent of the compiler.  Much like on some platforms,
"x+x+x" is the best way to multiply by three.  However, we often want to
postpone such decisions as long as possible, to simplify/enable other
transformations.

	!isnan(x) && !finite(x) => isinf(x)
	!isnan(x) && !isnan(y) && isless(x,y) => x < y

etc...  Hence, I think that its RTL expansion that should lower isnan
to an UNORDERED instruction, when it doesn't have to worry about
SAVE_EXPR, it understands the ISA supported by the target, and can
leave tree-ssa to operate on high-level concepts such as "isnan".

Introducing calls to "isnan" is much harder than calls to "unorddf2",
as we can't ever be sure isnan is available in libm.a, but we can
always rely on functions in libgcc, or to be supported by the target.
Hence its safe to go "isnan -> unorddf2", but unsafe to go the other
way.

Roger
--



More information about the Gcc-patches mailing list