cjm345
February 7, 2020, 5:20pm
#1
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
nlopes
February 7, 2020, 5:29pm
#2
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
cjm345
February 7, 2020, 6:27pm
#5
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..
cjm345
February 7, 2020, 7:12pm
#7
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?