xref: /llvm-project/mlir/test/Dialect/Affine/value-bounds-op-interface-impl.mlir (revision 0aa831e0edb1c1deabb96ce2435667cc82bac79b)
1// RUN: mlir-opt %s -pass-pipeline='builtin.module(func.func(test-affine-reify-value-bounds))' -verify-diagnostics \
2// RUN:     -split-input-file | FileCheck %s
3
4// CHECK: #[[$map:.*]] = affine_map<()[s0, s1] -> (s0 + s1)>
5// CHECK-LABEL: func @affine_apply(
6//  CHECK-SAME:     %[[a:.*]]: index, %[[b:.*]]: index
7//       CHECK:   %[[apply:.*]] = affine.apply #[[$map]]()[%[[a]], %[[b]]]
8//       CHECK:   %[[apply:.*]] = affine.apply #[[$map]]()[%[[a]], %[[b]]]
9//       CHECK:   return %[[apply]]
10func.func @affine_apply(%a: index, %b: index) -> index {
11  %0 = affine.apply affine_map<()[s0, s1] -> (s0 + s1)>()[%a, %b]
12  %1 = "test.reify_bound"(%0) : (index) -> (index)
13  return %1 : index
14}
15
16// -----
17
18// CHECK-LABEL: func @affine_max_lb(
19//  CHECK-SAME:     %[[a:.*]]: index
20//       CHECK:   %[[c2:.*]] = arith.constant 2 : index
21//       CHECK:   return %[[c2]]
22func.func @affine_max_lb(%a: index) -> (index) {
23  // Note: There are two LBs: s0 and 2. FlatAffineValueConstraints always
24  // returns the constant one at the moment.
25  %1 = affine.max affine_map<()[s0] -> (s0, 2)>()[%a]
26  %2 = "test.reify_bound"(%1) {type = "LB"}: (index) -> (index)
27  return %2 : index
28}
29
30// -----
31
32func.func @affine_max_ub(%a: index) -> (index) {
33  %1 = affine.max affine_map<()[s0] -> (s0, 2)>()[%a]
34  // expected-error @below{{could not reify bound}}
35  %2 = "test.reify_bound"(%1) {type = "UB"}: (index) -> (index)
36  return %2 : index
37}
38
39// -----
40
41// CHECK-LABEL: func @affine_min_ub(
42//  CHECK-SAME:     %[[a:.*]]: index
43//       CHECK:   %[[c3:.*]] = arith.constant 3 : index
44//       CHECK:   return %[[c3]]
45func.func @affine_min_ub(%a: index) -> (index) {
46  // Note: There are two UBs: s0 + 1 and 3. FlatAffineValueConstraints always
47  // returns the constant one at the moment.
48  %1 = affine.min affine_map<()[s0] -> (s0, 2)>()[%a]
49  %2 = "test.reify_bound"(%1) {type = "UB"}: (index) -> (index)
50  return %2 : index
51}
52
53// -----
54
55func.func @affine_min_lb(%a: index) -> (index) {
56  %1 = affine.min affine_map<()[s0] -> (s0, 2)>()[%a]
57  // expected-error @below{{could not reify bound}}
58  %2 = "test.reify_bound"(%1) {type = "LB"}: (index) -> (index)
59  return %2 : index
60}
61
62// -----
63
64// CHECK-LABEL: func @composed_affine_apply(
65//       CHECK:   %[[cst:.*]] = arith.constant -8 : index
66//       CHECK:   return %[[cst]]
67func.func @composed_affine_apply(%i1 : index) -> (index) {
68  // The ValueBoundsOpInterface implementation of affine.apply fully composes
69  // the affine map (and its operands) with other affine.apply ops drawn from
70  // its operands before adding it to the constraint set. This is to work
71  // around a limitation in `FlatLinearConstraints`, which can currently not
72  // compute a constant bound for %s. (The affine map simplification logic can
73  // simplify %s to -8.)
74  %i2 = affine.apply affine_map<(d0) -> ((d0 floordiv 32) * 16)>(%i1)
75  %i3 = affine.apply affine_map<(d0) -> ((d0 floordiv 32) * 16 + 8)>(%i1)
76  %s = affine.apply affine_map<()[s0, s1] -> (s0 - s1)>()[%i2, %i3]
77  %reified = "test.reify_bound"(%s) {type = "EQ", constant} : (index) -> (index)
78  return %reified : index
79}
80
81
82// -----
83
84func.func @are_equal(%i1 : index) {
85  %i2 = affine.apply affine_map<(d0) -> ((d0 floordiv 32) * 16)>(%i1)
86  %i3 = affine.apply affine_map<(d0) -> ((d0 floordiv 32) * 16 + 8)>(%i1)
87  %s = affine.apply affine_map<()[s0, s1] -> (s0 - s1)>()[%i2, %i3]
88  // expected-remark @below{{false}}
89   "test.compare"(%i2, %i3) : (index, index) -> ()
90  return
91}
92
93// -----
94
95// Test for affine::fullyComposeAndCheckIfEqual
96func.func @composed_are_equal(%i1 : index) {
97  %i2 = affine.apply affine_map<(d0) -> ((d0 floordiv 32) * 16)>(%i1)
98  %i3 = affine.apply affine_map<(d0) -> ((d0 floordiv 32) * 16 + 8)>(%i1)
99  %s = affine.apply affine_map<()[s0, s1] -> (s0 - s1)>()[%i2, %i3]
100  // expected-remark @below{{different}}
101   "test.compare"(%i2, %i3) {compose} : (index, index) -> ()
102  return
103}
104
105// -----
106
107func.func @compare_affine_max(%a: index, %b: index) {
108  %0 = affine.max affine_map<()[s0, s1] -> (s0, s1)>()[%a, %b]
109  // expected-remark @below{{true}}
110  "test.compare"(%0, %a) {cmp = "GE"} : (index, index) -> ()
111  // expected-error @below{{unknown}}
112  "test.compare"(%0, %a) {cmp = "GT"} : (index, index) -> ()
113  // expected-remark @below{{false}}
114  "test.compare"(%0, %a) {cmp = "LT"} : (index, index) -> ()
115  // expected-error @below{{unknown}}
116  "test.compare"(%0, %a) {cmp = "LE"} : (index, index) -> ()
117  return
118}
119
120// -----
121
122func.func @compare_affine_min(%a: index, %b: index) {
123  %0 = affine.min affine_map<()[s0, s1] -> (s0, s1)>()[%a, %b]
124  // expected-error @below{{unknown}}
125  "test.compare"(%0, %a) {cmp = "GE"} : (index, index) -> ()
126  // expected-remark @below{{false}}
127  "test.compare"(%0, %a) {cmp = "GT"} : (index, index) -> ()
128  // expected-error @below{{unknown}}
129  "test.compare"(%0, %a) {cmp = "LT"} : (index, index) -> ()
130  // expected-remark @below{{true}}
131  "test.compare"(%0, %a) {cmp = "LE"} : (index, index) -> ()
132  return
133}
134
135// -----
136
137func.func @compare_const_map() {
138  %c5 = arith.constant 5 : index
139  // expected-remark @below{{true}}
140  "test.compare"(%c5) {cmp = "GT", rhs_map = affine_map<() -> (4)>}
141      : (index) -> ()
142  // expected-remark @below{{true}}
143  "test.compare"(%c5) {cmp = "LT", lhs_map = affine_map<() -> (4)>}
144      : (index) -> ()
145  return
146}
147
148// -----
149
150func.func @compare_maps(%a: index, %b: index) {
151  // expected-remark @below{{true}}
152  "test.compare"(%a, %b, %b, %a)
153      {cmp = "GT", lhs_map = affine_map<(d0, d1) -> (1 + d0 + d1)>,
154       rhs_map = affine_map<(d0, d1) -> (d0 + d1)>}
155      : (index, index, index, index) -> ()
156  return
157}
158
159// -----
160
161// CHECK-DAG: #[[$map1:.+]] = affine_map<()[s0] -> (s0 floordiv 15)>
162// CHECK-DAG: #[[$map2:.+]] = affine_map<()[s0] -> ((s0 mod 15) floordiv 5)>
163// CHECK-DAG: #[[$map3:.+]] = affine_map<()[s0] -> (s0 mod 5)>
164// CHECK-LABEL: func.func @delinearize_static
165// CHECK-SAME: (%[[arg0:.+]]: index)
166// CHECK-DAG: %[[v1:.+]] = affine.apply #[[$map1]]()[%[[arg0]]]
167// CHECK-DAG: %[[v2:.+]] = affine.apply #[[$map2]]()[%[[arg0]]]
168// CHECK-DAG: %[[v3:.+]] = affine.apply #[[$map3]]()[%[[arg0]]]
169// CHECK: return %[[v1]], %[[v2]], %[[v3]]
170func.func @delinearize_static(%arg0: index) -> (index, index, index) {
171  %c2 = arith.constant 2 : index
172  %c3 = arith.constant 3 : index
173  %0:3 = affine.delinearize_index %arg0 into (2, 3, 5) : index, index, index
174  %1 = "test.reify_bound"(%0#0) {type = "EQ"} : (index) -> (index)
175  %2 = "test.reify_bound"(%0#1) {type = "EQ"} : (index) -> (index)
176  %3 = "test.reify_bound"(%0#2) {type = "EQ"} : (index) -> (index)
177  // expected-remark @below{{true}}
178  "test.compare"(%0#0, %c2) {cmp = "LT"} : (index, index) -> ()
179  // expected-remark @below{{true}}
180  "test.compare"(%0#1, %c3) {cmp = "LT"} : (index, index) -> ()
181  return %1, %2, %3 : index, index, index
182}
183
184// -----
185
186// CHECK-DAG: #[[$map1:.+]] = affine_map<()[s0] -> (s0 floordiv 15)>
187// CHECK-DAG: #[[$map2:.+]] = affine_map<()[s0] -> ((s0 mod 15) floordiv 5)>
188// CHECK-DAG: #[[$map3:.+]] = affine_map<()[s0] -> (s0 mod 5)>
189// CHECK-LABEL: func.func @delinearize_static_no_outer_bound
190// CHECK-SAME: (%[[arg0:.+]]: index)
191// CHECK-DAG: %[[v1:.+]] = affine.apply #[[$map1]]()[%[[arg0]]]
192// CHECK-DAG: %[[v2:.+]] = affine.apply #[[$map2]]()[%[[arg0]]]
193// CHECK-DAG: %[[v3:.+]] = affine.apply #[[$map3]]()[%[[arg0]]]
194// CHECK: return %[[v1]], %[[v2]], %[[v3]]
195func.func @delinearize_static_no_outer_bound(%arg0: index) -> (index, index, index) {
196  %c2 = arith.constant 2 : index
197  %c3 = arith.constant 3 : index
198  %0:3 = affine.delinearize_index %arg0 into (3, 5) : index, index, index
199  %1 = "test.reify_bound"(%0#0) {type = "EQ"} : (index) -> (index)
200  %2 = "test.reify_bound"(%0#1) {type = "EQ"} : (index) -> (index)
201  %3 = "test.reify_bound"(%0#2) {type = "EQ"} : (index) -> (index)
202  "test.compaare"(%0#0, %c2) {cmp = "LT"} : (index, index) -> ()
203  // expected-remark @below{{true}}
204  "test.compare"(%0#1, %c3) {cmp = "LT"} : (index, index) -> ()
205  return %1, %2, %3 : index, index, index
206}
207
208// -----
209
210// CHECK: #[[$map:.+]] = affine_map<()[s0, s1] -> (s0 + s1 * 3)>
211// CHECK-LABEL: func.func @linearize_static
212// CHECK-SAME: (%[[arg0:.+]]: index, %[[arg1:.+]]: index)
213// CHECK: %[[v1:.+]] = affine.apply #[[$map]]()[%[[arg1]], %[[arg0]]]
214// CHECK: return %[[v1]]
215func.func @linearize_static(%arg0: index, %arg1: index)  -> index {
216  %c6 = arith.constant 6 : index
217  %0 = affine.linearize_index disjoint [%arg0, %arg1] by (2, 3) : index
218  %1 = "test.reify_bound"(%0) {type = "EQ"} : (index) -> (index)
219  // expected-remark @below{{true}}
220  "test.compare"(%0, %c6) {cmp = "LT"} : (index, index) -> ()
221  return %1 : index
222}
223
224// -----
225
226// CHECK: #[[$map:.+]] = affine_map<()[s0, s1] -> (s0 + s1 * 3)>
227// CHECK-LABEL: func.func @linearize_static_no_outer_bound
228// CHECK-SAME: (%[[arg0:.+]]: index, %[[arg1:.+]]: index)
229// CHECK: %[[v1:.+]] = affine.apply #[[$map]]()[%[[arg1]], %[[arg0]]]
230// CHECK: return %[[v1]]
231func.func @linearize_static_no_outer_bound(%arg0: index, %arg1: index)  -> index {
232  %c6 = arith.constant 6 : index
233  %0 = affine.linearize_index disjoint [%arg0, %arg1] by (3) : index
234  %1 = "test.reify_bound"(%0) {type = "EQ"} : (index) -> (index)
235  // expected-error @below{{unknown}}
236  "test.compare"(%0, %c6) {cmp = "LT"} : (index, index) -> ()
237  return %1 : index
238}
239