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