To explain more in detail, I have sorted out some examples to trigger this undefined behavior.
import tvm
expr = tvm.tir.Div(tvm.tir.IntImm('int64', 0x8000000000000000), tvm.tir.IntImm('int64', -1))
analyzer = tvm.arith.Analyzer()
analyzer.rewrite_simplify(expr)
import tvm
expr = tvm.tir.Mod(tvm.tir.IntImm('int64', 0x8000000000000000), tvm.tir.IntImm('int64', -1))
analyzer = tvm.arith.Analyzer()
analyzer.rewrite_simplify(expr)
import tvm
expr = tvm.tir.FloorDiv(tvm.tir.IntImm('int64', 0x8000000000000000), tvm.tir.IntImm('int64', -1))
analyzer = tvm.arith.Analyzer()
analyzer.rewrite_simplify(expr)
import tvm
expr = tvm.tir.FloorMod(tvm.tir.IntImm('int64', 0x8000000000000000), tvm.tir.IntImm('int64', -1))
analyzer = tvm.arith.Analyzer()
analyzer.rewrite_simplify(expr)
The root causes of these four test cases are located in src/arith/const_fold.h, as they only check whether the divisor is zero.
Similarly, the following two cases will also cause an arithmetic error.
import tvm
from tvm import tir
expr = tir.Div(tir.Div(tir.Cast('int32', 2.95148e+28), tir.atan(tir.IntImm('int32',1))), tir.FloorMod(101, 11))
analyzer = tvm.arith.Analyzer()
analyzer.rewrite_simplify(expr)
import tvm
from tvm import tir
expr = tir.Div(tir.FloorDiv(tir.Cast('int32', 2.95148e+28), tir.atan(tir.IntImm('int32',1))), tir.FloorMod(101, 11))
analyzer = tvm.arith.Analyzer()
analyzer.rewrite_simplify(expr)
This is because the function InfAwareDiv
and InfAwareFloorDiv
in src/arith/const_int_bound.cc also forget to cover this UB.
static int64_t InfAwareDiv(int64_t x, int64_t y) {
ICHECK_NE(y, 0);
if (x == kPosInf || x == kNegInf) {
if (y > 0) return x;
return -x;
}
return x / y;
}
static int64_t InfAwareFloorDiv(int64_t x, int64_t y) {
ICHECK_NE(y, 0);
if (x == kPosInf || x == kNegInf) {
if (y > 0) return x;
return -x;
}
return floordiv(x, y);
}