// RUN: mlir-opt %s --split-input-file --duplicate-function-elimination | \ // RUN: FileCheck %s func.func @identity(%arg0: tensor) -> tensor { return %arg0 : tensor } func.func @also_identity(%arg0: tensor) -> tensor { return %arg0 : tensor } func.func @yet_another_identity(%arg0: tensor) -> tensor { return %arg0 : tensor } func.func @user(%arg0: tensor) -> tensor { %0 = call @identity(%arg0) : (tensor) -> tensor %1 = call @also_identity(%0) : (tensor) -> tensor %2 = call @yet_another_identity(%1) : (tensor) -> tensor return %2 : tensor } // 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