brintos

brintos / llvm-project-archived public Read only

0
0
Text · 11.1 KiB · 4fc9af1 Raw
367 lines · plain
1// RUN: mlir-opt -split-input-file -test-written-to %s 2>&1 |\2// RUN:          FileCheck %s --check-prefixes=CHECK,IP3// RUN: mlir-opt -split-input-file -test-written-to='interprocedural=false' %s \4// RUN:          2>&1 | FileCheck %s --check-prefixes=CHECK,LOCAL5// RUN: mlir-opt -split-input-file \6// RUN:          -test-written-to='assume-func-writes=true' %s 2>&1 |\7// RUN:          FileCheck %s --check-prefixes=CHECK,IP_AW8// RUN: mlir-opt -split-input-file \9// RUN:       -test-written-to='interprocedural=false assume-func-writes=true' \10// RUN:       %s 2>&1 | FileCheck %s --check-prefixes=CHECK,LC_AW11 12// Check prefixes are as follows:13// 'check': common for all runs;14// 'ip': interprocedural runs;15// 'ip_aw': interpocedural runs assuming calls to external functions write to16//          all arguments;17// 'local': local (non-interprocedural) analysis not assuming calls writing;18// 'lc_aw': local analysis assuming external calls writing to all arguments.19 20// Note that despite the name of the test analysis being "written to", it is set21// up in a peculiar way where passing a value through a block or region argument22// (via visitCall/BranchOperand) is considered as "writing" that value to the23// corresponding operand, which is itself a value and not necessarily "memory".24// This is arguably okay for testing purposes, but may be surprising for readers25// trying to interpret this test using their intuition.26 27// CHECK-LABEL: test_tag: constant028// CHECK: result #0: [a]29// CHECK-LABEL: test_tag: constant130// CHECK: result #0: [b]31func.func @test_two_writes(%m0: memref<i32>, %m1: memref<i32>) -> (memref<i32>, memref<i32>) {32  %c0 = arith.constant {tag = "constant0"} 0 : i3233  %c1 = arith.constant {tag = "constant1"} 1 : i3234  memref.store %c0, %m0[] {tag_name = "a"} : memref<i32>35  memref.store %c1, %m1[] {tag_name = "b"} : memref<i32>36  return %m0, %m1 : memref<i32>, memref<i32>37}38 39// -----40 41// CHECK-LABEL: test_tag: c042// CHECK: result #0: [b]43// CHECK-LABEL: test_tag: c144// CHECK: result #0: [b]45// CHECK-LABEL: test_tag: condition46// CHECK: result #0: [brancharg0]47// CHECK-LABEL: test_tag: c248// CHECK: result #0: [a]49// CHECK-LABEL: test_tag: c350// CHECK: result #0: [a]51func.func @test_if(%m0: memref<i32>, %m1: memref<i32>, %condition: i1) {52  %c0 = arith.constant {tag = "c0"} 2 : i3253  %c1 = arith.constant {tag = "c1"} 3 : i3254  %condition2 = arith.addi %condition, %condition {tag = "condition"} : i155  %0, %1 = scf.if %condition2 -> (i32, i32) {56    %c2 = arith.constant {tag = "c2"} 0 : i3257    scf.yield %c2, %c0: i32, i3258  } else {59    %c3 = arith.constant {tag = "c3"} 1 : i3260    scf.yield %c3, %c1: i32, i3261  }62  memref.store %0, %m0[] {tag_name = "a"} : memref<i32>63  memref.store %1, %m1[] {tag_name = "b"} : memref<i32>64  return65}66 67// -----68 69// CHECK-LABEL: test_tag: c070// CHECK: result #0: [a c]71// CHECK-LABEL: test_tag: c172// CHECK: result #0: [b c]73// CHECK-LABEL: test_tag: br74// CHECK: operand #0: [brancharg0]75func.func @test_blocks(%m0: memref<i32>,76                       %m1: memref<i32>,77                       %m2: memref<i32>, %cond : i1) {78  %0 = arith.constant {tag = "c0"} 0 : i3279  %1 = arith.constant {tag = "c1"} 1 : i3280  cf.cond_br %cond, ^a(%0: i32), ^b(%1: i32) {tag = "br"}81^a(%a0: i32):82  memref.store %a0, %m0[] {tag_name = "a"} : memref<i32>83  cf.br ^c(%a0 : i32)84^b(%b0: i32):85  memref.store %b0, %m1[] {tag_name = "b"} : memref<i32>86  cf.br ^c(%b0 : i32)87^c(%c0 : i32):88  memref.store %c0, %m2[] {tag_name = "c"} : memref<i32>89  return90}91 92// -----93 94// CHECK-LABEL: test_tag: two95// CHECK: result #0: [a]96func.func @test_infinite_loop(%m0: memref<i32>) {97  %0 = arith.constant 0 : i3298  %1 = arith.constant 1 : i3299  %2 = arith.constant {tag = "two"} 2 : i32100  %3 = arith.constant -1 : i32101  cf.br ^loop(%0, %1, %2: i32, i32, i32)102^loop(%a: i32, %b: i32, %c: i32):103  memref.store %a, %m0[] {tag_name = "a"} : memref<i32>104  cf.br ^loop(%b, %c, %3 : i32, i32, i32)105}106 107// -----108 109// CHECK-LABEL: test_tag: c0110// CHECK: result #0: [a b c]111func.func @test_switch(%flag: i32, %m0: memref<i32>) {112  %0 = arith.constant {tag = "c0"} 0 : i32113  cf.switch %flag : i32, [114      default: ^a(%0 : i32),115      42: ^b(%0 : i32),116      43: ^c(%0 : i32)117  ]118^a(%a0: i32):119  memref.store %a0, %m0[] {tag_name = "a"} : memref<i32>120  cf.br ^c(%a0 : i32)121^b(%b0: i32):122  memref.store %b0, %m0[] {tag_name = "b"} : memref<i32>123  cf.br ^c(%b0 : i32)124^c(%c0 : i32):125  memref.store %c0, %m0[] {tag_name = "c"} : memref<i32>126  return127}128 129// -----130 131// CHECK-LABEL: test_tag: add132// IP:    result #0: [a]133// LOCAL: result #0: [callarg0]134// LC_AW: result #0: [func.call]135func.func @test_caller(%m0: memref<f32>, %arg: f32) {136  %0 = arith.addf %arg, %arg {tag = "add"} : f32137  %1 = func.call @callee(%0) : (f32) -> f32138  %2 = arith.mulf %1, %1 : f32139  %3 = arith.mulf %2, %2 : f32140  %4 = arith.mulf %3, %3 : f32141  memref.store %4, %m0[] {tag_name = "a"} : memref<f32>142  return143}144 145func.func private @callee(%0 : f32) -> f32 {146  %1 = arith.mulf %0, %0 : f32147  %2 = arith.mulf %1, %1 : f32148  func.return %2 : f32149}150 151// -----152 153func.func private @callee(%0 : f32) -> f32 {154  %1 = arith.mulf %0, %0 : f32155  func.return %1 : f32156}157 158// CHECK-LABEL: test_tag: sub159// IP:    result #0: [a]160// LOCAL: result #0: [callarg0]161// LC_AW: result #0: [func.call]162func.func @test_caller_below_callee(%m0: memref<f32>, %arg: f32) {163  %0 = arith.subf %arg, %arg {tag = "sub"} : f32164  %1 = func.call @callee(%0) : (f32) -> f32165  memref.store %1, %m0[] {tag_name = "a"} : memref<f32>166  return167}168 169// -----170 171func.func private @callee1(%0 : f32) -> f32 {172  %1 = func.call @callee2(%0) : (f32) -> f32173  func.return %1 : f32174}175 176func.func private @callee2(%0 : f32) -> f32 {177  %1 = func.call @callee3(%0) : (f32) -> f32178  func.return %1 : f32179}180 181func.func private @callee3(%0 : f32) -> f32 {182  func.return %0 : f32183}184 185// CHECK-LABEL: test_tag: mul186// IP:    result #0: [a]187// LOCAL: result #0: [callarg0]188// LC_AW: result #0: [func.call]189func.func @test_callchain(%m0: memref<f32>, %arg: f32) {190  %0 = arith.mulf %arg, %arg {tag = "mul"} : f32191  %1 = func.call @callee1(%0) : (f32) -> f32192  memref.store %1, %m0[] {tag_name = "a"} : memref<f32>193  return194}195 196// -----197 198// CHECK-LABEL: test_tag: zero199// CHECK: result #0: [c]200// CHECK-LABEL: test_tag: init201// CHECK: result #0: [a b c]202// CHECK-LABEL: test_tag: condition203// CHECK: operand #0: [brancharg0]204// CHECK: operand #2: [a b c]205func.func @test_while(%m0: memref<i32>, %init : i32, %cond: i1) {206  %zero = arith.constant {tag = "zero"} 0 : i32207  %init2 = arith.addi %init, %init {tag = "init"} : i32208  %0, %1 = scf.while (%arg1 = %zero, %arg2 = %init2) : (i32, i32) -> (i32, i32) {209    memref.store %arg2, %m0[] {tag_name = "a"} : memref<i32>210    scf.condition(%cond) {tag = "condition"} %arg1, %arg2 : i32, i32211  } do {212   ^bb0(%arg1: i32, %arg2: i32):213    memref.store %arg1, %m0[] {tag_name = "c"} : memref<i32>214    %res = arith.addi %arg2, %arg2 : i32215    scf.yield %res, %res: i32, i32216  }217  memref.store %1, %m0[] {tag_name = "b"} : memref<i32>218  return219}220 221// -----222 223// CHECK-LABEL: test_tag: zero224// CHECK: result #0: []225// CHECK-LABEL: test_tag: one226// CHECK: result #0: [a]227// CHECK-LABEL: test_tag: condition228// CHECK: operand #0: [brancharg0]229//230// The important thing to note in this test is that the sparse backward dataflow231// analysis framework also works on complex region branch ops like this one232// where the number of operands in the `scf.yield` op don't match the number of233// results in the parent op.234func.func @test_complex_while(%m0: memref<i32>, %cond: i1) {235  %zero = arith.constant {tag = "zero"} 0 : i32236  %one = arith.constant {tag = "one"} 1 : i32237  %0 = scf.while (%arg1 = %zero, %arg2 = %one) : (i32, i32) -> (i32) {238    scf.condition(%cond) {tag = "condition"} %arg2 : i32239  } do {240   ^bb0(%arg1: i32):241    scf.yield %arg1, %arg1: i32, i32242  }243  memref.store %0, %m0[] {tag_name = "a"} : memref<i32>244  return245}246 247// -----248 249// CHECK-LABEL: test_tag: zero250// CHECK: result #0: [brancharg0]251// CHECK-LABEL: test_tag: ten252// CHECK: result #0: [brancharg1]253// CHECK-LABEL: test_tag: one254// CHECK: result #0: [brancharg2]255// CHECK-LABEL: test_tag: x256// CHECK: result #0: [a]257func.func @test_for(%m0: memref<i32>) {258  %zero = arith.constant {tag = "zero"} 0 : index259  %ten = arith.constant {tag = "ten"} 10 : index260  %one = arith.constant {tag = "one"} 1 : index261  %x = arith.constant {tag = "x"} 0 : i32262  %0 = scf.for %i = %zero to %ten step %one iter_args(%ix = %x) -> (i32) {263    scf.yield %ix : i32264  }265  memref.store %0, %m0[] {tag_name = "a"} : memref<i32>266  return267}268 269// -----270 271// CHECK-LABEL: test_tag: default_a272// CHECK:       result #0: [a]273// CHECK-LABEL: test_tag: default_b274// CHECK:       result #0: [b]275// CHECK-LABEL: test_tag: 1a276// CHECK:       result #0: [a]277// CHECK-LABEL: test_tag: 1b278// CHECK:       result #0: [b]279// CHECK-LABEL: test_tag: 2a280// CHECK:       result #0: [a]281// CHECK-LABEL: test_tag: 2b282// CHECK:       result #0: [b]283// CHECK-LABEL: test_tag: switch284// CHECK:       operand #0: [brancharg0]285func.func @test_switch(%arg0 : index, %m0: memref<i32>) {286  %0, %1 = scf.index_switch %arg0 {tag="switch"} -> i32, i32287  case 1 {288    %2 = arith.constant {tag="1a"} 10 : i32289    %3 = arith.constant {tag="1b"} 100 : i32290    scf.yield %2, %3 : i32, i32291  }292  case 2 {293    %4 = arith.constant {tag="2a"} 20 : i32294    %5 = arith.constant {tag="2b"} 200 : i32295    scf.yield %4, %5 : i32, i32296  }297  default {298    %6 = arith.constant {tag="default_a"} 30 : i32299    %7 = arith.constant {tag="default_b"} 300 : i32300    scf.yield %6, %7 : i32, i32301  }302  memref.store %0, %m0[] {tag_name = "a"} : memref<i32>303  memref.store %1, %m0[] {tag_name = "b"} : memref<i32>304  return305}306 307// -----308 309// The point of this test is to ensure the analysis doesn't crash in presence of310// external functions.311 312// CHECK-LABEL: llvm.func @decl(i64)313// CHECK-LABEL: llvm.func @func(%arg0: i64) {314// CHECK-NEXT:  llvm.call @decl(%arg0) : (i64) -> ()315// CHECK-NEXT:  llvm.return316 317llvm.func @decl(i64)318 319llvm.func @func(%lb : i64) -> () {320  llvm.call @decl(%lb) : (i64) -> ()321  llvm.return322}323 324// -----325 326func.func private @callee(%arg0 : i32, %arg1 : i32) -> i32 {327  func.return %arg0 : i32328}329 330// CHECK-LABEL: test_tag: a331 332// IP:           operand #0: [b]333// LOCAL:        operand #0: [callarg0]334// LC_AW:        operand #0: [test.call_on_device]335 336// IP:           operand #1: []337// LOCAL:        operand #1: [callarg1]338// LC_AW:        operand #1: [test.call_on_device]339 340// IP:           operand #2: [callarg2]341// LOCAL:        operand #2: [callarg2]342// LC_AW:        operand #2: [test.call_on_device]343 344// CHECK:        result #0: [b]345func.func @test_call_on_device(%arg0: i32, %arg1: i32, %device: i32, %m0: memref<i32>) {346  %0 = test.call_on_device @callee(%arg0, %arg1), %device {tag = "a"} : (i32, i32, i32) -> (i32)347  memref.store %0, %m0[] {tag_name = "b"} : memref<i32>348  return349}350 351// -----352 353func.func private @external_callee(%arg0: i32) -> i32354 355// CHECK-LABEL: test_tag: add_external356// IP:    operand #0: [callarg0]357// LOCAL: operand #0: [callarg0]358// LC_AW: operand #0: [func.call]359// IP_AW: operand #0: [func.call]360 361func.func @test_external_callee(%arg0: i32, %m0: memref<i32>) {362  %0 = arith.addi %arg0, %arg0 { tag = "add_external"}: i32363  %1 = func.call @external_callee(%arg0) : (i32) -> i32364  memref.store %1, %m0[] {tag_name = "a"} : memref<i32>365  return366}367