Requirements for being eligible for tail call optimization?

When apply in SIL becomes a tail call? Can I make it a tail call if apply and return live in difference basic blocks? Any reasons why tail call might be undesirable here?

Example 1:

// SimpleActorIsolated.__deallocating_deinit
sil hidden [available 12] @$s14default_deinit19SimpleActorIsolatedCfD : $@convention(method) (@owned SimpleActorIsolated) -> () {
// %0 "self"                                      // users: %5, %3, %1
bb0(%0 : $SimpleActorIsolated):
  debug_value %0 : $SimpleActorIsolated, let, name "self", argno 1, implicit // id: %1
  // function_ref SimpleActorIsolated.__isolated_deallocating_deinit
  %2 = function_ref @$s14default_deinit19SimpleActorIsolatedCfZ : $@convention(thin) (@owned SimpleActorIsolated) -> () // user: %6
  %3 = extract_executor %0 : $SimpleActorIsolated // user: %7
  // function_ref swift_task_performOnExecutor
  %4 = function_ref @swift_task_performOnExecutor : $@convention(thin) (@owned AnyObject, @convention(thin) (@owned AnyObject) -> (), Builtin.Executor) -> () // user: %7
  %5 = unchecked_bitwise_cast %0 : $SimpleActorIsolated to $AnyObject // user: %7
  %6 = convert_function %2 : $@convention(thin) (@owned SimpleActorIsolated) -> () to $@convention(thin) (@owned AnyObject) -> () // user: %7
 
  // How can I make sure this produces a tail call?
  %7 = apply %4(%5, %6, %3) : $@convention(thin) (@owned AnyObject, @convention(thin) (@owned AnyObject) -> (), Builtin.Executor) -> ()

  %8 = tuple ()                                   // user: %9
  return %8 : $()                                 // id: %9
} // end sil function '$s14default_deinit19SimpleActorIsolatedCfD'

Example 2:

...

bb1: 
  // function_ref MyDistActorIsolated.__isolated_deallocating_deinit
  %7 = function_ref @$s14default_deinit19MyDistActorIsolatedCfZ : $@convention(thin) (@owned MyDistActorIsolated) -> () // user: %11
  %8 = extract_executor %0 : $MyDistActorIsolated // user: %12
  // function_ref swift_task_performOnExecutor
  %9 = function_ref @swift_task_performOnExecutor : $@convention(thin) (@owned AnyObject, @convention(thin) (@owned AnyObject) -> (), Builtin.Executor) -> () // user: %12
  %10 = unchecked_bitwise_cast %0 : $MyDistActorIsolated to $AnyObject // user: %12
  %11 = convert_function %7 : $@convention(thin) (@owned MyDistActorIsolated) -> () to $@convention(thin) (@owned AnyObject) -> () // user: %12
  
  // How can I make sure this produces a tail call?
  %12 = apply %9(%10, %11, %8) : $@convention(thin) (@owned AnyObject, @convention(thin) (@owned AnyObject) -> (), Builtin.Executor) -> ()

  br bb2

bb2:                                              // Preds: bb1 bb3
  %14 = tuple ()                                  // user: %15
  return %14 : $()                                // id: %15
1 Like