[swift-dev] Why do open_existential instructions use a unique type per call site?

Nadav Rotem nrotem at apple.com
Thu Feb 18 11:46:23 CST 2016


I am looking into a performance issue that Mark Lacey identified yesterday. He pointed out that the implementation of calls that go through protocols could be optimized by CSE-ing the method lookup. Before each call we emit code for loading the pointer of the witness table from the existential container, and then we perform another lookup in the witness table to find the method pointer. In some cases we can prove that the witness table is not changed by the program and we could reuse the method pointer and eliminate two loads.

Consider the code below:

protocol Pingable { func ping() }

func foo(x : Pingable) {

The Swift code above is translated into the abridged SIL function below:

sil hidden @_TF4main3fooFPS_8Pingable_T_ : $@convention(thin) (@in Pingable) -> () {
bb0(%0 : $*Pingable):

// "CE4" call
  %2 = open_existential_addr %0 : $*Pingable to $*@opened(“8DF56CE4-...") Pingable
  %3 = witness_method $@opened(“8DF56CE4...") Pingable, #Pingable.ping!1, %2 : $*@opened(“8DF56CE4-..") Pingable :  .. 
  %4 = apply %3<@opened(“8DF56CE4-...") Pingable>(%2) : … 

// “4B4" call
  %5 = open_existential_addr %0 : $*Pingable to $*@opened("8DF574B4-..” )Pingable
  %6 = witness_method $@opened(“8DF574B4...") Pingable, #Pingable.ping!1, %5 : $*@opened("8DF574B4-") Singable : …
  %7 = apply %6<@opened("8DF574B4-") Pingable>(%5) :  … 
 destroy_addr %0 : $*Pingable
  %9 = tuple ()
  return %9 : $()

The three instructions open_existential_addr,witness_method and the apply are paired together with a unique type id. This means that the optimizer can’t replace the method pointer that was computed by the first call and use it for the second call. In the example above, we can’t use %3 for making the call in %7.  Notice that the ID of the first call ends with CE4 while the second ID ends with 4B4. 

My question is, why are the open_existential_addr+witness_method+apply instructions tied together with a unique type?  Can we come up with a different representation that will allow us to optimize the witness method lookups?


More information about the swift-dev mailing list