Why does FPBinOp(X, undef) -> NaN?

I came across this comment in SelectionDAG.cpp:

  case ISD::FADD:
  case ISD::FSUB:
  case ISD::FMUL:
  case ISD::FDIV:
  case ISD::FREM:
    // If both operands are undef, the result is undef. If 1 operand is undef,
    // the result is NaN. This should match the behavior of the IR optimizer.

That isn't intuitive to me. I would have expected a binary FP
operation with one undef operand to fold to undef. Does anyone know
the reasoning behind that decision? I don't see the value added in
returning a NaN here.

Thx,
Cameron

It's not correct (output of Alive2):

define half @fn(half %a) {
   %b = fadd half %a, undef
   ret half %b
}
=>
define half @fn(half %a) {
   ret half undef
}
Transformation doesn't verify!
ERROR: Value mismatch

Example:
half %a = #x0e02 (0.000366687774?)

Source:
half %b = NaN [based on undef value]

Target:
Source value: NaN
Target value: #x8000 (-0.0)

Essentially, for some inputs, doing an operation with any value can't produce some value, as the example above shows.

Nuno

Quoting Cameron McInally via llvm-dev <llvm-dev@lists.llvm.org>:

For reference, the IR side of this was:

For reference, the IR side of this was:
https://reviews.llvm.org/D44308

Ok, I can buy that. We're picking NaN for the value of the undef
operand since the result will always be a NaN.

So a few lines below this, we have something similar for integer operations:

    case ISD::ADD:
    case ISD::SUB:
    case ISD::UDIV:
    case ISD::SDIV:
    case ISD::UREM:
    case ISD::SREM:
      return getUNDEF(VT); // fold op(arg1, undef) -> undef

What's the reasoning behind folding to undef here? Would that fall
into the same "any value can't produce some value" bin?

>
> It's not correct (output of Alive2):
>
> define half @fn(half %a) {
> %b = fadd half %a, undef
> ret half %b
> }
> =>
> define half @fn(half %a) {
> ret half undef
> }
> Transformation doesn't verify!
> ERROR: Value mismatch
>
> Example:
> half %a = #x0e02 (0.000366687774?)
>
> Source:
> half %b = NaN [based on undef value]
>
> Target:
> Source value: NaN
> Target value: #x8000 (-0.0)
>
>
> Essentially, for some inputs, doing an operation with any value can't
> produce some value, as the example above shows.

Ok, I can buy that. We're picking NaN for the value of the undef
operand since the result will always be a NaN.

So a few lines below this, we have something similar for integer operations:

    case ISD::ADD:
    case ISD::SUB:

    case ISD::UDIV:
    case ISD::SDIV:
    case ISD::UREM:
    case ISD::SREM:
      return getUNDEF(VT); // fold op(arg1, undef) -> undef

For these 4 - because divisor 'undef' can be defined to any value, including 0,
but divisor can't be 0..

That makes sense. It's undefined behavior, so the "some value" as
output is fine.

The ADD and SUB I don't understand. Perhaps it's because there's no
single value for undef that will always give one defined result? Is
that a requirement?