Which exactly was the plan?
Add a new, regular instruction?
Add a new constrained math intrinsic?
Both?
I'd like to add an explicit FNEG IR operator. We would not need a
constrained FNEG operator if we go this route.
Andrew Kaylor made a good point here:
- As I said, all LLVM IR FP instructions are //assumed// to have no
side effects. I'm not sure we want an instruction that goes beyond this to
be //defined// as having no side effects. It adds a complication to the
language and introduces restrictions on the code generator that aren't
needed in the ordinary case of non-constrained FP. The target code
generators are free to do anything they want with the other FP
instructions, including things that introduce new FP status flags being set
that otherwise wouldn't be, and for the normal case the back ends should be
free to do that with fneg as well.
Personally, I’m not sure I like the idea of having exceptions to the rule
that FP instructions also have constrained versions. So I lean towards
having both a regular FNEG and a constrained version.
But I think I remember pushback. I can’t put my fingers on the message,
though.
We touched on this in the Differential Review and on this thread. To
summarize:
FNEG(X) is not really the same operation as FSUB(-0.0, X), although the
differences are admittedly subtle. I even went as far to say that any
xforms between the two operations should only occur under FastMath
conditions. If we follow those rules, I think emergence guarantees that we
don't have to worry about the side effects of FNEG (please correct me if
I've missed something).
Extending on that, I suspect that we should not be canonicalizing FNEG(X)
as FSUB(-0.0, X), but rather as XOR(X, 1 << (SIZE_OF_TYPE_IN_BITS - 1)). A
utility function could provide us with the sign-bit constant, so it's not
that ugly.
That said, I agree that Andrew's take is compelling. And I would be okay
with adding a constrained FNEG to solve the immediate issue, if that is the
final decision.