Many parts of our code base relies on integer simplifications that involves
div/mod. These simplifications are in particular tricky due to the different
division mode, and the dependence on knowing the sign of the operand.
Here is a list of division variants:
## Trunc div/mod
IEEE standard integer division is truncated division, directly maps to the
hardware. This is the division used by C and TVM by default. The problem of
trunc div is that we usually relies on knowing the sign of both operands. For
example, we cannot simplify ```(x * 4 + 3)/4 => x ``` if x can be negative.
## Floor div/mod
Always round down. This is the division mode adopted by python. To simplify
floordiv, we usually need to know the sign of divisor, but not necessarily the
sign of dividend ```floordiv(x * 4 + 3,4) => x ```.
## Euclidean div/mod
Always ensures that the remainder is non-negative. This is the division mode
used by Halide by default. Note that when the divisor is positive, Euclidean
and floordiv are equivalent. But floordiv will produce a negative remainder
when the divisor is negative.
## Discussion
Different division mode has its own advantage and disadvantages. While Floor
and Euclidean mode enjoys better invariance in simplification. We will have
some trouble lowering them into the trunc div/mod, especially when we do not
know the sign. In general, it is good to know the sign when lowering. However,
this will leads to some slight differences, consider the following case:
```c++
for (x = 0; x < 100; x++) {
// trunc division
a [(x * 5 + 3)/ 4] = xyz.
}
```
```(x * 5 + 3)/4``` can be simplified to (x * 5 /4) , if we setup the
simplifier, with currect context(```x in [0, 100]```). However, there can be
cases where we forget to do so in our code, i that scenario the simplifcation
cannot be done. If instead we use
```c++
for (x = 0; x < 100; x++) {
// floor division
a [floordiv(x * 5 + 3, 4)] = xyz.
}
```
```(x * 5 + 3)/4``` can be simplified to floordiv(x * 5, 4) in the analysis.
However, to get the most efficient version of the code. We need to lower the
floor division to ```x * 5 / 4``` knowing that x is non-negative. The context
information is only needed during the floor division lowering.
In summary, using trunc div during analysis requires m
ore information each time we transform it, using floor/euclidean div makes
simplification easier, but still requires us to provide context information to
most efficiently lowers to trunc div/mod.
## Proposal to be Discussed: Adding Floor Div/Mod
It might be helpful to encourage the use of floor div/mod for integer analysis
while providing an effective way to lower to trunc div when necessary. To avoid
confusion between division mode, I propose we add an explicit floordiv/floormod
node and operator to the IR.
The reason to choose floordiv/mod over Euclidean is mainly due to floor is more
common(used by python) and easier to understand. The difference in behavior
happens when the divisor is negative, and in most cases, we will know the sign
of divisor.
The original truc div/mod simplification will be kept around for a while, but
we will encourage most index calculations to use floordiv/mod, and provide
rewriter to rewrite truc div/mod into floor version when the sign of the
dividend is positive
--
You are receiving this because you are subscribed to this thread.
Reply to this email directly or view it on GitHub:
https://github.com/dmlc/tvm/issues/3478