Skip to content

Commit 0ebf870

Browse files
authored
Merge pull request #76836 from gottesmm/thunk_lowering
[sil] Add thunk lowering and the thunk instruction.
2 parents 44a5dd1 + f985b0e commit 0ebf870

34 files changed

+1838
-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/SILModule.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -644,6 +644,13 @@ class SILModule {
644644
return {functions.begin(), functions.end()};
645645
}
646646

647+
/// Move \p fn to be in the function list before \p moveBefore.
648+
void moveBefore(SILModule::iterator moveBefore, SILFunction *fn);
649+
650+
/// Move \p fn to be in the function list after \p moveAfter. It is assumed
651+
/// that \p moveAfter is not end.
652+
void moveAfter(SILModule::iterator moveAfter, SILFunction *fn);
653+
647654
const_iterator zombies_begin() const { return zombieFunctions.begin(); }
648655
const_iterator zombies_end() const { return zombieFunctions.end(); }
649656

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,

0 commit comments

Comments
 (0)