Skip to content

Commit 561662d

Browse files
committed
[sil] Add a new instruction called ThunkInst.
For now this will only be used for HopToMainActorIfNeeded thunks. I am creating this now since in the past there has only been one option for creating thunks... to create the thunk in SILGen using SILGenThunk. This code is hard to test and there is a lot of it. By using an instruction here we get a few benefits: 1. We decouple SILGen from needing to generate new kinds of thunks. This means that SILGenThunk does not need to expand to handle more thunks. 2. All thunks implemented via ThunkInst will be easy to test in a decoupled way with SIL tests. 3. Even though this stabilizes the patient, we still have many thunks in SILGen and various parts of the compiler. Over time, we can swap to this model, allowing us to hopefully eventually delete SILGenThunk.
1 parent 3442fba commit 561662d

27 files changed

+476
-11
lines changed

SwiftCompilerSources/Sources/SIL/Instruction.swift

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1601,3 +1601,6 @@ final public class CheckedCastAddrBranchInst : TermInst {
16011601
}
16021602
}
16031603
}
1604+
1605+
final public class ThunkInst : Instruction {
1606+
}

SwiftCompilerSources/Sources/SIL/Registration.swift

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -256,4 +256,5 @@ public func registerSILClasses() {
256256
register(AwaitAsyncContinuationInst.self)
257257
register(CheckedCastBranchInst.self)
258258
register(CheckedCastAddrBranchInst.self)
259+
register(ThunkInst.self)
259260
}

docs/SIL.rst

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8107,6 +8107,40 @@ passed to a function (materializeForSet) which escapes the closure in a way not
81078107
expressed by the convert's users. The mandatory pass must ensure the lifetime
81088108
in a conservative way.
81098109

