| // RUN: mlir-opt %s --split-input-file --duplicate-function-elimination | \ |
| // RUN: FileCheck %s |
| |
| func.func @identity(%arg0: tensor<f32>) -> tensor<f32> { |
| return %arg0 : tensor<f32> |
| } |
| |
| func.func @also_identity(%arg0: tensor<f32>) -> tensor<f32> { |
| return %arg0 : tensor<f32> |
| } |
| |
| func.func @yet_another_identity(%arg0: tensor<f32>) -> tensor<f32> { |
| return %arg0 : tensor<f32> |
| } |
| |
| func.func @user(%arg0: tensor<f32>) -> tensor<f32> { |
| %0 = call @identity(%arg0) : (tensor<f32>) -> tensor<f32> |
| %1 = call @also_identity(%0) : (tensor<f32>) -> tensor<f32> |
| %2 = call @yet_another_identity(%1) : (tensor<f32>) -> tensor<f32> |
| return %2 : tensor<f32> |
| } |
| |
| // CHECK: @identity |
| // CHECK-NOT: @also_identity |
| // CHECK-NOT: @yet_another_identity |
| // CHECK: @user |
| // CHECK-3: call @identity |
| |
| // ----- |
| |
| func.func @add_lr(%arg0: f32, %arg1: f32) -> f32 { |
| %0 = arith.addf %arg0, %arg1 : f32 |
| return %0 : f32 |
| } |
| |
| func.func @also_add_lr(%arg0: f32, %arg1: f32) -> f32 { |
| %0 = arith.addf %arg0, %arg1 : f32 |
| return %0 : f32 |
| } |
| |
| func.func @add_rl(%arg0: f32, %arg1: f32) -> f32 { |
| %0 = arith.addf %arg1, %arg0 : f32 |
| return %0 : f32 |
| } |
| |
| func.func @also_add_rl(%arg0: f32, %arg1: f32) -> f32 { |
| %0 = arith.addf %arg1, %arg0 : f32 |
| return %0 : f32 |
| } |
| |
| func.func @user(%arg0: f32, %arg1: f32) -> f32 { |
| %0 = call @add_lr(%arg0, %arg1) : (f32, f32) -> f32 |
| %1 = call @also_add_lr(%arg0, %arg1) : (f32, f32) -> f32 |
| %2 = call @add_rl(%0, %1) : (f32, f32) -> f32 |
| %3 = call @also_add_rl(%arg0, %2) : (f32, f32) -> f32 |
| return %3 : f32 |
| } |
| |
| // CHECK: @add_lr |
| // CHECK-NOT: @also_add_lr |
| // CHECK: @add_rl |
| // CHECK-NOT: @also_add_rl |
| // CHECK: @user |
| // CHECK-2: call @add_lr |
| // CHECK-2: call @add_rl |
| |
| // ----- |
| |
| func.func @ite(%pred: i1, %then: f32, %else: f32) -> f32 { |
| %0 = scf.if %pred -> f32 { |
| scf.yield %then : f32 |
| } else { |
| scf.yield %else : f32 |
| } |
| return %0 : f32 |
| } |
| |
| func.func @also_ite(%pred: i1, %then: f32, %else: f32) -> f32 { |
| %0 = scf.if %pred -> f32 { |
| scf.yield %then : f32 |
| } else { |
| scf.yield %else : f32 |
| } |
| return %0 : f32 |
| } |
| |
| func.func @reverse_ite(%pred: i1, %then: f32, %else: f32) -> f32 { |
| %0 = scf.if %pred -> f32 { |
| scf.yield %else : f32 |
| } else { |
| scf.yield %then : f32 |
| } |
| return %0 : f32 |
| } |
| |
| func.func @user(%pred : i1, %arg0: f32, %arg1: f32) -> f32 { |
| %0 = call @also_ite(%pred, %arg0, %arg1) : (i1, f32, f32) -> f32 |
| %1 = call @ite(%pred, %arg0, %arg1) : (i1, f32, f32) -> f32 |
| %2 = call @reverse_ite(%pred, %0, %1) : (i1, f32, f32) -> f32 |
| return %2 : f32 |
| } |
| |
| // CHECK: @ite |
| // CHECK-NOT: @also_ite |
| // CHECK: @reverse_ite |
| // CHECK: @user |
| // CHECK-2: call @ite |
| // CHECK: call @reverse_ite |
| |
| // ----- |
| |
| func.func @deep_tree(%p0: i1, %p1: i1, %p2: i1, %p3: i1, %even: f32, %odd: f32) |
| -> f32 { |
| %0 = scf.if %p0 -> f32 { |
| %1 = scf.if %p1 -> f32 { |
| %2 = scf.if %p2 -> f32 { |
| %3 = scf.if %p3 -> f32 { |
| scf.yield %even : f32 |
| } else { |
| scf.yield %odd : f32 |
| } |
| scf.yield %3 : f32 |
| } else { |
| %3 = scf.if %p3 -> f32 { |
| scf.yield %odd : f32 |
| } else { |
| scf.yield %even : f32 |
| } |
| scf.yield %3 : f32 |
| } |
| scf.yield %2 : f32 |
| } else { |
| %2 = scf.if %p2 -> f32 { |
| %3 = scf.if %p3 -> f32 { |
| scf.yield %odd : f32 |
| } else { |
| scf.yield %even : f32 |
| } |
| scf.yield %3 : f32 |
| } else { |
| %3 = scf.if %p3 -> f32 { |
| scf.yield %even : f32 |
| } else { |
| scf.yield %odd : f32 |
| } |
| scf.yield %3 : f32 |
| } |
| scf.yield %2 : f32 |
| } |
| scf.yield %1 : f32 |
| } else { |
| %1 = scf.if %p1 -> f32 { |
| %2 = scf.if %p2 -> f32 { |
| %3 = scf.if %p3 -> f32 { |
| scf.yield %odd : f32 |
| } else { |
| scf.yield %even : f32 |
| } |
| scf.yield %3 : f32 |
| } else { |
| %3 = scf.if %p3 -> f32 { |
| scf.yield %even : f32 |
| } else { |
| scf.yield %odd : f32 |
| } |
| scf.yield %3 : f32 |
| } |
| scf.yield %2 : f32 |
| } else { |
| %2 = scf.if %p2 -> f32 { |
| %3 = scf.if %p3 -> f32 { |
| scf.yield %even : f32 |
| } else { |
| scf.yield %odd : f32 |
| } |
| scf.yield %3 : f32 |
| } else { |
| %3 = scf.if %p3 -> f32 { |
| scf.yield %odd : f32 |
| } else { |
| scf.yield %even : f32 |
| } |
| scf.yield %3 : f32 |
| } |
| scf.yield %2 : f32 |
| } |
| scf.yield %1 : f32 |
| } |
| return %0 : f32 |
| } |
| |
| func.func @also_deep_tree(%p0: i1, %p1: i1, %p2: i1, %p3: i1, %even: f32, |
| %odd: f32) -> f32 { |
| %0 = scf.if %p0 -> f32 { |
| %1 = scf.if %p1 -> f32 { |
| %2 = scf.if %p2 -> f32 { |
| %3 = scf.if %p3 -> f32 { |
| scf.yield %even : f32 |
| } else { |
| scf.yield %odd : f32 |
| } |
| scf.yield %3 : f32 |
| } else { |
| %3 = scf.if %p3 -> f32 { |
| scf.yield %odd : f32 |
| } else { |
| scf.yield %even : f32 |
| } |
| scf.yield %3 : f32 |
| } |
| scf.yield %2 : f32 |
| } else { |
| %2 = scf.if %p2 -> f32 { |
| %3 = scf.if %p3 -> f32 { |
| scf.yield %odd : f32 |
| } else { |
| scf.yield %even : f32 |
| } |
| scf.yield %3 : f32 |
| } else { |
| %3 = scf.if %p3 -> f32 { |
| scf.yield %even : f32 |
| } else { |
| scf.yield %odd : f32 |
| } |
| scf.yield %3 : f32 |
| } |
| scf.yield %2 : f32 |
| } |
| scf.yield %1 : f32 |
| } else { |
| %1 = scf.if %p1 -> f32 { |
| %2 = scf.if %p2 -> f32 { |
| %3 = scf.if %p3 -> f32 { |
| scf.yield %odd : f32 |
| } else { |
| scf.yield %even : f32 |
| } |
| scf.yield %3 : f32 |
| } else { |
| %3 = scf.if %p3 -> f32 { |
| scf.yield %even : f32 |
| } else { |
| scf.yield %odd : f32 |
| } |
| scf.yield %3 : f32 |
| } |
| scf.yield %2 : f32 |
| } else { |
| %2 = scf.if %p2 -> f32 { |
| %3 = scf.if %p3 -> f32 { |
| scf.yield %even : f32 |
| } else { |
| scf.yield %odd : f32 |
| } |
| scf.yield %3 : f32 |
| } else { |
| %3 = scf.if %p3 -> f32 { |
| scf.yield %odd : f32 |
| } else { |
| scf.yield %even : f32 |
| } |
| scf.yield %3 : f32 |
| } |
| scf.yield %2 : f32 |
| } |
| scf.yield %1 : f32 |
| } |
| return %0 : f32 |
| } |
| |
| func.func @reverse_deep_tree(%p0: i1, %p1: i1, %p2: i1, %p3: i1, %even: f32, |
| %odd: f32) -> f32 { |
| %0 = scf.if %p0 -> f32 { |
| %1 = scf.if %p1 -> f32 { |
| %2 = scf.if %p2 -> f32 { |
| %3 = scf.if %p3 -> f32 { |
| scf.yield %odd : f32 |
| } else { |
| scf.yield %even : f32 |
| } |
| scf.yield %3 : f32 |
| } else { |
| %3 = scf.if %p3 -> f32 { |
| scf.yield %even : f32 |
| } else { |
| scf.yield %odd : f32 |
| } |
| scf.yield %3 : f32 |
| } |
| scf.yield %2 : f32 |
| } else { |
| %2 = scf.if %p2 -> f32 { |
| %3 = scf.if %p3 -> f32 { |
| scf.yield %even : f32 |
| } else { |
| scf.yield %odd : f32 |
| } |
| scf.yield %3 : f32 |
| } else { |
| %3 = scf.if %p3 -> f32 { |
| scf.yield %odd : f32 |
| } else { |
| scf.yield %even : f32 |
| } |
| scf.yield %3 : f32 |
| } |
| scf.yield %2 : f32 |
| } |
| scf.yield %1 : f32 |
| } else { |
| %1 = scf.if %p1 -> f32 { |
| %2 = scf.if %p2 -> f32 { |
| %3 = scf.if %p3 -> f32 { |
| scf.yield %even : f32 |
| } else { |
| scf.yield %odd : f32 |
| } |
| scf.yield %3 : f32 |
| } else { |
| %3 = scf.if %p3 -> f32 { |
| scf.yield %odd : f32 |
| } else { |
| scf.yield %even : f32 |
| } |
| scf.yield %3 : f32 |
| } |
| scf.yield %2 : f32 |
| } else { |
| %2 = scf.if %p2 -> f32 { |
| %3 = scf.if %p3 -> f32 { |
| scf.yield %odd : f32 |
| } else { |
| scf.yield %even : f32 |
| } |
| scf.yield %3 : f32 |
| } else { |
| %3 = scf.if %p3 -> f32 { |
| scf.yield %even : f32 |
| } else { |
| scf.yield %odd : f32 |
| } |
| scf.yield %3 : f32 |
| } |
| scf.yield %2 : f32 |
| } |
| scf.yield %1 : f32 |
| } |
| return %0 : f32 |
| } |
| |
| func.func @user(%p0: i1, %p1: i1, %p2: i1, %p3: i1, %odd: f32, %even: f32) |
| -> (f32, f32, f32) { |
| %0 = call @deep_tree(%p0, %p1, %p2, %p3, %odd, %even) |
| : (i1, i1, i1, i1, f32, f32) -> f32 |
| %1 = call @also_deep_tree(%p0, %p1, %p2, %p3, %odd, %even) |
| : (i1, i1, i1, i1, f32, f32) -> f32 |
| %2 = call @reverse_deep_tree(%p0, %p1, %p2, %p3, %odd, %even) |
| : (i1, i1, i1, i1, f32, f32) -> f32 |
| return %0, %1, %2 : f32, f32, f32 |
| } |
| |
| // CHECK: @deep_tree |
| // CHECK-NOT: @also_deep_tree |
| // CHECK: @reverse_deep_tree |
| // CHECK: @user |
| // CHECK-2: call @deep_tree |
| // CHECK: call @reverse_deep_tree |