mirror of
https://github.com/apple/swift.git
synced 2025-12-14 20:36:38 +01:00
[concurrency] NFC refactor out some code from LowerHopToActor before changing the pass.
Specifically, I am refactoring out the code that converts actor/Optional<any
Actor> to an executor in preparation for adding code to LowerHopToExecutor that
handles Builtin.ImplicitIsolationActor.
The only actual functional change is that I made getExecutorForOptionalActor
support being invoked when generating code (i.e. when its SILBuilder has an
insertion point at the end of the block). It previously assumed that it would
always have a real SILInstruction as an insertion point. The changes can be seen
in the places where we now check if the insertion point equals the end of a
block. Its very minor and due to conditional control flow doesn't have any
actual impact given the manner that the code today is generated. This came up in
a subsequent commit when I reuse this code to generate a helper function for
converting Builtin.ImplicitIsolationActor to Builtin.Executor.
(cherry picked from commit 21915ae428)
Conflicts:
lib/SILOptimizer/Mandatory/LowerHopToActor.cpp
This commit is contained in:
@@ -51,7 +51,6 @@ namespace {
|
||||
/// inserts the derivations, turning those hops into hops to executors.
|
||||
/// IRGen expects hops to be to executors before it runs.
|
||||
class LowerHopToActor {
|
||||
SILFunction *F;
|
||||
DominanceInfo *Dominance;
|
||||
|
||||
/// A map from an actor value to the dominating instruction that
|
||||
@@ -72,11 +71,7 @@ class LowerHopToActor {
|
||||
SILValue actor, bool makeOptional);
|
||||
|
||||
public:
|
||||
LowerHopToActor(SILFunction *f,
|
||||
DominanceInfo *dominance)
|
||||
: F(f),
|
||||
Dominance(dominance)
|
||||
{ }
|
||||
LowerHopToActor(DominanceInfo *dominance) : Dominance(dominance) {}
|
||||
|
||||
/// The entry point to the transformation.
|
||||
bool run();
|
||||
@@ -194,47 +189,33 @@ static AccessorDecl *getUnownedExecutorGetter(ASTContext &ctx,
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
SILValue LowerHopToActor::emitGetExecutor(SILBuilderWithScope &B,
|
||||
SILLocation loc, SILValue actor,
|
||||
bool makeOptional) {
|
||||
// This is okay because actor types have to be classes and so never
|
||||
// have multiple abstraction patterns.
|
||||
CanType actorType = actor->getType().getASTType();
|
||||
|
||||
// If the operand is already a BuiltinExecutorType, just wrap it
|
||||
// in an optional.
|
||||
if (makeOptional && actor->getType().is<BuiltinExecutorType>()) {
|
||||
return B.createOptionalSome(
|
||||
loc, actor,
|
||||
SILType::getOptionalType(actor->getType()));
|
||||
}
|
||||
|
||||
/// Emit the instructions to derive an executor value from an actor value.
|
||||
static SILValue getExecutorForActor(SILBuilder &B, SILLocation loc,
|
||||
SILValue actor) {
|
||||
auto *F = actor->getFunction();
|
||||
auto &ctx = F->getASTContext();
|
||||
auto executorType = SILType::getPrimitiveObjectType(ctx.TheExecutorType);
|
||||
auto optionalExecutorType = SILType::getOptionalType(executorType);
|
||||
|
||||
/// Emit the instructions to derive an executor value from an actor value.
|
||||
auto getExecutorFor = [&](SILValue actor) -> SILValue {
|
||||
// If the actor type is a default actor, go ahead and devirtualize here.
|
||||
auto module = F->getModule().getSwiftModule();
|
||||
CanType actorType = actor->getType().getASTType();
|
||||
|
||||
// Determine if the actor is a "default actor" in which case we'll build a default
|
||||
// actor executor ref inline, rather than calling out to the user-provided executor function.
|
||||
// Determine if the actor is a "default actor" in which case we'll build a
|
||||
// default actor executor ref inline, rather than calling out to the
|
||||
// user-provided executor function.
|
||||
if (isDefaultActorType(actorType, module, F->getResilienceExpansion())) {
|
||||
auto builtinName = ctx.getIdentifier(
|
||||
getBuiltinName(BuiltinValueKind::BuildDefaultActorExecutorRef));
|
||||
auto builtinDecl = cast<FuncDecl>(getBuiltinValueDecl(ctx, builtinName));
|
||||
auto subs = SubstitutionMap::get(builtinDecl->getGenericSignature(),
|
||||
{actorType},
|
||||
LookUpConformanceInModule());
|
||||
{actorType}, LookUpConformanceInModule());
|
||||
return B.createBuiltin(loc, builtinName, executorType, subs, {actor});
|
||||
}
|
||||
|
||||
// Otherwise, go through (Distributed)Actor.unownedExecutor.
|
||||
auto actorKind = actorType->isDistributedActor() ?
|
||||
KnownProtocolKind::DistributedActor :
|
||||
KnownProtocolKind::Actor;
|
||||
auto actorKind = actorType->isDistributedActor()
|
||||
? KnownProtocolKind::DistributedActor
|
||||
: KnownProtocolKind::Actor;
|
||||
auto actorProtocol = ctx.getProtocol(actorKind);
|
||||
auto req = getUnownedExecutorGetter(ctx, actorProtocol);
|
||||
assert(req && "Concurrency library broken");
|
||||
@@ -248,15 +229,14 @@ SILValue LowerHopToActor::emitGetExecutor(SILBuilderWithScope &B,
|
||||
}
|
||||
|
||||
auto actorConf = lookupConformance(actorType, actorProtocol);
|
||||
assert(actorConf &&
|
||||
"hop_to_executor with actor that doesn't conform to Actor or DistributedActor");
|
||||
assert(actorConf && "hop_to_executor with actor that doesn't conform to "
|
||||
"Actor or DistributedActor");
|
||||
|
||||
auto subs = SubstitutionMap::get(req->getGenericSignature(),
|
||||
{actorType}, {actorConf});
|
||||
auto subs = SubstitutionMap::get(req->getGenericSignature(), {actorType},
|
||||
{actorConf});
|
||||
auto fnType = F->getModule().Types.getConstantFunctionType(*F, fn);
|
||||
|
||||
auto witness =
|
||||
B.createWitnessMethod(loc, actorType, actorConf, fn,
|
||||
auto witness = B.createWitnessMethod(loc, actorType, actorConf, fn,
|
||||
SILType::getPrimitiveObjectType(fnType));
|
||||
auto witnessCall = B.createApply(loc, witness, subs, {actor});
|
||||
|
||||
@@ -266,27 +246,26 @@ SILValue LowerHopToActor::emitGetExecutor(SILBuilderWithScope &B,
|
||||
auto executorProps = executorDecl->getStoredProperties();
|
||||
assert(executorProps.size() == 1);
|
||||
return B.createStructExtract(loc, witnessCall, executorProps[0]);
|
||||
};
|
||||
|
||||
bool needEndBorrow = false;
|
||||
SILValue unmarkedExecutor;
|
||||
if (auto wrappedActor = actorType->getOptionalObjectType()) {
|
||||
assert(makeOptional);
|
||||
|
||||
if (B.hasOwnership() && actor->getOwnershipKind() == OwnershipKind::Owned) {
|
||||
actor = B.createBeginBorrow(loc, actor);
|
||||
needEndBorrow = true;
|
||||
}
|
||||
|
||||
static SILValue getExecutorForOptionalActor(SILBuilder &B, SILLocation loc,
|
||||
SILValue actor) {
|
||||
auto &ctx = B.getASTContext();
|
||||
auto executorType = SILType::getPrimitiveObjectType(ctx.TheExecutorType);
|
||||
auto optionalExecutorType = SILType::getOptionalType(executorType);
|
||||
|
||||
// Unwrap the optional and call 'unownedExecutor'.
|
||||
auto *someDecl = B.getASTContext().getOptionalSomeDecl();
|
||||
auto *curBB = B.getInsertionPoint()->getParent();
|
||||
auto *contBB = curBB->split(B.getInsertionPoint());
|
||||
auto *someDecl = ctx.getOptionalSomeDecl();
|
||||
auto *curBB = B.getInsertionBB();
|
||||
auto *contBB = B.getInsertionPoint() == curBB->end()
|
||||
? B.getFunction().createBasicBlockAfter(curBB)
|
||||
: curBB->split(B.getInsertionPoint());
|
||||
auto *someBB = B.getFunction().createBasicBlockAfter(curBB);
|
||||
auto *noneBB = B.getFunction().createBasicBlockAfter(someBB);
|
||||
|
||||
unmarkedExecutor = contBB->createPhiArgument(
|
||||
optionalExecutorType, actor->getOwnershipKind());
|
||||
// unmarked executor
|
||||
SILValue result = contBB->createPhiArgument(optionalExecutorType,
|
||||
actor->getOwnershipKind());
|
||||
|
||||
SmallVector<std::pair<EnumElementDecl *, SILBasicBlock *>, 1> caseBBs;
|
||||
caseBBs.push_back(std::make_pair(someDecl, someBB));
|
||||
@@ -304,7 +283,7 @@ SILValue LowerHopToActor::emitGetExecutor(SILBuilderWithScope &B,
|
||||
|
||||
// Call 'unownedExecutor' in the some block and wrap the result into
|
||||
// an optional.
|
||||
SILValue unwrappedExecutor = getExecutorFor(unwrappedActor);
|
||||
SILValue unwrappedExecutor = getExecutorForActor(B, loc, unwrappedActor);
|
||||
SILValue someValue =
|
||||
B.createOptionalSome(loc, unwrappedExecutor, optionalExecutorType);
|
||||
B.createBranch(loc, contBB, {someValue});
|
||||
@@ -314,15 +293,49 @@ SILValue LowerHopToActor::emitGetExecutor(SILBuilderWithScope &B,
|
||||
B.setInsertionPoint(noneBB);
|
||||
SILValue noneValue = B.createOptionalNone(loc, optionalExecutorType);
|
||||
B.createBranch(loc, contBB, {noneValue});
|
||||
B.setInsertionPoint(contBB->begin());
|
||||
if (contBB->begin() == contBB->end()) {
|
||||
B.setInsertionPoint(contBB);
|
||||
} else {
|
||||
unmarkedExecutor = getExecutorFor(actor);
|
||||
|
||||
// Inject the result into an optional if requested.
|
||||
if (makeOptional) {
|
||||
unmarkedExecutor = B.createOptionalSome(loc, unmarkedExecutor,
|
||||
SILType::getOptionalType(unmarkedExecutor->getType()));
|
||||
B.setInsertionPoint(contBB->begin());
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
SILValue LowerHopToActor::emitGetExecutor(SILBuilderWithScope &B,
|
||||
SILLocation loc, SILValue actor,
|
||||
bool makeOptional) {
|
||||
// This is okay because actor types have to be classes and so never
|
||||
// have multiple abstraction patterns.
|
||||
CanType actorType = actor->getType().getASTType();
|
||||
|
||||
// If the operand is already a BuiltinExecutorType, just wrap it
|
||||
// in an optional.
|
||||
if (makeOptional && actor->getType().is<BuiltinExecutorType>()) {
|
||||
return B.createOptionalSome(loc, actor,
|
||||
SILType::getOptionalType(actor->getType()));
|
||||
}
|
||||
|
||||
bool needEndBorrow = false;
|
||||
SILValue unmarkedExecutor;
|
||||
if (auto wrappedActor = actorType->getOptionalObjectType()) {
|
||||
assert(makeOptional);
|
||||
if (B.hasOwnership() &&
|
||||
actor->getOwnershipKind() != OwnershipKind::Guaranteed) {
|
||||
actor = B.createBeginBorrow(loc, actor);
|
||||
needEndBorrow = true;
|
||||
}
|
||||
|
||||
unmarkedExecutor = getExecutorForOptionalActor(B, loc, actor);
|
||||
} else {
|
||||
unmarkedExecutor = getExecutorForActor(B, loc, actor);
|
||||
}
|
||||
|
||||
// Inject the result into an optional if requested and if our executor is not
|
||||
// yet optional.
|
||||
if (makeOptional && !unmarkedExecutor->getType().getOptionalObjectType()) {
|
||||
unmarkedExecutor = B.createOptionalSome(
|
||||
loc, unmarkedExecutor,
|
||||
SILType::getOptionalType(unmarkedExecutor->getType()));
|
||||
}
|
||||
|
||||
// Mark the dependence of the resulting value on the actor value to
|
||||
@@ -342,7 +355,7 @@ class LowerHopToActorPass : public SILFunctionTransform {
|
||||
void run() override {
|
||||
auto fn = getFunction();
|
||||
auto domTree = getAnalysis<DominanceAnalysis>()->get(fn);
|
||||
LowerHopToActor pass(getFunction(), domTree);
|
||||
LowerHopToActor pass(domTree);
|
||||
if (pass.run())
|
||||
invalidateAnalysis(SILAnalysis::InvalidationKind::BranchesAndInstructions);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user