I have a question about the correct way to treat the devision-by-zero case of arith.divf
op. When convering the upper dialect op (e.g. complex.abs
) to the arith dialect using arith.divf
), who is responsible for taking care of making sure the denominator is not zero? I think whether it causes the crash depends on how arith.divf
is lowered. But from the user point of view of arith.divf
, is it possible to pass the possibly zero value to the denominator of arith.divf
?
I want to know how the devision-by-zero semantics of the arith.divf
op is defined in general.
See: [mlir][complex] Prevent underflow in complex.abs by Lewuathe · Pull Request #76316 · llvm/llvm-project · GitHub
Division by zero is usually undefined behavior. For integer division, some hardware can trap, others just return zero. For floating-point division, there’s the IEEE754 definitions (± inf, NaN, etc) which will be implemented by hardware.
In the context of your PR, I don’t think you can wrap division with conditionals because you don’t know what to do in the else
case. Trap? Set the value to zero? These are the decisions that are made by the language and the hardware, not the IR.
The main problem here is that you don’t know the program semantics anymore (you’re working with IR, not some language’s AST), but you also don’t know the semantics of the hardware (if it traps of not). So at this point it is just not possible to make any decision safely.
@rengolin Thank you so much for answering my question. From the IR viewpoint, we can keep it undefined. The language frontend or the hardware should be responsible for how to treat the decision-by-zero case. That clarifies everything to me.
That’s a C/C++ thing though?
LLVM is explicit on integer division, but does not mention anything (curiously?) for floating point: https://llvm.org/docs/LangRef.html#fdiv-instruction.
In MLIR we define clearly arith.divsi
and arith.divui
has having undefined behavior, while we don’t for arith.fdiv
. We also define the integer division as conditionally-speculatable (checking if the denominator is known-non-zero), while the floating-point division is considered “pure” in the Arith dialect at the moment.
1 Like
Right, thus “usually”. Different languages can implement different semantics, for example force a trap or a specific behaviour.
Same for LLVM: udiv, sdiv, fdiv.
This is because IEEE745 defines the behaviour and hardware architectures follow, while integer division isn’t defined, and some architectures trap others do not.
1 Like