xref: /llvm-project/mlir/test/Analysis/DataFlow/test-last-modified-callgraph.mlir (revision 32a4e3fccaf304c8d541bdefdb1a7ef829f84c1c)
1*32a4e3fcSOleksandr "Alex" Zinenko// RUN: mlir-opt -test-last-modified --split-input-file %s 2>&1 |\
2*32a4e3fcSOleksandr "Alex" Zinenko// RUN:          FileCheck %s --check-prefixes=CHECK,IP,IP_ONLY
3*32a4e3fcSOleksandr "Alex" Zinenko// RUN: mlir-opt -test-last-modified='assume-func-writes=true' \
4*32a4e3fcSOleksandr "Alex" Zinenko// RUN:          --split-input-file %s 2>&1 |\
5*32a4e3fcSOleksandr "Alex" Zinenko// RUN:          FileCheck %s --check-prefixes=CHECK,IP,IP_AW
6*32a4e3fcSOleksandr "Alex" Zinenko// RUN: mlir-opt -test-last-modified='interprocedural=false' \
7*32a4e3fcSOleksandr "Alex" Zinenko// RUN:          --split-input-file %s 2>&1 |\
8*32a4e3fcSOleksandr "Alex" Zinenko// RUN:          FileCheck %s --check-prefixes=CHECK,LOCAL
9*32a4e3fcSOleksandr "Alex" Zinenko// RUN: mlir-opt \
10*32a4e3fcSOleksandr "Alex" Zinenko// RUN:    -test-last-modified='interprocedural=false assume-func-writes=true' \
11*32a4e3fcSOleksandr "Alex" Zinenko// RUN:    --split-input-file %s 2>&1 |\
12*32a4e3fcSOleksandr "Alex" Zinenko// RUN:    FileCheck %s --check-prefixes=CHECK,LC_AW
13*32a4e3fcSOleksandr "Alex" Zinenko
14*32a4e3fcSOleksandr "Alex" Zinenko// Check prefixes are as follows:
15*32a4e3fcSOleksandr "Alex" Zinenko// 'check': common for all runs;
16*32a4e3fcSOleksandr "Alex" Zinenko// 'ip': interprocedural runs;
17*32a4e3fcSOleksandr "Alex" Zinenko// 'ip_aw': interpocedural runs assuming calls to external functions write to
18*32a4e3fcSOleksandr "Alex" Zinenko//          all arguments;
19*32a4e3fcSOleksandr "Alex" Zinenko// 'ip_only': interprocedural runs not assuming calls writing;
20*32a4e3fcSOleksandr "Alex" Zinenko// 'local': local (non-interprocedural) analysis not assuming calls writing;
21*32a4e3fcSOleksandr "Alex" Zinenko// 'lc_aw': local analysis assuming external calls writing to all arguments.
22d80c271cSMogball
23d80c271cSMogball// CHECK-LABEL: test_tag: test_callsite
24*32a4e3fcSOleksandr "Alex" Zinenko// IP:    operand #0
25*32a4e3fcSOleksandr "Alex" Zinenko// IP-NEXT: - a
26*32a4e3fcSOleksandr "Alex" Zinenko// LOCAL: operand #0
27*32a4e3fcSOleksandr "Alex" Zinenko// LOCAL-NEXT: - <unknown>
28*32a4e3fcSOleksandr "Alex" Zinenko// LC_AW: operand #0
29*32a4e3fcSOleksandr "Alex" Zinenko// LC_AW-NEXT: - <unknown>
30d80c271cSMogballfunc.func private @single_callsite_fn(%ptr: memref<i32>) -> memref<i32> {
31d80c271cSMogball  return {tag = "test_callsite"} %ptr : memref<i32>
32d80c271cSMogball}
33d80c271cSMogball
34d80c271cSMogballfunc.func @test_callsite() {
35d80c271cSMogball  %ptr = memref.alloc() : memref<i32>
36d80c271cSMogball  %c0 = arith.constant 0 : i32
37d80c271cSMogball  memref.store %c0, %ptr[] {tag_name = "a"} : memref<i32>
38d80c271cSMogball  %0 = func.call @single_callsite_fn(%ptr) : (memref<i32>) -> memref<i32>
39d80c271cSMogball  return
40d80c271cSMogball}
41d80c271cSMogball
42d80c271cSMogball// CHECK-LABEL: test_tag: test_return_site
43*32a4e3fcSOleksandr "Alex" Zinenko// IP:    operand #0
44*32a4e3fcSOleksandr "Alex" Zinenko// IP-NEXT:    - b
45*32a4e3fcSOleksandr "Alex" Zinenko// LOCAL: operand #0
46*32a4e3fcSOleksandr "Alex" Zinenko// LOCAL-NEXT: - <unknown>
47*32a4e3fcSOleksandr "Alex" Zinenko// LC_AW: operand #0
48*32a4e3fcSOleksandr "Alex" Zinenko// LC_AW-NEXT: - <unknown>
49d80c271cSMogballfunc.func private @single_return_site_fn(%ptr: memref<i32>) -> memref<i32> {
50d80c271cSMogball  %c0 = arith.constant 0 : i32
51d80c271cSMogball  memref.store %c0, %ptr[] {tag_name = "b"} : memref<i32>
52d80c271cSMogball  return %ptr : memref<i32>
53d80c271cSMogball}
54d80c271cSMogball
55d80c271cSMogball// CHECK-LABEL: test_tag: test_multiple_callsites
56*32a4e3fcSOleksandr "Alex" Zinenko// IP:    operand #0
57*32a4e3fcSOleksandr "Alex" Zinenko// IP-NEXT:    write0
58*32a4e3fcSOleksandr "Alex" Zinenko// IP-NEXT:    write1
59*32a4e3fcSOleksandr "Alex" Zinenko// LOCAL: operand #0
60*32a4e3fcSOleksandr "Alex" Zinenko// LOCAL-NEXT: - <unknown>
61*32a4e3fcSOleksandr "Alex" Zinenko// LC_AW: operand #0
62*32a4e3fcSOleksandr "Alex" Zinenko// LC_AW-NEXT: - <unknown>
63d80c271cSMogballfunc.func @test_return_site(%ptr: memref<i32>) -> memref<i32> {
64d80c271cSMogball  %0 = func.call @single_return_site_fn(%ptr) : (memref<i32>) -> memref<i32>
65d80c271cSMogball  return {tag = "test_return_site"} %0 : memref<i32>
66d80c271cSMogball}
67d80c271cSMogball
68d80c271cSMogballfunc.func private @multiple_callsite_fn(%ptr: memref<i32>) -> memref<i32> {
69d80c271cSMogball  return {tag = "test_multiple_callsites"} %ptr : memref<i32>
70d80c271cSMogball}
71d80c271cSMogball
72d80c271cSMogballfunc.func @test_multiple_callsites(%a: i32, %ptr: memref<i32>) -> memref<i32> {
73d80c271cSMogball  memref.store %a, %ptr[] {tag_name = "write0"} : memref<i32>
74d80c271cSMogball  %0 = func.call @multiple_callsite_fn(%ptr) : (memref<i32>) -> memref<i32>
75d80c271cSMogball  memref.store %a, %ptr[] {tag_name = "write1"} : memref<i32>
76d80c271cSMogball  %1 = func.call @multiple_callsite_fn(%ptr) : (memref<i32>) -> memref<i32>
77d80c271cSMogball  return %ptr : memref<i32>
78d80c271cSMogball}
79d80c271cSMogball
80d80c271cSMogball// CHECK-LABEL: test_tag: test_multiple_return_sites
81*32a4e3fcSOleksandr "Alex" Zinenko// IP:    operand #0
82*32a4e3fcSOleksandr "Alex" Zinenko// IP-NEXT:    return0
83*32a4e3fcSOleksandr "Alex" Zinenko// IP-NEXT:    return1
84*32a4e3fcSOleksandr "Alex" Zinenko// LOCAL: operand #0
85*32a4e3fcSOleksandr "Alex" Zinenko// LOCAL-NEXT: - <unknown>
86*32a4e3fcSOleksandr "Alex" Zinenko// LC_AW: operand #0
87*32a4e3fcSOleksandr "Alex" Zinenko// LC_AW-NEXT: - <unknown>
88d80c271cSMogballfunc.func private @multiple_return_site_fn(%cond: i1, %a: i32, %ptr: memref<i32>) -> memref<i32> {
89d80c271cSMogball  cf.cond_br %cond, ^a, ^b
90d80c271cSMogball
91d80c271cSMogball^a:
92d80c271cSMogball  memref.store %a, %ptr[] {tag_name = "return0"} : memref<i32>
93d80c271cSMogball  return %ptr : memref<i32>
94d80c271cSMogball
95d80c271cSMogball^b:
96d80c271cSMogball  memref.store %a, %ptr[] {tag_name = "return1"} : memref<i32>
97d80c271cSMogball  return %ptr : memref<i32>
98d80c271cSMogball}
99d80c271cSMogball
100d80c271cSMogballfunc.func @test_multiple_return_sites(%cond: i1, %a: i32, %ptr: memref<i32>) -> memref<i32> {
101d80c271cSMogball  %0 = func.call @multiple_return_site_fn(%cond, %a, %ptr) : (i1, i32, memref<i32>) -> memref<i32>
102d80c271cSMogball  return {tag = "test_multiple_return_sites"} %0 : memref<i32>
103d80c271cSMogball}
1045d8813deSAlex Zinenko
1055d8813deSAlex Zinenko// -----
1065d8813deSAlex Zinenko
1074732b0cbSJacob Mai Peng// CHECK-LABEL: test_tag: after_call
108*32a4e3fcSOleksandr "Alex" Zinenko// IP:    operand #0
109*32a4e3fcSOleksandr "Alex" Zinenko// IP-NEXT:    - write0
110*32a4e3fcSOleksandr "Alex" Zinenko// LOCAL: operand #0
111*32a4e3fcSOleksandr "Alex" Zinenko// LOCAL-NEXT: - <unknown>
112*32a4e3fcSOleksandr "Alex" Zinenko// LC_AW: operand #0
113*32a4e3fcSOleksandr "Alex" Zinenko// LC_AW-NEXT: - func.call
1144732b0cbSJacob Mai Pengfunc.func private @void_return(%ptr: memref<i32>) {
1154732b0cbSJacob Mai Peng  return
1164732b0cbSJacob Mai Peng}
1174732b0cbSJacob Mai Peng
1184732b0cbSJacob Mai Pengfunc.func @test_call_void_return() {
1194732b0cbSJacob Mai Peng  %ptr = memref.alloc() : memref<i32>
1204732b0cbSJacob Mai Peng  %c0 = arith.constant 0 : i32
1214732b0cbSJacob Mai Peng  memref.store %c0, %ptr[] {tag_name = "write0"} : memref<i32>
1224732b0cbSJacob Mai Peng  func.call @void_return(%ptr) : (memref<i32>) -> ()
1234732b0cbSJacob Mai Peng  memref.load %ptr[] {tag = "after_call"} : memref<i32>
1244732b0cbSJacob Mai Peng  return
1254732b0cbSJacob Mai Peng}
1264732b0cbSJacob Mai Peng
1274732b0cbSJacob Mai Peng// -----
1285d8813deSAlex Zinenko
1295d8813deSAlex Zinenkofunc.func private @callee(%arg0: memref<f32>) -> memref<f32> {
1305d8813deSAlex Zinenko  %2 = arith.constant 2.0 : f32
1315d8813deSAlex Zinenko  memref.load %arg0[] {tag = "call_and_store_before::enter_callee"} : memref<f32>
1325d8813deSAlex Zinenko  memref.store %2, %arg0[] {tag_name = "callee"} : memref<f32>
1335d8813deSAlex Zinenko  memref.load %arg0[] {tag = "exit_callee"} : memref<f32>
1345d8813deSAlex Zinenko  return %arg0 : memref<f32>
1355d8813deSAlex Zinenko}
1365d8813deSAlex Zinenko// In this test, the "call" operation also stores to %arg0 itself before
1375d8813deSAlex Zinenko// transferring control flow to the callee. Therefore, the order of accesses is
1385d8813deSAlex Zinenko// "pre" -> "call" -> "callee" -> "post"
1395d8813deSAlex Zinenko
1405d8813deSAlex Zinenko// CHECK-LABEL: test_tag: call_and_store_before::enter_callee:
141*32a4e3fcSOleksandr "Alex" Zinenko// IP:     operand #0
142*32a4e3fcSOleksandr "Alex" Zinenko// IP:      - call
143*32a4e3fcSOleksandr "Alex" Zinenko// LOCAL:  operand #0
144*32a4e3fcSOleksandr "Alex" Zinenko// LOCAL:   - <unknown>
145*32a4e3fcSOleksandr "Alex" Zinenko// LC_AW:  operand #0
146*32a4e3fcSOleksandr "Alex" Zinenko// LC_AW:   - <unknown>
147*32a4e3fcSOleksandr "Alex" Zinenko
1485d8813deSAlex Zinenko// CHECK: test_tag: exit_callee:
1495d8813deSAlex Zinenko// CHECK:  operand #0
1505d8813deSAlex Zinenko// CHECK:   - callee
151*32a4e3fcSOleksandr "Alex" Zinenko
1525d8813deSAlex Zinenko// CHECK: test_tag: before_call:
1535d8813deSAlex Zinenko// CHECK:  operand #0
1545d8813deSAlex Zinenko// CHECK:   - pre
155*32a4e3fcSOleksandr "Alex" Zinenko
1565d8813deSAlex Zinenko// CHECK: test_tag: after_call:
157*32a4e3fcSOleksandr "Alex" Zinenko// IP:     operand #0
158*32a4e3fcSOleksandr "Alex" Zinenko// IP:      - callee
159*32a4e3fcSOleksandr "Alex" Zinenko// LOCAL:  operand #0
160*32a4e3fcSOleksandr "Alex" Zinenko// LOCAL:   - <unknown>
161*32a4e3fcSOleksandr "Alex" Zinenko// LC_AW:  operand #0
162*32a4e3fcSOleksandr "Alex" Zinenko// LC_AW:   - call
163*32a4e3fcSOleksandr "Alex" Zinenko
1645d8813deSAlex Zinenko// CHECK: test_tag: return:
1655d8813deSAlex Zinenko// CHECK:  operand #0
1665d8813deSAlex Zinenko// CHECK:   - post
1675d8813deSAlex Zinenkofunc.func @call_and_store_before(%arg0: memref<f32>) -> memref<f32> {
1685d8813deSAlex Zinenko  %0 = arith.constant 0.0 : f32
1695d8813deSAlex Zinenko  %1 = arith.constant 1.0 : f32
1705d8813deSAlex Zinenko  memref.store %0, %arg0[] {tag_name = "pre"} : memref<f32>
1715d8813deSAlex Zinenko  memref.load %arg0[] {tag = "before_call"} : memref<f32>
1725d8813deSAlex Zinenko  test.call_and_store @callee(%arg0), %arg0 {tag_name = "call", store_before_call = true} : (memref<f32>, memref<f32>) -> ()
1735d8813deSAlex Zinenko  memref.load %arg0[] {tag = "after_call"} : memref<f32>
1745d8813deSAlex Zinenko  memref.store %1, %arg0[] {tag_name = "post"} : memref<f32>
1755d8813deSAlex Zinenko  return {tag = "return"} %arg0 : memref<f32>
1765d8813deSAlex Zinenko}
1775d8813deSAlex Zinenko
1785d8813deSAlex Zinenko// -----
1795d8813deSAlex Zinenko
1805d8813deSAlex Zinenkofunc.func private @callee(%arg0: memref<f32>) -> memref<f32> {
1815d8813deSAlex Zinenko  %2 = arith.constant 2.0 : f32
1825d8813deSAlex Zinenko  memref.load %arg0[] {tag = "call_and_store_after::enter_callee"} : memref<f32>
1835d8813deSAlex Zinenko  memref.store %2, %arg0[] {tag_name = "callee"} : memref<f32>
1845d8813deSAlex Zinenko  memref.load %arg0[] {tag = "exit_callee"} : memref<f32>
1855d8813deSAlex Zinenko  return %arg0 : memref<f32>
1865d8813deSAlex Zinenko}
1875d8813deSAlex Zinenko
1885d8813deSAlex Zinenko// In this test, the "call" operation also stores to %arg0 itself after getting
1895d8813deSAlex Zinenko// control flow back from the callee. Therefore, the order of accesses is
1905d8813deSAlex Zinenko// "pre" -> "callee" -> "call" -> "post"
1915d8813deSAlex Zinenko
1925d8813deSAlex Zinenko// CHECK-LABEL: test_tag: call_and_store_after::enter_callee:
193*32a4e3fcSOleksandr "Alex" Zinenko// IP:     operand #0
194*32a4e3fcSOleksandr "Alex" Zinenko// IP:      - pre
195*32a4e3fcSOleksandr "Alex" Zinenko// LOCAL:  operand #0
196*32a4e3fcSOleksandr "Alex" Zinenko// LOCAL:   - <unknown>
197*32a4e3fcSOleksandr "Alex" Zinenko// LC_AW:  operand #0
198*32a4e3fcSOleksandr "Alex" Zinenko// LC_AW:   - <unknown>
199*32a4e3fcSOleksandr "Alex" Zinenko
2005d8813deSAlex Zinenko// CHECK: test_tag: exit_callee:
2015d8813deSAlex Zinenko// CHECK:  operand #0
2025d8813deSAlex Zinenko// CHECK:   - callee
203*32a4e3fcSOleksandr "Alex" Zinenko
2045d8813deSAlex Zinenko// CHECK: test_tag: before_call:
2055d8813deSAlex Zinenko// CHECK:  operand #0
2065d8813deSAlex Zinenko// CHECK:   - pre
207*32a4e3fcSOleksandr "Alex" Zinenko
2085d8813deSAlex Zinenko// CHECK:    test_tag: after_call:
209*32a4e3fcSOleksandr "Alex" Zinenko// IP:     operand #0
210*32a4e3fcSOleksandr "Alex" Zinenko// IP:      - call
211*32a4e3fcSOleksandr "Alex" Zinenko// LOCAL:  operand #0
212*32a4e3fcSOleksandr "Alex" Zinenko// LOCAL:   - <unknown>
213*32a4e3fcSOleksandr "Alex" Zinenko// LC_AW:  operand #0
214*32a4e3fcSOleksandr "Alex" Zinenko// LC_AW:   - call
215*32a4e3fcSOleksandr "Alex" Zinenko
2165d8813deSAlex Zinenko// CHECK: test_tag: return:
2175d8813deSAlex Zinenko// CHECK:  operand #0
2185d8813deSAlex Zinenko// CHECK:   - post
2195d8813deSAlex Zinenkofunc.func @call_and_store_after(%arg0: memref<f32>) -> memref<f32> {
2205d8813deSAlex Zinenko  %0 = arith.constant 0.0 : f32
2215d8813deSAlex Zinenko  %1 = arith.constant 1.0 : f32
2225d8813deSAlex Zinenko  memref.store %0, %arg0[] {tag_name = "pre"} : memref<f32>
2235d8813deSAlex Zinenko  memref.load %arg0[] {tag = "before_call"} : memref<f32>
2245d8813deSAlex Zinenko  test.call_and_store @callee(%arg0), %arg0 {tag_name = "call", store_before_call = false} : (memref<f32>, memref<f32>) -> ()
2255d8813deSAlex Zinenko  memref.load %arg0[] {tag = "after_call"} : memref<f32>
2265d8813deSAlex Zinenko  memref.store %1, %arg0[] {tag_name = "post"} : memref<f32>
2275d8813deSAlex Zinenko  return {tag = "return"} %arg0 : memref<f32>
2285d8813deSAlex Zinenko}
229*32a4e3fcSOleksandr "Alex" Zinenko
230*32a4e3fcSOleksandr "Alex" Zinenko// -----
231*32a4e3fcSOleksandr "Alex" Zinenko
232*32a4e3fcSOleksandr "Alex" Zinenkofunc.func private @void_return(%ptr: memref<i32>)
233*32a4e3fcSOleksandr "Alex" Zinenko
234*32a4e3fcSOleksandr "Alex" Zinenko// CHECK-LABEL: test_tag: after_opaque_call:
235*32a4e3fcSOleksandr "Alex" Zinenko// CHECK:        operand #0
236*32a4e3fcSOleksandr "Alex" Zinenko// IP_ONLY:       - <unknown>
237*32a4e3fcSOleksandr "Alex" Zinenko// IP_AW:         - func.call
238*32a4e3fcSOleksandr "Alex" Zinenkofunc.func @test_opaque_call_return() {
239*32a4e3fcSOleksandr "Alex" Zinenko  %ptr = memref.alloc() : memref<i32>
240*32a4e3fcSOleksandr "Alex" Zinenko  %c0 = arith.constant 0 : i32
241*32a4e3fcSOleksandr "Alex" Zinenko  memref.store %c0, %ptr[] {tag_name = "write0"} : memref<i32>
242*32a4e3fcSOleksandr "Alex" Zinenko  func.call @void_return(%ptr) : (memref<i32>) -> ()
243*32a4e3fcSOleksandr "Alex" Zinenko  memref.load %ptr[] {tag = "after_opaque_call"} : memref<i32>
244*32a4e3fcSOleksandr "Alex" Zinenko  return
245*32a4e3fcSOleksandr "Alex" Zinenko}
246