Skip to content

Commit 74603ee

Browse files
author
neildhickey
authored
[Arith] ConstIntBound was incorrectly assuming bounds were over int64… (#13918)
[Arith] ConstIntBound was incorrectly assuming bounds were over int64_t range This commit improved the floormod and floordiv conversion check to be simpler for the negative range and adds a test to cover all integer data types.
1 parent 54a62c1 commit 74603ee

File tree

3 files changed

+121
-7
lines changed

3 files changed

+121
-7
lines changed

src/tir/transforms/lower_intrin.cc

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -118,9 +118,8 @@ class IntrinInjecter : public tvm::arith::IRMutatorWithAnalyzer {
118118
// If the numerator's lower bound is known, express the floordiv
119119
// in terms of truncdiv using only positive operands.
120120
arith::ConstIntBound const_int_bound = analyzer_->const_int_bound(op->a);
121-
if (const_int_bound->min_value != arith::ConstIntBound::kNegInf &&
122-
const_int_bound->min_value < 0 &&
123-
const_int_bound->min_value > Downcast<IntImm>(tvm::min_value(op->a->dtype))->value) {
121+
if (const_int_bound->min_value < 0 &&
122+
const_int_bound->min_value > -(Downcast<IntImm>(tvm::max_value(op->a->dtype))->value)) {
124123
// The goal is to write floordiv(a,b) in terms of truncdiv, without using
125124
// negative operands.
126125
//
@@ -214,9 +213,8 @@ class IntrinInjecter : public tvm::arith::IRMutatorWithAnalyzer {
214213
// If the numerator's lower bound is known, express the floormod
215214
// in terms of truncmod using only positive operands.
216215
arith::ConstIntBound const_int_bound = analyzer_->const_int_bound(op->a);
217-
if (const_int_bound->min_value != arith::ConstIntBound::kNegInf &&
218-
const_int_bound->min_value < 0 &&
219-
const_int_bound->min_value > Downcast<IntImm>(tvm::min_value(op->a->dtype))->value) {
216+
if (const_int_bound->min_value < 0 &&
217+
const_int_bound->min_value > -(Downcast<IntImm>(tvm::max_value(op->a->dtype))->value)) {
220218
// The goal is to write floormod(a,b) in terms of truncdiv and truncmod,
221219
// without using negative operands.
222220
//
Lines changed: 117 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,117 @@
1+
# Licensed to the Apache Software Foundation (ASF) under one
2+
# or more contributor license agreements. See the NOTICE file
3+
# distributed with this work for additional information
4+
# regarding copyright ownership. The ASF licenses this file
5+
# to you under the Apache License, Version 2.0 (the
6+
# "License"); you may not use this file except in compliance
7+
# with the License. You may obtain a copy of the License at
8+
#
9+
# http://www.apache.org/licenses/LICENSE-2.0
10+
#
11+
# Unless required by applicable law or agreed to in writing,
12+
# software distributed under the License is distributed on an
13+
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
14+
# KIND, either express or implied. See the License for the
15+
# specific language governing permissions and limitations
16+
# under the License.
17+
import numpy as np
18+
import pytest
19+
import tvm
20+
from tvm import te
21+
import tvm.testing
22+
from tvm.script import tir
23+
24+
25+
def test_floor_div_op():
26+
target = "llvm"
27+
dev = tvm.device(target)
28+
N = 100
29+
divisor = 5
30+
31+
@tir.prim_func
32+
def func_64(
33+
A: tir.Buffer((N + 100, 2), "int64"),
34+
B: tir.Buffer((N), "int64"),
35+
C: tir.Buffer((N), "int64"),
36+
):
37+
for i in tir.serial(N):
38+
with tir.block("A"):
39+
v_i = tir.axis.spatial(N, i)
40+
A[v_i, 0] = tir.floordiv(C[v_i] - tir.max_value("int64"), divisor)
41+
A[v_i, 1] = tir.floormod(C[v_i] - tir.max_value("int64"), divisor)
42+
A[v_i + 100, 0] = tir.floordiv(B[v_i], divisor)
43+
A[v_i + 100, 1] = tir.floormod(B[v_i], divisor)
44+
45+
@tir.prim_func
46+
def func_32(
47+
A: tir.Buffer((N + 100, 2), "int32"),
48+
B: tir.Buffer((N), "int32"),
49+
C: tir.Buffer((N), "int32"),
50+
):
51+
for i in tir.serial(N):
52+
with tir.block("A"):
53+
v_i = tir.axis.spatial(N, i)
54+
A[v_i, 0] = tir.floordiv(C[v_i] - tir.max_value("int32"), divisor)
55+
A[v_i, 1] = tir.floormod(C[v_i] - tir.max_value("int32"), divisor)
56+
A[v_i + 100, 0] = tir.floordiv(B[v_i], divisor)
57+
A[v_i + 100, 1] = tir.floormod(B[v_i], divisor)
58+
59+
@tir.prim_func
60+
def func_16(
61+
A: tir.Buffer((N + 100, 2), "int16"),
62+
B: tir.Buffer((N), "int16"),
63+
C: tir.Buffer((N), "int16"),
64+
):
65+
for i in tir.serial(N):
66+
with tir.block("A"):
67+
v_i = tir.axis.spatial(N, i)
68+
A[v_i, 0] = tir.floordiv(C[v_i] - tir.max_value("int16"), divisor)
69+
A[v_i, 1] = tir.floormod(C[v_i] - tir.max_value("int16"), divisor)
70+
A[v_i + 100, 0] = tir.floordiv(B[v_i], divisor)
71+
A[v_i + 100, 1] = tir.floormod(B[v_i], divisor)
72+
73+
@tir.prim_func
74+
def func_8(
75+
A: tir.Buffer((N + 100, 2), "int8"), B: tir.Buffer((N), "int8"), C: tir.Buffer((N), "int8")
76+
):
77+
for i in tir.serial(N):
78+
with tir.block("A"):
79+
v_i = tir.axis.spatial(N, i)
80+
A[v_i, 0] = tir.floordiv(C[v_i] - tir.max_value("int8"), divisor)
81+
A[v_i, 1] = tir.floormod(C[v_i] - tir.max_value("int8"), divisor)
82+
A[v_i + 100, 0] = tir.floordiv(B[v_i], divisor)
83+
A[v_i + 100, 1] = tir.floormod(B[v_i], divisor)
84+
85+
for opfunc, type in [
86+
(func_8, "int8"),
87+
(func_16, "int16"),
88+
(func_32, "int32"),
89+
(func_64, "int64"),
90+
]:
91+
built = tvm.build(opfunc, target=target)
92+
x_data = np.random.randint(te.min_value(type), te.max_value(type), size=(100), dtype=type)
93+
y_data = np.asarray([i for i in range(N)], dtype=type)
94+
95+
a_dev = tvm.nd.empty([N + 100, 2], type, dev)
96+
b_dev = tvm.nd.array(x_data, dev)
97+
c_dev = tvm.nd.array(y_data, dev)
98+
99+
built(a_dev, b_dev, c_dev)
100+
101+
a = a_dev.numpy()
102+
b = b_dev.numpy()
103+
c = c_dev.numpy()
104+
105+
# python modulo behaves a bit different to tvm floormod for negative numbers
106+
for i in range(N + 100):
107+
if a[i, 1] < 0:
108+
a[i, 1] = divisor + a[i, 1]
109+
110+
np.testing.assert_array_equal(a[:100, 0], (c - te.max_value(type)) // divisor)
111+
np.testing.assert_array_equal(a[:100, 1], (c - te.max_value(type)) % divisor)
112+
np.testing.assert_array_equal(a[100 : N + 100, 0], b // divisor)
113+
np.testing.assert_array_equal(a[100 : N + 100, 1], b % divisor)
114+
115+
116+
if __name__ == "__main__":
117+
tvm.testing.main()

tests/python/topi/python/test_topi_transform.py

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -859,7 +859,6 @@ def test_dynamic_strided_slice():
859859
verify_dynamic_strided_slice((3, 4, 3), [0, 2, 0], [1, 2, 3])
860860

861861

862-
@tvm.testing.requires_gpu
863862
@tvm.testing.uses_gpu
864863
def test_strided_set():
865864
verify_strided_set((3, 4, 3), (3, 2, 2), [0, 3, 0], [4, 1, 4], [1, -1, 2])

0 commit comments

Comments
 (0)