Skip to content

[CoroutineAccessors] Use yield_once_2 on Darwin and Linux. #80701

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
Apr 10, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions include/swift/AST/SILOptions.h
Original file line number Diff line number Diff line change
Expand Up @@ -338,6 +338,10 @@ class SILOptions {
// Whether to allow merging traps and cond_fails.
bool MergeableTraps = false;

/// Whether the @yield_once_2 convention is used by accessors added with the
/// CoroutineAccessors feature (i.e. read2/modify2).
bool CoroutineAccessorsUseYieldOnce2 = false;

SILOptions() {}

/// Return a hash code of any components from these options that should
Expand Down
6 changes: 6 additions & 0 deletions include/swift/Option/FrontendOptions.td
Original file line number Diff line number Diff line change
Expand Up @@ -1175,6 +1175,12 @@ def enable_arm64_corocc : Flag<["-"], "enable-arm64-corocc">,
def disable_arm64_corocc : Flag<["-"], "disable-arm64-corocc">,
HelpText<"Don't use swiftcorocc for yield_once_2 routines on arm64 variants.">;

def enable_callee_allocated_coro_abi : Flag<["-"], "enable-callee-allocated-coro-abi">,
HelpText<"Override per-platform settings and use yield_once_2.">;

def disable_callee_allocated_coro_abi : Flag<["-"], "disable-callee-allocated-coro-abi">,
HelpText<"Override per-platform settings and don't use yield_once_2.">;

def enable_cond_fail_message_annotation : Flag<["-"], "enable-cond-fail-message-annotation">,
HelpText<"Enable cond_fail message annotation. Will serialize a .o.yaml file per .o file.">;

Expand Down
14 changes: 14 additions & 0 deletions lib/DriverTool/sil_opt_main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -597,6 +597,16 @@ struct SILOptOptions {
"enable-address-dependencies",
llvm::cl::desc("Enable enforcement of lifetime dependencies on addressable values."));

llvm::cl::opt<bool> EnableCalleeAllocatedCoroAbi = llvm::cl::opt<bool>(
"enable-callee-allocated-coro-abi",
llvm::cl::desc("Override per-platform settings and use yield_once_2."),
llvm::cl::init(false));
llvm::cl::opt<bool> DisableCalleeAllocatedCoroAbi = llvm::cl::opt<bool>(
"disable-callee-allocated-coro-abi",
llvm::cl::desc(
"Override per-platform settings and don't use yield_once_2."),
llvm::cl::init(false));

llvm::cl::opt<bool> MergeableTraps = llvm::cl::opt<bool>(
"mergeable-traps",
llvm::cl::desc("Enable cond_fail merging."));
Expand Down Expand Up @@ -918,6 +928,10 @@ int sil_opt_main(ArrayRef<const char *> argv, void *MainAddr) {
options.EnablePackMetadataStackPromotion;

SILOpts.EnableAddressDependencies = options.EnableAddressDependencies;
if (options.EnableCalleeAllocatedCoroAbi)
SILOpts.CoroutineAccessorsUseYieldOnce2 = true;
if (options.DisableCalleeAllocatedCoroAbi)
SILOpts.CoroutineAccessorsUseYieldOnce2 = false;
SILOpts.MergeableTraps = options.MergeableTraps;

if (options.OptModeFlag == OptimizationMode::NotSet) {
Expand Down
10 changes: 10 additions & 0 deletions lib/Frontend/CompilerInvocation.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3130,6 +3130,16 @@ static bool ParseSILArgs(SILOptions &Opts, ArgList &Args,
Opts.EnableAddressDependencies = Args.hasFlag(
OPT_enable_address_dependencies, OPT_disable_address_dependencies,
Opts.EnableAddressDependencies);

if (LangOpts.Target.isOSDarwin() || LangOpts.Target.isOSLinux()) {
// On Darwin and Linux, use yield_once_2 by default.
Opts.CoroutineAccessorsUseYieldOnce2 = true;
}
Opts.CoroutineAccessorsUseYieldOnce2 =
Args.hasFlag(OPT_enable_callee_allocated_coro_abi,
OPT_disable_callee_allocated_coro_abi,
Opts.CoroutineAccessorsUseYieldOnce2);

Opts.MergeableTraps = Args.hasArg(OPT_mergeable_traps);

return false;
Expand Down
5 changes: 4 additions & 1 deletion lib/SIL/IR/SILDeclRef.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1855,5 +1855,8 @@ bool SILDeclRef::isCalleeAllocatedCoroutine() const {
if (!accessor)
return false;

return requiresFeatureCoroutineAccessors(accessor->getAccessorKind());
if (!requiresFeatureCoroutineAccessors(accessor->getAccessorKind()))
return false;

return getASTContext().SILOpts.CoroutineAccessorsUseYieldOnce2;
}
4 changes: 3 additions & 1 deletion lib/SIL/IR/SILFunctionType.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2481,8 +2481,10 @@ static CanSILFunctionType getSILFunctionType(

if (auto accessor = getAsCoroutineAccessor(constant)) {
auto origAccessor = cast<AccessorDecl>(origConstant->getDecl());
auto &ctx = origAccessor->getASTContext();
coroutineKind =
requiresFeatureCoroutineAccessors(accessor->getAccessorKind())
(requiresFeatureCoroutineAccessors(accessor->getAccessorKind()) &&
ctx.SILOpts.CoroutineAccessorsUseYieldOnce2)
? SILCoroutineKind::YieldOnce2
: SILCoroutineKind::YieldOnce;

Expand Down
55 changes: 34 additions & 21 deletions lib/SILGen/SILGenApply.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4999,14 +4999,16 @@ class CallEmission {
FormalEvaluationScope initialWritebackScope;
std::optional<ActorIsolation> implicitActorHopTarget;
bool implicitlyThrows;
bool canUnwind;

public:
/// Create an emission for a call of the given callee.
CallEmission(SILGenFunction &SGF, Callee &&callee,
FormalEvaluationScope &&writebackScope)
: SGF(SGF), callee(std::move(callee)),
initialWritebackScope(std::move(writebackScope)),
implicitActorHopTarget(std::nullopt), implicitlyThrows(false) {}
implicitActorHopTarget(std::nullopt), implicitlyThrows(false),
canUnwind(false) {}

/// A factory method for decomposing the apply expr \p e into a call
/// emission.
Expand Down Expand Up @@ -5057,6 +5059,8 @@ class CallEmission {
/// function can throw or not.
void setImplicitlyThrows(bool flag) { implicitlyThrows = flag; }

void setCanUnwind(bool flag) { canUnwind = flag; }

CleanupHandle applyCoroutine(SmallVectorImpl<ManagedValue> &yields);

RValue apply(SGFContext C = SGFContext()) {
Expand Down Expand Up @@ -5114,9 +5118,11 @@ namespace {
/// Cleanup to end a coroutine application.
class EndCoroutineApply : public Cleanup {
SILValue ApplyToken;
bool CanUnwind;
std::vector<BeginBorrowInst *> BorrowedMoveOnlyValues;
public:
EndCoroutineApply(SILValue applyToken) : ApplyToken(applyToken) {}
EndCoroutineApply(SILValue applyToken, bool CanUnwind)
: ApplyToken(applyToken), CanUnwind(CanUnwind) {}

void setBorrowedMoveOnlyValues(ArrayRef<BeginBorrowInst *> values) {
BorrowedMoveOnlyValues.insert(BorrowedMoveOnlyValues.end(),
Expand All @@ -5129,14 +5135,7 @@ class EndCoroutineApply : public Cleanup {
SGF.B.createEndBorrow(l, *i);
SGF.B.createDestroyValue(l, (*i)->getOperand());
}
auto *beginApply =
cast<BeginApplyInst>(ApplyToken->getDefiningInstruction());
auto isCalleeAllocated = beginApply->isCalleeAllocated();
auto unwindOnCallerError =
!isCalleeAllocated ||
SGF.SGM.getASTContext().LangOpts.hasFeature(
Feature::CoroutineAccessorsUnwindOnCallerError);
if (forUnwind && unwindOnCallerError) {
if (forUnwind && CanUnwind) {
SGF.B.createAbortApply(l, ApplyToken);
} else {
SGF.B.createEndApply(l, ApplyToken,
Expand Down Expand Up @@ -5179,18 +5178,15 @@ CallEmission::applyCoroutine(SmallVectorImpl<ManagedValue> &yields) {

auto fnValue = callee.getFnValue(SGF, borrowedSelf);

return SGF.emitBeginApply(uncurriedLoc.value(), fnValue,
return SGF.emitBeginApply(uncurriedLoc.value(), fnValue, canUnwind,
callee.getSubstitutions(), uncurriedArgs,
calleeTypeInfo.substFnType, options, yields);
}

CleanupHandle
SILGenFunction::emitBeginApply(SILLocation loc, ManagedValue fn,
SubstitutionMap subs,
ArrayRef<ManagedValue> args,
CanSILFunctionType substFnType,
ApplyOptions options,
SmallVectorImpl<ManagedValue> &yields) {
CleanupHandle SILGenFunction::emitBeginApply(
SILLocation loc, ManagedValue fn, bool canUnwind, SubstitutionMap subs,
ArrayRef<ManagedValue> args, CanSILFunctionType substFnType,
ApplyOptions options, SmallVectorImpl<ManagedValue> &yields) {
// Emit the call.
SmallVector<SILValue, 4> rawResults;
emitRawApply(*this, loc, fn, subs, args, substFnType, options,
Expand All @@ -5206,7 +5202,7 @@ SILGenFunction::emitBeginApply(SILLocation loc, ManagedValue fn,

// Push a cleanup to end the application.
// TODO: destroy all the arguments at exactly this point?
Cleanups.pushCleanup<EndCoroutineApply>(token);
Cleanups.pushCleanup<EndCoroutineApply>(token, canUnwind);
auto endApplyHandle = getTopCleanup();

// Manage all the yielded values.
Expand Down Expand Up @@ -6183,7 +6179,7 @@ SILValue SILGenFunction::emitApplyWithRethrow(SILLocation loc, SILValue fn,
std::tuple<MultipleValueInstructionResult *, CleanupHandle, SILValue,
CleanupHandle>
SILGenFunction::emitBeginApplyWithRethrow(SILLocation loc, SILValue fn,
SILType substFnType,
SILType substFnType, bool canUnwind,
SubstitutionMap subs,
ArrayRef<SILValue> args,
SmallVectorImpl<SILValue> &yields) {
Expand All @@ -6208,7 +6204,7 @@ SILGenFunction::emitBeginApplyWithRethrow(SILLocation loc, SILValue fn,
deallocCleanup = enterDeallocStackCleanup(allocation);
}

Cleanups.pushCleanup<EndCoroutineApply>(token);
Cleanups.pushCleanup<EndCoroutineApply>(token, canUnwind);
auto abortCleanup = Cleanups.getTopCleanup();

return {token, abortCleanup, allocation, deallocCleanup};
Expand Down Expand Up @@ -7561,6 +7557,21 @@ ManagedValue SILGenFunction::emitAddressorAccessor(
return ManagedValue::forLValue(address);
}

bool SILGenFunction::canUnwindAccessorDeclRef(SILDeclRef accessorRef) {
auto *accessor =
dyn_cast_or_null<AccessorDecl>(accessorRef.getAbstractFunctionDecl());
ASSERT(accessor && "only accessors can unwind");
auto kind = accessor->getAccessorKind();
ASSERT(isYieldingAccessor(kind) && "only yielding accessors can unwind");
if (!requiresFeatureCoroutineAccessors(kind)) {
// _read and _modify can unwind
return true;
}
// Coroutine accessors can only unwind with the experimental feature.
return getASTContext().LangOpts.hasFeature(
Feature::CoroutineAccessorsUnwindOnCallerError);
}

CleanupHandle
SILGenFunction::emitCoroutineAccessor(SILLocation loc, SILDeclRef accessor,
SubstitutionMap substitutions,
Expand Down Expand Up @@ -7596,6 +7607,8 @@ SILGenFunction::emitCoroutineAccessor(SILLocation loc, SILDeclRef accessor,

emission.addCallSite(loc, std::move(subscriptIndices));

emission.setCanUnwind(canUnwindAccessorDeclRef(accessor));

auto endApplyHandle = emission.applyCoroutine(yields);

return endApplyHandle;
Expand Down
9 changes: 6 additions & 3 deletions lib/SILGen/SILGenFunction.h
Original file line number Diff line number Diff line change
Expand Up @@ -2034,6 +2034,7 @@ class LLVM_LIBRARY_VISIBILITY SILGenFunction
PreparedArguments &&optionalSubscripts,
SILType addressType, bool isOnSelfParameter);

bool canUnwindAccessorDeclRef(SILDeclRef accessorRef);
CleanupHandle emitCoroutineAccessor(SILLocation loc, SILDeclRef accessor,
SubstitutionMap substitutions,
ArgumentSource &&optionalSelfValue,
Expand Down Expand Up @@ -2301,8 +2302,9 @@ class LLVM_LIBRARY_VISIBILITY SILGenFunction
PreparedArguments &&args, Type overriddenSelfType,
SGFContext ctx);

CleanupHandle emitBeginApply(SILLocation loc, ManagedValue fn,
SubstitutionMap subs, ArrayRef<ManagedValue> args,
CleanupHandle emitBeginApply(SILLocation loc, ManagedValue fn, bool canUnwind,
SubstitutionMap subs,
ArrayRef<ManagedValue> args,
CanSILFunctionType substFnType,
ApplyOptions options,
SmallVectorImpl<ManagedValue> &yields);
Expand All @@ -2315,7 +2317,8 @@ class LLVM_LIBRARY_VISIBILITY SILGenFunction
std::tuple<MultipleValueInstructionResult *, CleanupHandle, SILValue,
CleanupHandle>
emitBeginApplyWithRethrow(SILLocation loc, SILValue fn, SILType substFnType,
SubstitutionMap subs, ArrayRef<SILValue> args,
bool canUnwind, SubstitutionMap subs,
ArrayRef<SILValue> args,
SmallVectorImpl<SILValue> &yields);
void emitEndApplyWithRethrow(SILLocation loc,
MultipleValueInstructionResult *token,
Expand Down
6 changes: 3 additions & 3 deletions lib/SILGen/SILGenLValue.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2518,9 +2518,9 @@ namespace {

// Perform the begin_apply.
SmallVector<ManagedValue, 1> yields;
auto cleanup =
SGF.emitBeginApply(loc, projectFnRef, subs, { base, keyPathValue },
substFnType, ApplyOptions(), yields);
auto cleanup = SGF.emitBeginApply(loc, projectFnRef, /*canUnwind=*/true,
subs, {base, keyPathValue}, substFnType,
ApplyOptions(), yields);

// Push an operation to do the end_apply.
pushEndApplyWriteback(SGF, loc, cleanup, getTypeData());
Expand Down
7 changes: 4 additions & 3 deletions lib/SILGen/SILGenPoly.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -7046,8 +7046,8 @@ SILGenFunction::emitVTableThunk(SILDeclRef base,
case SILCoroutineKind::YieldOnce2: {
SmallVector<SILValue, 4> derivedYields;
auto tokenAndCleanups = emitBeginApplyWithRethrow(
loc, derivedRef, SILType::getPrimitiveObjectType(derivedFTy), subs,
args, derivedYields);
loc, derivedRef, SILType::getPrimitiveObjectType(derivedFTy),
canUnwindAccessorDeclRef(base), subs, args, derivedYields);
auto token = std::get<0>(tokenAndCleanups);
auto abortCleanup = std::get<1>(tokenAndCleanups);
auto allocation = std::get<2>(tokenAndCleanups);
Expand Down Expand Up @@ -7441,7 +7441,8 @@ void SILGenFunction::emitProtocolWitness(
case SILCoroutineKind::YieldOnce2: {
SmallVector<SILValue, 4> witnessYields;
auto tokenAndCleanups = emitBeginApplyWithRethrow(
loc, witnessFnRef, witnessSILTy, witnessSubs, args, witnessYields);
loc, witnessFnRef, witnessSILTy, canUnwindAccessorDeclRef(requirement),
witnessSubs, args, witnessYields);
auto token = std::get<0>(tokenAndCleanups);
auto abortCleanup = std::get<1>(tokenAndCleanups);
auto allocation = std::get<2>(tokenAndCleanups);
Expand Down
1 change: 1 addition & 0 deletions test/IRGen/coroutine_accessors.swift
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
// RUN: %target-swift-emit-irgen \
// RUN: %s \
// RUN: -enable-callee-allocated-coro-abi \
// RUN: -enable-experimental-feature CoroutineAccessors \
// RUN: | %IRGenFileCheck %s

Expand Down
1 change: 1 addition & 0 deletions test/IRGen/coroutine_accessors_backdeploy_async_56.swift
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
// RUN: %target-swift-emit-irgen \
// RUN: %s \
// RUN: -enable-callee-allocated-coro-abi \
// RUN: -module-name backdep \
// RUN: -target %target-swift-5.6-abi-triple \
// RUN: -Onone \
Expand Down
1 change: 1 addition & 0 deletions test/IRGen/coroutine_accessors_backdeploy_async_57.swift
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
// RUN: %target-swift-emit-irgen \
// RUN: %s \
// RUN: -enable-callee-allocated-coro-abi \
// RUN: -module-name backdep \
// RUN: -target %target-swift-5.7-abi-triple \
// RUN: -Onone \
Expand Down
1 change: 1 addition & 0 deletions test/IRGen/coroutine_accessors_popless.swift
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
// RUN: %target-swift-emit-irgen \
// RUN: %s \
// RUN: -Onone \
// RUN: -enable-callee-allocated-coro-abi \
// RUN: -enable-experimental-feature CoroutineAccessors \
// RUN: -enable-arm64-corocc \
// RUN: -enable-x86_64-corocc \
Expand Down
1 change: 1 addition & 0 deletions test/IRGen/default_override.sil
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
// RUN: %target-swift-frontend \
// RUN: %s \
// RUN: -enable-callee-allocated-coro-abi \
// RUN: -module-name Library \
// RUN: -emit-ir \
// RUN: -enable-experimental-feature CoroutineAccessors \
Expand Down
2 changes: 0 additions & 2 deletions test/IRGen/run-coroutine_accessors.swift
Original file line number Diff line number Diff line change
Expand Up @@ -94,8 +94,6 @@
// UNSUPPORTED: wasm
// UNSUPPORTED: OS=wasi
// UNSUPPORTED: CPU=wasm32
// TODO: CoroutineAccessors: Enable on Windows.
// UNSUPPORTED: OS=windows-msvc

// REQUIRES: swift_feature_CoroutineAccessors

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
// RUN: %target-swift-frontend \
// RUN: %t/Library.swift \
// RUN: %t/LibImpl.underscored.swift \
// RUN: -enable-callee-allocated-coro-abi \
// RUN: -emit-module \
// RUN: -module-name Library \
// RUN: -parse-as-library \
Expand All @@ -13,6 +14,7 @@

// RUN: %target-swift-frontend \
// RUN: %t/Executable.swift \
// RUN: -enable-callee-allocated-coro-abi \
// RUN: -c \
// RUN: -parse-as-library \
// RUN: -module-name Executable \
Expand All @@ -22,6 +24,7 @@
// RUN: %target-build-swift-dylib(%t/%target-library-name(Library)) \
// RUN: %t/Library.swift \
// RUN: %t/LibImpl.nonunderscored.swift \
// RUN: -Xfrontend -enable-callee-allocated-coro-abi \
// RUN: -emit-module \
// RUN: -enable-library-evolution \
// RUN: -enable-experimental-feature CoroutineAccessors \
Expand Down
Loading