| // RUN: mlir-opt -test-last-modified %s 2>&1 | FileCheck %s |
| |
| // CHECK-LABEL: test_tag: test_simple_mod |
| // CHECK: operand #0 |
| // CHECK-NEXT: - a |
| // CHECK: operand #1 |
| // CHECK-NEXT: - b |
| func.func @test_simple_mod(%arg0: memref<i32>, %arg1: memref<i32>) -> (memref<i32>, memref<i32>) { |
| %c0 = arith.constant 0 : i32 |
| %c1 = arith.constant 1 : i32 |
| memref.store %c0, %arg0[] {tag_name = "a"} : memref<i32> |
| memref.store %c1, %arg1[] {tag_name = "b"} : memref<i32> |
| return {tag = "test_simple_mod"} %arg0, %arg1 : memref<i32>, memref<i32> |
| } |
| |
| // CHECK-LABEL: test_tag: test_simple_mod_overwrite_a |
| // CHECK: operand #1 |
| // CHECK-NEXT: - a |
| // CHECK-LABEL: test_tag: test_simple_mod_overwrite_b |
| // CHECK: operand #0 |
| // CHECK-NEXT: - b |
| func.func @test_simple_mod_overwrite(%arg0: memref<i32>) -> memref<i32> { |
| %c0 = arith.constant 0 : i32 |
| memref.store %c0, %arg0[] {tag = "test_simple_mod_overwrite_a", tag_name = "a"} : memref<i32> |
| %c1 = arith.constant 1 : i32 |
| memref.store %c1, %arg0[] {tag_name = "b"} : memref<i32> |
| return {tag = "test_simple_mod_overwrite_b"} %arg0 : memref<i32> |
| } |
| |
| // CHECK-LABEL: test_tag: test_mod_control_flow |
| // CHECK: operand #0 |
| // CHECK-NEXT: - b |
| // CHECK-NEXT: - a |
| func.func @test_mod_control_flow(%cond: i1, %ptr: memref<i32>) -> memref<i32> { |
| cf.cond_br %cond, ^a, ^b |
| |
| ^a: |
| %c0 = arith.constant 0 : i32 |
| memref.store %c0, %ptr[] {tag_name = "a"} : memref<i32> |
| cf.br ^c |
| |
| ^b: |
| %c1 = arith.constant 1 : i32 |
| memref.store %c1, %ptr[] {tag_name = "b"} : memref<i32> |
| cf.br ^c |
| |
| ^c: |
| return {tag = "test_mod_control_flow"} %ptr : memref<i32> |
| } |
| |
| // CHECK-LABEL: test_tag: test_mod_dead_branch |
| // CHECK: operand #0 |
| // CHECK-NEXT: - a |
| func.func @test_mod_dead_branch(%arg: i32, %ptr: memref<i32>) -> memref<i32> { |
| %0 = arith.subi %arg, %arg : i32 |
| %1 = arith.constant -1 : i32 |
| %2 = arith.cmpi sgt, %0, %1 : i32 |
| cf.cond_br %2, ^a, ^b |
| |
| ^a: |
| %c0 = arith.constant 0 : i32 |
| memref.store %c0, %ptr[] {tag_name = "a"} : memref<i32> |
| cf.br ^c |
| |
| ^b: |
| %c1 = arith.constant 1 : i32 |
| memref.store %c1, %ptr[] {tag_name = "b"} : memref<i32> |
| cf.br ^c |
| |
| ^c: |
| return {tag = "test_mod_dead_branch"} %ptr : memref<i32> |
| } |
| |
| // CHECK-LABEL: test_tag: test_mod_region_control_flow |
| // CHECK: operand #0 |
| // CHECK-NEXT: then |
| // CHECK-NEXT: else |
| func.func @test_mod_region_control_flow(%cond: i1, %ptr: memref<i32>) -> memref<i32> { |
| scf.if %cond { |
| %c0 = arith.constant 0 : i32 |
| memref.store %c0, %ptr[] {tag_name = "then"}: memref<i32> |
| } else { |
| %c1 = arith.constant 1 : i32 |
| memref.store %c1, %ptr[] {tag_name = "else"} : memref<i32> |
| } |
| return {tag = "test_mod_region_control_flow"} %ptr : memref<i32> |
| } |
| |
| // CHECK-LABEL: test_tag: test_mod_dead_region |
| // CHECK: operand #0 |
| // CHECK-NEXT: else |
| func.func @test_mod_dead_region(%ptr: memref<i32>) -> memref<i32> { |
| %false = arith.constant false |
| scf.if %false { |
| %c0 = arith.constant 0 : i32 |
| memref.store %c0, %ptr[] {tag_name = "then"}: memref<i32> |
| } else { |
| %c1 = arith.constant 1 : i32 |
| memref.store %c1, %ptr[] {tag_name = "else"} : memref<i32> |
| } |
| return {tag = "test_mod_dead_region"} %ptr : memref<i32> |
| } |
| |
| // CHECK-LABEL: test_tag: unknown_memory_effects_a |
| // CHECK: operand #1 |
| // CHECK-NEXT: - a |
| // CHECK-LABEL: test_tag: unknown_memory_effects_b |
| // CHECK: operand #0 |
| // CHECK-NEXT: - <unknown> |
| func.func @unknown_memory_effects(%ptr: memref<i32>) -> memref<i32> { |
| %c0 = arith.constant 0 : i32 |
| memref.store %c0, %ptr[] {tag = "unknown_memory_effects_a", tag_name = "a"} : memref<i32> |
| "test.unknown_effects"() : () -> () |
| return {tag = "unknown_memory_effects_b"} %ptr : memref<i32> |
| } |
| |
| // CHECK-LABEL: test_tag: store_with_a_region_before::before: |
| // CHECK: operand #0 |
| // CHECK: - pre |
| // CHECK: test_tag: inside_region: |
| // CHECK: operand #0 |
| // CHECK: - region |
| // CHECK: test_tag: after: |
| // CHECK: operand #0 |
| // CHECK: - region |
| // CHECK: test_tag: return: |
| // CHECK: operand #0 |
| // CHECK: - post |
| func.func @store_with_a_region_before(%arg0: memref<f32>) -> memref<f32> { |
| %0 = arith.constant 0.0 : f32 |
| %1 = arith.constant 1.0 : f32 |
| memref.store %0, %arg0[] {tag_name = "pre"} : memref<f32> |
| memref.load %arg0[] {tag = "store_with_a_region_before::before"} : memref<f32> |
| test.store_with_a_region %arg0 attributes { tag_name = "region", store_before_region = true } { |
| memref.load %arg0[] {tag = "inside_region"} : memref<f32> |
| test.store_with_a_region_terminator |
| } : memref<f32> |
| memref.load %arg0[] {tag = "after"} : memref<f32> |
| memref.store %1, %arg0[] {tag_name = "post"} : memref<f32> |
| return {tag = "return"} %arg0 : memref<f32> |
| } |
| |
| // CHECK-LABEL: test_tag: store_with_a_region_after::before: |
| // CHECK: operand #0 |
| // CHECK: - pre |
| // CHECK: test_tag: inside_region: |
| // CHECK: operand #0 |
| // CHECK: - pre |
| // CHECK: test_tag: after: |
| // CHECK: operand #0 |
| // CHECK: - region |
| // CHECK: test_tag: return: |
| // CHECK: operand #0 |
| // CHECK: - post |
| func.func @store_with_a_region_after(%arg0: memref<f32>) -> memref<f32> { |
| %0 = arith.constant 0.0 : f32 |
| %1 = arith.constant 1.0 : f32 |
| memref.store %0, %arg0[] {tag_name = "pre"} : memref<f32> |
| memref.load %arg0[] {tag = "store_with_a_region_after::before"} : memref<f32> |
| test.store_with_a_region %arg0 attributes { tag_name = "region", store_before_region = false } { |
| memref.load %arg0[] {tag = "inside_region"} : memref<f32> |
| test.store_with_a_region_terminator |
| } : memref<f32> |
| memref.load %arg0[] {tag = "after"} : memref<f32> |
| memref.store %1, %arg0[] {tag_name = "post"} : memref<f32> |
| return {tag = "return"} %arg0 : memref<f32> |
| } |
| |
| // CHECK-LABEL: test_tag: store_with_a_region_before_containing_a_store::before: |
| // CHECK: operand #0 |
| // CHECK: - pre |
| // CHECK: test_tag: enter_region: |
| // CHECK: operand #0 |
| // CHECK: - region |
| // CHECK: test_tag: exit_region: |
| // CHECK: operand #0 |
| // CHECK: - inner |
| // CHECK: test_tag: after: |
| // CHECK: operand #0 |
| // CHECK: - inner |
| // CHECK: test_tag: return: |
| // CHECK: operand #0 |
| // CHECK: - post |
| func.func @store_with_a_region_before_containing_a_store(%arg0: memref<f32>) -> memref<f32> { |
| %0 = arith.constant 0.0 : f32 |
| %1 = arith.constant 1.0 : f32 |
| memref.store %0, %arg0[] {tag_name = "pre"} : memref<f32> |
| memref.load %arg0[] {tag = "store_with_a_region_before_containing_a_store::before"} : memref<f32> |
| test.store_with_a_region %arg0 attributes { tag_name = "region", store_before_region = true } { |
| memref.load %arg0[] {tag = "enter_region"} : memref<f32> |
| %2 = arith.constant 2.0 : f32 |
| memref.store %2, %arg0[] {tag_name = "inner"} : memref<f32> |
| memref.load %arg0[] {tag = "exit_region"} : memref<f32> |
| test.store_with_a_region_terminator |
| } : memref<f32> |
| memref.load %arg0[] {tag = "after"} : memref<f32> |
| memref.store %1, %arg0[] {tag_name = "post"} : memref<f32> |
| return {tag = "return"} %arg0 : memref<f32> |
| } |
| |
| // CHECK-LABEL: test_tag: store_with_a_region_after_containing_a_store::before: |
| // CHECK: operand #0 |
| // CHECK: - pre |
| // CHECK: test_tag: enter_region: |
| // CHECK: operand #0 |
| // CHECK: - pre |
| // CHECK: test_tag: exit_region: |
| // CHECK: operand #0 |
| // CHECK: - inner |
| // CHECK: test_tag: after: |
| // CHECK: operand #0 |
| // CHECK: - region |
| // CHECK: test_tag: return: |
| // CHECK: operand #0 |
| // CHECK: - post |
| func.func @store_with_a_region_after_containing_a_store(%arg0: memref<f32>) -> memref<f32> { |
| %0 = arith.constant 0.0 : f32 |
| %1 = arith.constant 1.0 : f32 |
| memref.store %0, %arg0[] {tag_name = "pre"} : memref<f32> |
| memref.load %arg0[] {tag = "store_with_a_region_after_containing_a_store::before"} : memref<f32> |
| test.store_with_a_region %arg0 attributes { tag_name = "region", store_before_region = false } { |
| memref.load %arg0[] {tag = "enter_region"} : memref<f32> |
| %2 = arith.constant 2.0 : f32 |
| memref.store %2, %arg0[] {tag_name = "inner"} : memref<f32> |
| memref.load %arg0[] {tag = "exit_region"} : memref<f32> |
| test.store_with_a_region_terminator |
| } : memref<f32> |
| memref.load %arg0[] {tag = "after"} : memref<f32> |
| memref.store %1, %arg0[] {tag_name = "post"} : memref<f32> |
| return {tag = "return"} %arg0 : memref<f32> |
| } |
| |
| // CHECK-LABEL: test_tag: store_with_a_loop_region_before::before: |
| // CHECK: operand #0 |
| // CHECK: - pre |
| // CHECK: test_tag: inside_region: |
| // CHECK: operand #0 |
| // CHECK: - region |
| // CHECK: test_tag: after: |
| // CHECK: operand #0 |
| // CHECK: - region |
| // CHECK: test_tag: return: |
| // CHECK: operand #0 |
| // CHECK: - post |
| func.func @store_with_a_loop_region_before(%arg0: memref<f32>) -> memref<f32> { |
| %0 = arith.constant 0.0 : f32 |
| %1 = arith.constant 1.0 : f32 |
| memref.store %0, %arg0[] {tag_name = "pre"} : memref<f32> |
| memref.load %arg0[] {tag = "store_with_a_loop_region_before::before"} : memref<f32> |
| test.store_with_a_loop_region %arg0 attributes { tag_name = "region", store_before_region = true } { |
| memref.load %arg0[] {tag = "inside_region"} : memref<f32> |
| test.store_with_a_region_terminator |
| } : memref<f32> |
| memref.load %arg0[] {tag = "after"} : memref<f32> |
| memref.store %1, %arg0[] {tag_name = "post"} : memref<f32> |
| return {tag = "return"} %arg0 : memref<f32> |
| } |
| |
| // CHECK-LABEL: test_tag: store_with_a_loop_region_after::before: |
| // CHECK: operand #0 |
| // CHECK: - pre |
| // CHECK: test_tag: inside_region: |
| // CHECK: operand #0 |
| // CHECK: - pre |
| // CHECK: test_tag: after: |
| // CHECK: operand #0 |
| // CHECK: - region |
| // CHECK: test_tag: return: |
| // CHECK: operand #0 |
| // CHECK: - post |
| func.func @store_with_a_loop_region_after(%arg0: memref<f32>) -> memref<f32> { |
| %0 = arith.constant 0.0 : f32 |
| %1 = arith.constant 1.0 : f32 |
| memref.store %0, %arg0[] {tag_name = "pre"} : memref<f32> |
| memref.load %arg0[] {tag = "store_with_a_loop_region_after::before"} : memref<f32> |
| test.store_with_a_loop_region %arg0 attributes { tag_name = "region", store_before_region = false } { |
| memref.load %arg0[] {tag = "inside_region"} : memref<f32> |
| test.store_with_a_region_terminator |
| } : memref<f32> |
| memref.load %arg0[] {tag = "after"} : memref<f32> |
| memref.store %1, %arg0[] {tag_name = "post"} : memref<f32> |
| return {tag = "return"} %arg0 : memref<f32> |
| } |
| |
| // CHECK-LABEL: test_tag: store_with_a_loop_region_before_containing_a_store::before: |
| // CHECK: operand #0 |
| // CHECK: - pre |
| // CHECK: test_tag: enter_region: |
| // CHECK: operand #0 |
| // CHECK-DAG: - region |
| // CHECK-DAG: - inner |
| // CHECK: test_tag: exit_region: |
| // CHECK: operand #0 |
| // CHECK: - inner |
| // CHECK: test_tag: after: |
| // CHECK: operand #0 |
| // CHECK-DAG: - region |
| // CHECK-DAG: - inner |
| // CHECK: test_tag: return: |
| // CHECK: operand #0 |
| // CHECK: - post |
| func.func @store_with_a_loop_region_before_containing_a_store(%arg0: memref<f32>) -> memref<f32> { |
| %0 = arith.constant 0.0 : f32 |
| %1 = arith.constant 1.0 : f32 |
| memref.store %0, %arg0[] {tag_name = "pre"} : memref<f32> |
| memref.load %arg0[] {tag = "store_with_a_loop_region_before_containing_a_store::before"} : memref<f32> |
| test.store_with_a_loop_region %arg0 attributes { tag_name = "region", store_before_region = true } { |
| memref.load %arg0[] {tag = "enter_region"} : memref<f32> |
| %2 = arith.constant 2.0 : f32 |
| memref.store %2, %arg0[] {tag_name = "inner"} : memref<f32> |
| memref.load %arg0[] {tag = "exit_region"} : memref<f32> |
| test.store_with_a_region_terminator |
| } : memref<f32> |
| memref.load %arg0[] {tag = "after"} : memref<f32> |
| memref.store %1, %arg0[] {tag_name = "post"} : memref<f32> |
| return {tag = "return"} %arg0 : memref<f32> |
| } |
| |
| // CHECK-LABEL: test_tag: store_with_a_loop_region_after_containing_a_store::before: |
| // CHECK: operand #0 |
| // CHECK: - pre |
| // CHECK: test_tag: enter_region: |
| // CHECK: operand #0 |
| // CHECK-DAG: - pre |
| // CHECK-DAG: - inner |
| // CHECK: test_tag: exit_region: |
| // CHECK: operand #0 |
| // CHECK: - inner |
| // CHECK: test_tag: after: |
| // CHECK: operand #0 |
| // CHECK: - region |
| // CHECK: test_tag: return: |
| // CHECK: operand #0 |
| // CHECK: - post |
| func.func @store_with_a_loop_region_after_containing_a_store(%arg0: memref<f32>) -> memref<f32> { |
| %0 = arith.constant 0.0 : f32 |
| %1 = arith.constant 1.0 : f32 |
| memref.store %0, %arg0[] {tag_name = "pre"} : memref<f32> |
| memref.load %arg0[] {tag = "store_with_a_loop_region_after_containing_a_store::before"} : memref<f32> |
| test.store_with_a_loop_region %arg0 attributes { tag_name = "region", store_before_region = false } { |
| memref.load %arg0[] {tag = "enter_region"} : memref<f32> |
| %2 = arith.constant 2.0 : f32 |
| memref.store %2, %arg0[] {tag_name = "inner"} : memref<f32> |
| memref.load %arg0[] {tag = "exit_region"} : memref<f32> |
| test.store_with_a_region_terminator |
| } : memref<f32> |
| memref.load %arg0[] {tag = "after"} : memref<f32> |
| memref.store %1, %arg0[] {tag_name = "post"} : memref<f32> |
| return {tag = "return"} %arg0 : memref<f32> |
| } |