8110+
8111+
thunk
8112+
`````
8113+
::
8114+
8115+
sil-instruction ::= 'thunk' sil-thunk-attr* sil-value sil-apply-substitution-list? () sil-type
8116+
sil-thunk-attr ::= '[' thunk-kind ']'
8117+
sil-thunk-kind ::= identity
8118+
8119+
%1 = thunk [identity] %0() : $@convention(thin) (T) -> U
8120+
// %0 must be of a function type $T -> U
8121+
// %1 will be of type @callee_guaranteed (T) -> U since we are creating an
8122+
// "identity" thunk.
8123+
8124+
%1 = thunk [identity] %0<T>() : $@convention(thin) (τ_0_0) -> ()
8125+
// %0 must be of a function type $T -> ()
8126+
// %1 will be of type @callee_guaranteed <τ_0_0> (τ_0_0) -> () since we are creating a
8127+
// "identity" thunk.
8128+
8129+
Takes in a function and depending on the kind produces a new function result
8130+
that is ``@callee_guaranteed``. The specific way that the function type of the
8131+
input is modified by this instruction depends on the specific sil-thunk-kind of
8132+
the instruction. So for instance, the hop_to_mainactor_if_needed thunk just
8133+
returns a callee_guaranteed version of the input function... but one could
8134+
imagine a "reabstracted" thunk kind that would produce the appropriate
8135+
reabstracted thunk kind.
8136+
8137+
This instructions is lowered to a true think in Lowered SIL by the ThunkLowering
8138+
pass.
8139+
8140+
It is assumed that like `partial_apply`_, if we need a substitution map, it will be
8141+
attached to `thunk`_. This ensures that we have the substitution
8142+
map already created if we need to create a `partial_apply`_.
8143+
81108144
classify_bridge_object
81118145
``````````````````````
81128146
::

include/swift/AST/DiagnosticsParse.def

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2165,5 +2165,11 @@ ERROR(sending_repeated,none,
21652165
ERROR(sending_cannot_be_used_with_borrowing,none,
21662166
"'%0' cannot be used together with 'borrowing'", (StringRef))
21672167

2168+
ERROR(sil_thunkinst_failed_to_parse_kind,none,
2169+
"'%0' is not a valid thunk kind supported by ThunkInst", (StringRef))
2170+
2171+
ERROR(sil_failed_to_parse_sil_optional,none,
2172+
"Expected SIL optional value of the form '[' NAME ']'", ())
2173+
21682174
#define UNDEFINE_DIAGNOSTIC_MACROS
21692175
#include "DefineDiagnosticMacros.h"

include/swift/AST/Types.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5027,6 +5027,11 @@ class SILFunctionType final
50275027
return getCalleeConvention() == ParameterConvention::Direct_Guaranteed;
50285028
}
50295029

5030+
/// Return a copy of this SILFunctionType with its CalleConvention changed to
5031+
/// \p newCalleeConvention.
5032+
CanSILFunctionType
5033+
getWithCalleeConvention(ParameterConvention newCalleeConvention);
5034+
50305035
/// Is this some kind of coroutine?
50315036
bool isCoroutine() const {
50325037
return getCoroutineKind() != SILCoroutineKind::None;

include/swift/SIL/SILBuilder.h

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1240,6 +1240,17 @@ class SILBuilder {
12401240
WithoutActuallyEscaping, forwardingOwnershipKind));
12411241
}
12421242

1243+
ThunkInst *createThunk(SILLocation Loc, SILValue Op, ThunkInst::Kind kind,
1244+
SubstitutionMap substitutionMap = {}) {
1245+
return insert(ThunkInst::create(getSILDebugLocation(Loc), Op, getModule(),
1246+
F, kind, substitutionMap));
1247+
}
1248+
1249+
ThunkInst *createIdentityThunk(SILLocation Loc, SILValue Op,
1250+
SubstitutionMap substitutionMap = {}) {
1251+
return createThunk(Loc, Op, ThunkInst::Kind::Identity, substitutionMap);
1252+
}
1253+
12431254
ConvertEscapeToNoEscapeInst *
12441255
createConvertEscapeToNoEscape(SILLocation Loc, SILValue Op, SILType Ty,
12451256
bool lifetimeGuaranteed) {

include/swift/SIL/SILCloner.h

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1783,6 +1783,15 @@ SILCloner<ImplClass>::visitConvertFunctionInst(ConvertFunctionInst *Inst) {
17831783
: ValueOwnershipKind(OwnershipKind::None)));
17841784
}
17851785

1786+
template <typename ImplClass>
1787+
void SILCloner<ImplClass>::visitThunkInst(ThunkInst *Inst) {
1788+
getBuilder().setCurrentDebugScope(getOpScope(Inst->getDebugScope()));
1789+
recordClonedInstruction(
1790+
Inst, getBuilder().createThunk(getOpLocation(Inst->getLoc()),
1791+
getOpValue(Inst->getOperand()),
1792+
Inst->getThunkKind()));
1793+
}
1794+
17861795
template <typename ImplClass>
17871796
void SILCloner<ImplClass>::visitConvertEscapeToNoEscapeInst(
17881797
ConvertEscapeToNoEscapeInst *Inst) {

include/swift/SIL/SILInstruction.h

Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5868,6 +5868,78 @@ class ConvertFunctionInst final
58685868
bool onlyConvertsSendable() const;
58695869
};
58705870

5871+
class ThunkInst final
5872+
: public UnaryInstructionWithTypeDependentOperandsBase<
5873+
SILInstructionKind::ThunkInst, ThunkInst, SingleValueInstruction> {
5874+
public:
5875+
struct Kind {
5876+
enum InnerTy {
5877+
Invalid = 0,
5878+
5879+
/// A thunk that just calls the passed in function. Used for testing
5880+
/// purposes of the underlying thunking machinery.
5881+
Identity = 1,
5882+
5883+
MaxValue = Identity,
5884+
};
5885+
5886+
InnerTy innerTy;
5887+
5888+
Kind() : innerTy(InnerTy::Invalid) {}
5889+
Kind(InnerTy innerTy) : innerTy(innerTy) {}
5890+
Kind(unsigned inputInnerTy) : innerTy(InnerTy(inputInnerTy)) {
5891+
assert(inputInnerTy <= MaxValue && "Invalid value");
5892+
}
5893+
5894+
operator InnerTy() const { return innerTy; }
5895+
5896+
/// Given the current enum state returned the derived output function from
5897+
/// \p inputFunction.
5898+
CanSILFunctionType getDerivedFunctionType(SILFunction *fn,
5899+
CanSILFunctionType inputFunction,
5900+
SubstitutionMap subMap) const;
5901+
5902+
SILType getDerivedFunctionType(SILFunction *fn, SILType inputFunctionType,
5903+
SubstitutionMap subMap) const {
5904+
auto fType = inputFunctionType.castTo<SILFunctionType>();
5905+
return SILType::getPrimitiveType(
5906+
getDerivedFunctionType(fn, fType, subMap),
5907+
inputFunctionType.getCategory());
5908+
}
5909+
};
5910+
5911+
/// The type of thunk we are supposed to produce.
5912+
Kind kind;
5913+
5914+
/// The substitutions being applied to the callee when we generate thunks for
5915+
/// it. E.x.: if we generate a partial_apply, this will be the substitution
5916+
/// map used to generate the partial_apply.
5917+
SubstitutionMap substitutions;
5918+
5919+
private:
5920+
friend SILBuilder;
5921+
5922+
ThunkInst(SILDebugLocation debugLoc, SILValue operand,
5923+
ArrayRef<SILValue> typeDependentOperands, SILType outputType,
5924+
Kind kind, SubstitutionMap subs)
5925+
: UnaryInstructionWithTypeDependentOperandsBase(
5926+
debugLoc, operand, typeDependentOperands, outputType),
5927+
kind(kind), substitutions(subs) {}
5928+
5929+
static ThunkInst *create(SILDebugLocation debugLoc, SILValue operand,
5930+
SILModule &mod, SILFunction *func, Kind kind,
5931+
SubstitutionMap subs);
5932+
5933+
public:
5934+
Kind getThunkKind() const { return kind; }
5935+
5936+
SubstitutionMap getSubstitutionMap() const { return substitutions; }
5937+
5938+
CanSILFunctionType getOrigCalleeType() const {
5939+
return getOperand()->getType().castTo<SILFunctionType>();
5940+
}
5941+
};
5942+
58715943
/// ConvertEscapeToNoEscapeInst - Change the type of a escaping function value
58725944
/// to a trivial function type (@noescape T -> U).
58735945
class ConvertEscapeToNoEscapeInst final

include/swift/SIL/SILNodes.def

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -405,6 +405,8 @@ ABSTRACT_VALUE_AND_INST(SingleValueInstruction, ValueBase, SILInstruction)
405405
#include "swift/AST/ReferenceStorage.def"
406406
SINGLE_VALUE_INST(ConvertFunctionInst, convert_function,
407407
SingleValueInstruction, None, DoesNotRelease)
408+
SINGLE_VALUE_INST(ThunkInst, thunk,
409+
SingleValueInstruction, MayHaveSideEffects, MayRelease)
408410
SINGLE_VALUE_INST(ConvertEscapeToNoEscapeInst, convert_escape_to_noescape,
409411
SingleValueInstruction, None, DoesNotRelease)
410412
SINGLE_VALUE_INST(RefToBridgeObjectInst, ref_to_bridge_object,

lib/IRGen/IRGenSIL.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1425,6 +1425,10 @@ class IRGenSILFunction :
14251425
void visitIncrementProfilerCounterInst(IncrementProfilerCounterInst *I);
14261426

14271427
void visitConvertFunctionInst(ConvertFunctionInst *i);
1428+
void visitThunkInst(ThunkInst *i) {
1429+
llvm_unreachable(
1430+
"Should have been lowered before IRGen by the ThunkLowering pass");
1431+
}
14281432
void visitConvertEscapeToNoEscapeInst(ConvertEscapeToNoEscapeInst *i);
14291433
void visitUpcastInst(UpcastInst *i);
14301434
void visitAddressToPointerInst(AddressToPointerInst *i);

0 commit comments

Comments
 (0)