[AArch64] Add cost model for @experimental.vector.match (#118512)
[llvm-project.git] / mlir / test / Transforms / remove-dead-values.mlir
blob9273ac01e7ccecde2fd0f957323d589ba5157095
1 // RUN: mlir-opt %s -remove-dead-values -split-input-file -verify-diagnostics | FileCheck %s
3 // The IR is updated regardless of memref.global private constant
4 //
5 module {
6   // CHECK: memref.global "private" constant @__constant_4xi32 : memref<4xi32> = dense<[1, 2, 3, 4]> {alignment = 16 : i64}
7   memref.global "private" constant @__constant_4xi32 : memref<4xi32> = dense<[1, 2, 3, 4]> {alignment = 16 : i64}
8   func.func @main(%arg0: i32) -> i32 {
9     %0 = tensor.empty() : tensor<10xbf16>
10     // CHECK-NOT: memref.get_global
11     %1 = memref.get_global @__constant_4xi32 : memref<4xi32>
12     // CHECK-NOT: tensor.empty
13     return %arg0 : i32
14   }
17 // -----
19 // Dead values are removed from the IR even if the module has a name
21 module @named_module_acceptable {
22   func.func @main(%arg0: tensor<10xf32>) -> tensor<10xf32> {
23     %0 = tensor.empty() : tensor<10xbf16>
24     // CHECK-NOT: tensor.empty
25     return %arg0 : tensor<10xf32>
26   }
29 // -----
31 // The IR contains both conditional and unconditional branches with a loop
32 // in which the last cf.cond_br is referncing the first cf.br
34 func.func @acceptable_ir_has_cleanable_loop_of_conditional_and_branch_op(%arg0: i1) {
35   %non_live = arith.constant 0 : i32
36   // CHECK-NOT: arith.constant
37   cf.br ^bb1(%non_live : i32)
38   // CHECK: cf.br ^[[BB1:bb[0-9]+]]
39 ^bb1(%non_live_1 : i32):
40   // CHECK: ^[[BB1]]:
41   %non_live_5 = arith.constant 1 : i32
42   cf.br ^bb3(%non_live_1, %non_live_5 : i32, i32)
43   // CHECK: cf.br ^[[BB3:bb[0-9]+]]
44   // CHECK-NOT: i32
45 ^bb3(%non_live_2 : i32, %non_live_6 : i32):
46   // CHECK: ^[[BB3]]:
47   cf.cond_br %arg0, ^bb1(%non_live_2 : i32), ^bb4(%non_live_2 : i32)
48   // CHECK: cf.cond_br %arg0, ^[[BB1]], ^[[BB4:bb[0-9]+]]
49 ^bb4(%non_live_4 : i32):
50   // CHECK: ^[[BB4]]:
51   return
54 // -----
56 // Checking that iter_args are properly handled
58 func.func @cleanable_loop_iter_args_value(%arg0: index) -> index {
59   %c0 = arith.constant 0 : index
60   %c1 = arith.constant 1 : index
61   %c10 = arith.constant 10 : index
62   %non_live = arith.constant 0 : index
63   // CHECK: [[RESULT:%.+]] = scf.for [[ARG_1:%.*]] = %c0 to %c10 step %c1 iter_args([[ARG_2:%.*]] = %arg0) -> (index) {
64   %result, %result_non_live = scf.for %i = %c0 to %c10 step %c1 iter_args(%live_arg = %arg0, %non_live_arg = %non_live) -> (index, index) {
65     // CHECK: [[SUM:%.+]] = arith.addi [[ARG_2]], [[ARG_1]] : index
66     %new_live = arith.addi %live_arg, %i : index
67     // CHECK: scf.yield [[SUM:%.+]]
68     scf.yield %new_live, %non_live_arg : index, index
69   }
70   // CHECK: return [[RESULT]] : index
71   return %result : index
74 // -----
76 // Note that this cleanup cannot be done by the `canonicalize` pass.
78 // CHECK-LABEL: func.func private @clean_func_op_remove_argument_and_return_value() {
79 // CHECK-NEXT:    return
80 // CHECK-NEXT:  }
81 // CHECK:       func.func @main(%[[arg0:.*]]: i32) {
82 // CHECK-NEXT:    call @clean_func_op_remove_argument_and_return_value() : () -> ()
83 // CHECK-NEXT:    return
84 // CHECK-NEXT:  }
85 func.func private @clean_func_op_remove_argument_and_return_value(%arg0: i32) -> (i32) {
86   return %arg0 : i32
88 func.func @main(%arg0 : i32) {
89   %non_live = func.call @clean_func_op_remove_argument_and_return_value(%arg0) : (i32) -> (i32)
90   return
93 // -----
95 // %arg0 is not live because it is never used. %arg1 is not live because its
96 // user `arith.addi` doesn't have any uses and the value that it is forwarded to
97 // (%non_live_0) also doesn't have any uses.
99 // Note that this cleanup cannot be done by the `canonicalize` pass.
101 // CHECK-LABEL: func.func private @clean_func_op_remove_arguments() -> i32 {
102 // CHECK-NEXT:    %[[c0:.*]] = arith.constant 0
103 // CHECK-NEXT:    return %[[c0]]
104 // CHECK-NEXT:  }
105 // CHECK:       func.func @main(%[[arg2:.*]]: memref<i32>, %[[arg3:.*]]: i32, %[[DEVICE:.*]]: i32) -> (i32, memref<i32>) {
106 // CHECK-NEXT:    %[[live:.*]] = test.call_on_device @clean_func_op_remove_arguments(), %[[DEVICE]] : (i32) -> i32
107 // CHECK-NEXT:    return %[[live]], %[[arg2]]
108 // CHECK-NEXT:  }
109 func.func private @clean_func_op_remove_arguments(%arg0 : memref<i32>, %arg1 : i32) -> (i32, i32) {
110   %c0 = arith.constant 0 : i32
111   %non_live = arith.addi %arg1, %arg1 : i32
112   return %c0, %arg1 : i32, i32
114 func.func @main(%arg2 : memref<i32>, %arg3 : i32, %device : i32) -> (i32, memref<i32>) {
115   %live, %non_live_0 = test.call_on_device @clean_func_op_remove_arguments(%arg2, %arg3), %device : (memref<i32>, i32, i32) -> (i32, i32)
116   return %live, %arg2 : i32, memref<i32>
119 // -----
121 // Even though %non_live_0 is not live, the first return value of
122 // @clean_func_op_remove_return_values isn't removed because %live is live
123 // (liveness is checked across all callers).
125 // Also, the second return value of @clean_func_op_remove_return_values is
126 // removed despite %c0 being live because neither %non_live nor %non_live_1 were
127 // live (removal doesn't depend on the liveness of the operand itself but on the
128 // liveness of where it is forwarded).
130 // Note that this cleanup cannot be done by the `canonicalize` pass.
132 // CHECK:       func.func private @clean_func_op_remove_return_values(%[[arg0:.*]]: memref<i32>) -> i32 {
133 // CHECK-NEXT:    %[[c0]] = arith.constant 0
134 // CHECK-NEXT:    memref.store %[[c0]], %[[arg0]][]
135 // CHECK-NEXT:    return %[[c0]]
136 // CHECK-NEXT:  }
137 // CHECK:       func.func @main(%[[arg1:.*]]: memref<i32>) -> i32 {
138 // CHECK-NEXT:    %[[live:.*]] = call @clean_func_op_remove_return_values(%[[arg1]]) : (memref<i32>) -> i32
139 // CHECK-NEXT:    %[[non_live_0:.*]] = call @clean_func_op_remove_return_values(%[[arg1]]) : (memref<i32>) -> i32
140 // CHECK-NEXT:    return %[[live]] : i32
141 // CHECK-NEXT:  }
142 func.func private @clean_func_op_remove_return_values(%arg0 : memref<i32>) -> (i32, i32) {
143   %c0 = arith.constant 0 : i32
144   memref.store %c0, %arg0[] : memref<i32>
145   return %c0, %c0 : i32, i32
147 func.func @main(%arg1 : memref<i32>) -> (i32) {
148   %live, %non_live = func.call @clean_func_op_remove_return_values(%arg1) : (memref<i32>) -> (i32, i32)
149   %non_live_0, %non_live_1 = func.call @clean_func_op_remove_return_values(%arg1) : (memref<i32>) -> (i32, i32)
150   return %live : i32
153 // -----
155 // None of the return values of @clean_func_op_dont_remove_return_values can be
156 // removed because the first one is forwarded to a live value %live and the
157 // second one is forwarded to a live value %live_0.
159 // CHECK-LABEL: func.func private @clean_func_op_dont_remove_return_values() -> (i32, i32) {
160 // CHECK-NEXT:    %[[c0:.*]] = arith.constant 0 : i32
161 // CHECK-NEXT:    return %[[c0]], %[[c0]] : i32, i32
162 // CHECK-NEXT:  }
163 // CHECK-LABEL: func.func @main() -> (i32, i32) {
164 // CHECK-NEXT:    %[[live_and_non_live:.*]]:2 = call @clean_func_op_dont_remove_return_values() : () -> (i32, i32)
165 // CHECK-NEXT:    %[[non_live_0_and_live_0:.*]]:2 = call @clean_func_op_dont_remove_return_values() : () -> (i32, i32)
166 // CHECK-NEXT:    return %[[live_and_non_live]]#0, %[[non_live_0_and_live_0]]#1 : i32, i32
167 // CHECK-NEXT:  }
168 func.func private @clean_func_op_dont_remove_return_values() -> (i32, i32) {
169   %c0 = arith.constant 0 : i32
170   return %c0, %c0 : i32, i32
172 func.func @main() -> (i32, i32) {
173   %live, %non_live = func.call @clean_func_op_dont_remove_return_values() : () -> (i32, i32)
174   %non_live_0, %live_0 = func.call @clean_func_op_dont_remove_return_values() : () -> (i32, i32)
175   return %live, %live_0 : i32, i32
178 // -----
180 // Values kept:
181 //  (1) %non_live is not live. Yet, it is kept because %arg4 in `scf.condition`
182 //  forwards to it, which has to be kept. %arg4 in `scf.condition` has to be
183 //  kept because it forwards to %arg6 which is live.
185 //  (2) %arg5 is not live. Yet, it is kept because %live_0 forwards to it, which
186 //  also forwards to %live, which is live.
188 // Values not kept:
189 //  (1) %arg1 is not kept as an operand of `scf.while` because it only forwards
190 //  to %arg3, which is not kept. %arg3 is not kept because %arg3 is not live and
191 //  only %arg1 and %arg7 forward to it, such that neither of them forward
192 //  anywhere else. Thus, %arg7 is also not kept in the `scf.yield` op.
194 // Note that this cleanup cannot be done by the `canonicalize` pass.
196 // CHECK:       func.func @clean_region_branch_op_dont_remove_first_2_results_but_remove_first_operand(%[[arg0:.*]]: i1, %[[arg1:.*]]: i32, %[[arg2:.*]]: i32) -> i32 {
197 // CHECK-NEXT:    %[[live_and_non_live:.*]]:2 = scf.while (%[[arg4:.*]] = %[[arg2]]) : (i32) -> (i32, i32) {
198 // CHECK-NEXT:      %[[live_0:.*]] = arith.addi %[[arg4]], %[[arg4]]
199 // CHECK-NEXT:      scf.condition(%arg0) %[[live_0]], %[[arg4]] : i32, i32
200 // CHECK-NEXT:    } do {
201 // CHECK-NEXT:    ^bb0(%[[arg5:.*]]: i32, %[[arg6:.*]]: i32):
202 // CHECK-NEXT:      %[[live_1:.*]] = arith.addi %[[arg6]], %[[arg6]]
203 // CHECK-NEXT:      scf.yield %[[live_1]] : i32
204 // CHECK-NEXT:    }
205 // CHECK-NEXT:    return %[[live_and_non_live]]#0
206 // CHECK-NEXT:  }
207 func.func @clean_region_branch_op_dont_remove_first_2_results_but_remove_first_operand(%arg0: i1, %arg1: i32, %arg2: i32) -> (i32) {
208   %live, %non_live, %non_live_0 = scf.while (%arg3 = %arg1, %arg4 = %arg2) : (i32, i32) -> (i32, i32, i32) {
209     %live_0 = arith.addi %arg4, %arg4 : i32
210     %non_live_1 = arith.addi %arg3, %arg3 : i32
211     scf.condition(%arg0) %live_0, %arg4, %non_live_1 : i32, i32, i32
212   } do {
213   ^bb0(%arg5: i32, %arg6: i32, %arg7: i32):
214     %live_1 = arith.addi %arg6, %arg6 : i32
215     scf.yield %arg7, %live_1 : i32, i32
216   }
217   return %live : i32
220 // -----
222 // Values kept:
223 //  (1) %live is kept because it is live.
225 //  (2) %non_live is not live. Yet, it is kept because %arg3 in `scf.condition`
226 //  forwards to it and this %arg3 has to be kept. This %arg3 in `scf.condition`
227 //  has to be kept because it forwards to %arg6, which forwards to %arg4, which
228 //  forwards to %live, which is live.
230 // Values not kept:
231 //  (1) %non_live_0 is not kept because %non_live_2 in `scf.condition` forwards
232 //  to it, which forwards to only %non_live_0 and %arg7, where both these are
233 //  not live and have no other value forwarding to them.
235 //  (2) %non_live_1 is not kept because %non_live_3 in `scf.condition` forwards
236 //  to it, which forwards to only %non_live_1 and %arg8, where both these are
237 //  not live and have no other value forwarding to them.
239 //  (3) %c2 is not kept because it only forwards to %arg10, which is not kept.
241 //  (4) %arg10 is not kept because only %c2 and %non_live_4 forward to it, none
242 //  of them forward anywhere else, and %arg10 is not.
244 //  (5) %arg7 and %arg8 are not kept because they are not live, %non_live_2 and
245 //  %non_live_3 forward to them, and both only otherwise forward to %non_live_0
246 //  and %non_live_1 which are not live and have no other predecessors.
248 // Note that this cleanup cannot be done by the `canonicalize` pass.
250 // CHECK:       func.func @clean_region_branch_op_remove_last_2_results_last_2_arguments_and_last_operand(%[[arg2:.*]]: i1) -> i32 {
251 // CHECK-NEXT:    %[[c0:.*]] = arith.constant 0
252 // CHECK-NEXT:    %[[c1:.*]] = arith.constant 1
253 // CHECK-NEXT:    %[[live_and_non_live:.*]]:2 = scf.while (%[[arg3:.*]] = %[[c0]], %[[arg4:.*]] = %[[c1]]) : (i32, i32) -> (i32, i32) {
254 // CHECK-NEXT:      func.call @identity() : () -> ()
255 // CHECK-NEXT:      scf.condition(%[[arg2]]) %[[arg4]], %[[arg3]] : i32, i32
256 // CHECK-NEXT:    } do {
257 // CHECK-NEXT:    ^bb0(%[[arg5:.*]]: i32, %[[arg6:.*]]: i32):
258 // CHECK-NEXT:      scf.yield %[[arg5]], %[[arg6]] : i32, i32
259 // CHECK-NEXT:    }
260 // CHECK-NEXT:    return %[[live_and_non_live]]#0 : i32
261 // CHECK-NEXT:  }
262 // CHECK:       func.func private @identity() {
263 // CHECK-NEXT:    return
264 // CHECK-NEXT:  }
265 func.func @clean_region_branch_op_remove_last_2_results_last_2_arguments_and_last_operand(%arg2: i1) -> (i32) {
266   %c0 = arith.constant 0 : i32
267   %c1 = arith.constant 1 : i32
268   %c2 = arith.constant 2 : i32
269   %live, %non_live, %non_live_0, %non_live_1 = scf.while (%arg3 = %c0, %arg4 = %c1, %arg10 = %c2) : (i32, i32, i32) -> (i32, i32, i32, i32) {
270     %non_live_2 = arith.addi %arg10, %arg10 : i32
271     %non_live_3 = func.call @identity(%arg10) : (i32) -> (i32)
272     scf.condition(%arg2) %arg4, %arg3, %non_live_2, %non_live_3 : i32, i32, i32, i32
273   } do {
274   ^bb0(%arg5: i32, %arg6: i32, %arg7: i32, %arg8: i32):
275     %non_live_4 = arith.addi %arg7, %arg8 :i32
276     scf.yield %arg5, %arg6, %non_live_4 : i32, i32, i32
277   }
278   return %live : i32
280 func.func private @identity(%arg1 : i32) -> (i32) {
281   return %arg1 : i32
284 // -----
286 // The op isn't erased because it has memory effects but its unnecessary result
287 // is removed.
289 // Note that this cleanup cannot be done by the `canonicalize` pass.
291 // CHECK:       func.func @clean_region_branch_op_remove_result(%[[arg0:.*]]: index, %[[arg1:.*]]: memref<i32>) {
292 // CHECK-NEXT:    scf.index_switch %[[arg0]]
293 // CHECK-NEXT:    case 1 {
294 // CHECK-NEXT:      %[[c10:.*]] = arith.constant 10
295 // CHECK-NEXT:      memref.store %[[c10]], %[[arg1]][]
296 // CHECK-NEXT:      scf.yield
297 // CHECK-NEXT:    }
298 // CHECK-NEXT:    default {
299 // CHECK-NEXT:    }
300 // CHECK-NEXT:    return
301 // CHECK-NEXT:  }
302 func.func @clean_region_branch_op_remove_result(%arg0 : index, %arg1 : memref<i32>) {
303   %non_live = scf.index_switch %arg0 -> i32
304   case 1 {
305     %c10 = arith.constant 10 : i32
306     memref.store %c10, %arg1[] : memref<i32>
307     scf.yield %c10 : i32
308   }
309   default {
310     %c11 = arith.constant 11 : i32
311     scf.yield %c11 : i32
312   }
313   return
316 // -----
318 // The simple ops which don't have memory effects or live results get removed.
319 // %arg5 doesn't get removed from the @main even though it isn't live because
320 // the signature of a public function is always left untouched.
322 // Note that this cleanup cannot be done by the `canonicalize` pass.
324 // CHECK:       func.func private @clean_simple_ops(%[[arg0:.*]]: i32, %[[arg1:.*]]: memref<i32>)
325 // CHECK-NEXT:    %[[live_0:.*]] = arith.addi %[[arg0]], %[[arg0]]
326 // CHECK-NEXT:    %[[c2:.*]] = arith.constant 2
327 // CHECK-NEXT:    %[[live_1:.*]] = arith.muli %[[live_0]], %[[c2]]
328 // CHECK-NEXT:    %[[c3:.*]] = arith.constant 3
329 // CHECK-NEXT:    %[[live_2:.*]] = arith.addi %[[arg0]], %[[c3]]
330 // CHECK-NEXT:    memref.store %[[live_2]], %[[arg1]][]
331 // CHECK-NEXT:    return %[[live_1]]
332 // CHECK-NEXT:  }
333 // CHECK:       func.func @main(%[[arg3:.*]]: i32, %[[arg4:.*]]: memref<i32>, %[[arg5:.*]]
334 // CHECK-NEXT:    %[[live:.*]] = call @clean_simple_ops(%[[arg3]], %[[arg4]])
335 // CHECK-NEXT:    return %[[live]]
336 // CHECK-NEXT:  }
337 func.func private @clean_simple_ops(%arg0 : i32, %arg1 : memref<i32>, %arg2 : i32) -> (i32, i32, i32, i32) {
338   %live_0 = arith.addi %arg0, %arg0 : i32
339   %c2 = arith.constant 2 : i32
340   %live_1 = arith.muli %live_0, %c2 : i32
341   %non_live_1 = arith.addi %live_1, %live_0 : i32
342   %non_live_2 = arith.constant 7 : i32
343   %non_live_3 = arith.subi %arg0, %non_live_1 : i32
344   %c3 = arith.constant 3 : i32
345   %live_2 = arith.addi %arg0, %c3 : i32
346   memref.store %live_2, %arg1[] : memref<i32>
347   return %live_1, %non_live_1, %non_live_2, %non_live_3 : i32, i32, i32, i32
350 func.func @main(%arg3 : i32, %arg4 : memref<i32>, %arg5 : i32) -> (i32) {
351   %live, %non_live_1, %non_live_2, %non_live_3 = func.call @clean_simple_ops(%arg3, %arg4, %arg5) : (i32, memref<i32>, i32) -> (i32, i32, i32, i32)
352   return %live : i32
355 // -----
357 // The scf.while op has no memory effects and its result isn't live.
359 // Note that this cleanup cannot be done by the `canonicalize` pass.
361 // CHECK-LABEL: func.func private @clean_region_branch_op_erase_it() {
362 // CHECK-NEXT:    return
363 // CHECK-NEXT:  }
364 // CHECK:       func.func @main(%[[arg3:.*]]: i32, %[[arg4:.*]]: i1) {
365 // CHECK-NEXT:    call @clean_region_branch_op_erase_it() : () -> ()
366 // CHECK-NEXT:    return
367 // CHECK-NEXT:  }
368 func.func private @clean_region_branch_op_erase_it(%arg0 : i32, %arg1 : i1) -> (i32) {
369   %non_live = scf.while (%arg2 = %arg0) : (i32) -> (i32) {
370     scf.condition(%arg1) %arg2 : i32
371   } do {
372   ^bb0(%arg2: i32):
373     scf.yield %arg2 : i32
374   }
375   return %non_live : i32
378 func.func @main(%arg3 : i32, %arg4 : i1) {
379   %non_live_0 = func.call @clean_region_branch_op_erase_it(%arg3, %arg4) : (i32, i1) -> (i32)
380   return
383 // -----
385 #map = affine_map<(d0)[s0, s1] -> (d0 * s0 + s1)>
386 func.func @kernel(%arg0: memref<18xf32>) {
387   %c1 = arith.constant 1 : index
388   %c18 = arith.constant 18 : index
389   gpu.launch blocks(%arg3, %arg4, %arg5) in (%arg9 = %c18, %arg10 = %c18, %arg11 = %c18) threads(%arg6, %arg7, %arg8) in (%arg12 = %c1, %arg13 = %c1, %arg14 = %c1) {
390     %c1_0 = arith.constant 1 : index
391     %c0_1 = arith.constant 0 : index
392     %cst_2 = arith.constant 25.4669495 : f32
393     %6 = affine.apply #map(%arg3)[%c1_0, %c0_1]
394     memref.store %cst_2, %arg0[%6] : memref<18xf32>
395     gpu.terminator
396   } {SCFToGPU_visited}
397   return
400 // CHECK-LABEL: func.func @kernel(%arg0: memref<18xf32>) {
401 // CHECK: gpu.launch blocks
402 // CHECK: memref.store
403 // CHECK-NEXT: gpu.terminator
405 // -----
407 // CHECK: func.func private @no_block_func_declaration()
408 func.func private @no_block_func_declaration() -> ()
410 // -----
412 // CHECK: llvm.func @no_block_external_func()
413 llvm.func @no_block_external_func() attributes {sym_visibility = "private"}