Context
SIL supports instructions that produce multiple values (i.e. multiple result SILValue
s).
However, apply
instructions don't produce multiple values. Instead, they produce a single value, which may have a tuple type. This leads to much avoidable destructuring and restructuring of tuples, which complicates SIL transformations like autodiff:
// example.swift
@_silgen_name("foo")
func foo() -> (Int, Int) {
(0, 0)
}
@_silgen_name("bar")
func bar() -> (Int, Int) {
return foo()
}
$ swiftc -emit-silgen example.swift
sil hidden [ossa] @bar : $@convention(thin) () -> (Int, Int) {
bb0:
%0 = function_ref @foo : $@convention(thin) () -> (Int, Int)
%1 = apply %0() : $@convention(thin) () -> (Int, Int)
(%2, %3) = destructure_tuple %1 : $(Int, Int) // this is not good
%4 = tuple (%2 : $Int, %3 : $Int)
return %4 : $(Int, Int)
}
Motivation
Here are utilities that can be cleaned up if ApplyInst
produces multiple values:
-
getSingleDestructureTupleUser
: used just forApplyInst
. -
forEachApplyDirectResult
: a helper to iterate over all direct results of anApplySite
, callinggetSingleDestructureTupleUser
forApplyInst
. -
Example usage of
forEachApplyDirectResult
inPullbackCloner::visitApplyInst
.
Questions
-
It's my understanding is that this design is because
MultipleValueInstruction
infra was added afterApplyInst
. Is this true? -
Since SIL does not promise compatibility, can we change
ApplyInst
to inheritMultipleValueInstruction
? What's the bar for accepting this change (e.g. all tests pass, code generation is unchanged after the change)?
I went ahead and filed an issue tracking this internal cleanup, feel free to modify it: