Skip to content

[Async CC] Test: Mark functions that call async functions async. #34402

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
12 changes: 9 additions & 3 deletions lib/IRGen/GenCall.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1747,6 +1747,8 @@ llvm::Value *irgen::getDynamicAsyncContextSize(IRGenFunction &IGF,
AsyncContextLayout layout,
CanSILFunctionType functionType,
llvm::Value *thickContext) {
// TODO: This calculation should be extracted out into a standalone function
// emitted on-demand per-module to improve codesize.
switch (functionType->getRepresentation()) {
case SILFunctionTypeRepresentation::Thick: {
// If the called function is thick, the size of the called function's
Expand Down Expand Up @@ -2061,11 +2063,15 @@ class AsyncCallEmission final : public CallEmission {
Size contextSize;
Address context;
llvm::Value *thickContext = nullptr;
Optional<AsyncContextLayout> asyncContextLayout;

AsyncContextLayout getAsyncContextLayout() {
return ::getAsyncContextLayout(IGF, getCallee().getOrigFunctionType(),
getCallee().getSubstFunctionType(),
getCallee().getSubstitutions());
if (!asyncContextLayout) {
asyncContextLayout.emplace(::getAsyncContextLayout(
IGF, getCallee().getOrigFunctionType(),
getCallee().getSubstFunctionType(), getCallee().getSubstitutions()));
}
return *asyncContextLayout;
}

void saveValue(ElementLayout layout, Explosion &explosion, bool isOutlined) {
Expand Down
30 changes: 15 additions & 15 deletions lib/IRGen/GenProto.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2688,21 +2688,21 @@ void irgen::emitPolymorphicParametersFromArray(IRGenFunction &IGF,

Size NecessaryBindings::getBufferSize(IRGenModule &IGM) const {
// We need one pointer for each archetype or witness table.
return IGM.getPointerSize() * Requirements.size();
return IGM.getPointerSize() * size();
}

void NecessaryBindings::restore(IRGenFunction &IGF, Address buffer,
MetadataState metadataState) const {
bindFromGenericRequirementsBuffer(IGF, Requirements.getArrayRef(), buffer,
bindFromGenericRequirementsBuffer(IGF, getRequirements(), buffer,
metadataState,
[&](CanType type) { return type;});
[&](CanType type) { return type; });
}

template <typename Transform>
static void save(const NecessaryBindings &bindings, IRGenFunction &IGF,
Address buffer, Transform transform) {
emitInitOfGenericRequirementsBuffer(
IGF, bindings.getRequirements().getArrayRef(), buffer,
IGF, bindings.getRequirements(), buffer,
[&](GenericRequirement requirement) -> llvm::Value * {
CanType type = requirement.TypeParameter;
if (auto protocol = requirement.Protocol) {
Expand Down Expand Up @@ -2770,14 +2770,13 @@ void NecessaryBindings::addTypeMetadata(CanType type) {
// Generic types are trickier, because they can require conformances.

// Otherwise, just record the need for this metadata.
Requirements.insert({type, nullptr});
addRequirement({type, nullptr});
}

/// Add all the abstract conditional conformances in the specialized
/// conformance to the \p requirements.
static void addAbstractConditionalRequirements(
SpecializedProtocolConformance *specializedConformance,
llvm::SetVector<GenericRequirement> &requirements) {
void NecessaryBindings::addAbstractConditionalRequirements(
SpecializedProtocolConformance *specializedConformance) {
auto subMap = specializedConformance->getSubstitutionMap();
auto condRequirements = specializedConformance->getConditionalRequirements();
for (auto req : condRequirements) {
Expand All @@ -2789,7 +2788,7 @@ static void addAbstractConditionalRequirements(
auto archetype = dyn_cast<ArchetypeType>(ty);
if (!archetype)
continue;
requirements.insert({ty, proto});
addRequirement({ty, proto});
}
// Recursively add conditional requirements.
for (auto &conf : subMap.getConformances()) {
Expand All @@ -2799,7 +2798,7 @@ static void addAbstractConditionalRequirements(
dyn_cast<SpecializedProtocolConformance>(conf.getConcrete());
if (!specializedConf)
continue;
addAbstractConditionalRequirements(specializedConf, requirements);
addAbstractConditionalRequirements(specializedConf);
}
}

Expand All @@ -2811,8 +2810,8 @@ void NecessaryBindings::addProtocolConformance(CanType type,
dyn_cast<SpecializedProtocolConformance>(concreteConformance);
// The partial apply forwarder does not have the context to reconstruct
// abstract conditional conformance requirements.
if (forPartialApply && specializedConf) {
addAbstractConditionalRequirements(specializedConf, Requirements);
if (forPartialApply() && specializedConf) {
addAbstractConditionalRequirements(specializedConf);
} else if (forAsyncFunction()) {
ProtocolDecl *protocol = conf.getRequirement();
GenericRequirement requirement;
Expand All @@ -2821,15 +2820,15 @@ void NecessaryBindings::addProtocolConformance(CanType type,
std::pair<GenericRequirement, ProtocolConformanceRef> pair{requirement,
conf};
Conformances.insert(pair);
Requirements.insert({type, concreteConformance->getProtocol()});
addRequirement({type, concreteConformance->getProtocol()});
}
return;
}
assert(isa<ArchetypeType>(type) || forAsyncFunction());

// TODO: pass something about the root conformance necessary to
// reconstruct this.
Requirements.insert({type, conf.getAbstract()});
addRequirement({type, conf.getAbstract()});
}

llvm::Value *irgen::emitWitnessTableRef(IRGenFunction &IGF,
Expand Down Expand Up @@ -3033,7 +3032,8 @@ NecessaryBindings NecessaryBindings::computeBindings(
bool forPartialApplyForwarder, bool considerParameterSources) {

NecessaryBindings bindings;
bindings.forPartialApply = forPartialApplyForwarder;
bindings.kind =
forPartialApplyForwarder ? Kind::PartialApply : Kind::AsyncFunction;

// Bail out early if we don't have polymorphic parameters.
if (!hasPolymorphicParameters(origType))
Expand Down
15 changes: 12 additions & 3 deletions lib/IRGen/IRGenSIL.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1331,7 +1331,11 @@ std::unique_ptr<COrObjCEntryPointArgumentEmission>
getCOrObjCEntryPointArgumentEmission(IRGenSILFunction &IGF,
SILBasicBlock &entry,
Explosion &allParamValues) {
if (IGF.CurSILFn->isAsync()) {
if (IGF.CurSILFn->isAsync() &&
!(/*FIXME: Remove this condition once Task.runDetached is
available. rdar://problem/70597390*/
IGF.CurSILFn->getLoweredFunctionType()->getRepresentation() ==
SILFunctionTypeRepresentation::CFunctionPointer)) {
llvm_unreachable("unsupported");
} else {
return std::make_unique<SyncCOrObjCEntryPointArgumentEmission>(
Expand Down Expand Up @@ -2686,7 +2690,7 @@ void IRGenSILFunction::visitFullApplySite(FullApplySite site) {
}
}

Explosion llArgs;
Explosion llArgs;
WitnessMetadata witnessMetadata;
auto emission = getCallEmissionForLoweredValue(
*this, origCalleeType, substCalleeType, calleeLV, selfValue,
Expand Down Expand Up @@ -3141,7 +3145,12 @@ static void emitReturnInst(IRGenSILFunction &IGF,
auto &retTI = cast<LoadableTypeInfo>(IGF.getTypeInfo(resultTy));
retTI.initialize(IGF, result, IGF.IndirectReturn, false);
IGF.Builder.CreateRetVoid();
} else if (IGF.isAsync()) {
} else if (IGF.isAsync() &&
!(/*FIXME: Remove this condition once Task.runDetached is
available. rdar://problem/70597390*/
IGF.CurSILFn->getLoweredFunctionType()
->getRepresentation() ==
SILFunctionTypeRepresentation::CFunctionPointer)) {
// If we're generating an async function, store the result into the buffer.
assert(!IGF.IndirectReturn.isValid() &&
"Formally direct results should stay direct results for async "
Expand Down
61 changes: 44 additions & 17 deletions lib/IRGen/NecessaryBindings.h
Original file line number Diff line number Diff line change
Expand Up @@ -25,31 +25,49 @@
#include "llvm/ADT/SetVector.h"
#include "swift/AST/Types.h"

#include "Explosion.h"

namespace swift {
class CanType;
enum class MetadataState : size_t;
class ProtocolDecl;
class ProtocolConformanceRef;
class SpecializedProtocolConformance;

namespace irgen {
namespace irgen {
class Address;
class Explosion;
class IRGenFunction;
class IRGenModule;
class Size;

/// NecessaryBindings - The set of metadata that must be saved in
/// order to perform some set of operations on a type.
class NecessaryBindings {
llvm::SetVector<GenericRequirement> Requirements;
enum class Kind {
/// Are the bindings to be computed for a partial apply forwarder.
/// In the case this is true we need to store/restore the conformance of a
/// specialized type with conditional conformance because the conditional
/// requirements are not available in the partial apply forwarder.
PartialApply,
AsyncFunction,
};
Kind kind;
llvm::SetVector<GenericRequirement> RequirementsSet;
llvm::SmallVector<GenericRequirement, 2> RequirementsVector;
llvm::DenseMap<GenericRequirement, ProtocolConformanceRef> Conformances;

/// Are the bindings to be computed for a partial apply forwarder.
/// In the case this is true we need to store/restore the conformance of a
/// specialized type with conditional conformance because the conditional
/// requirements are not available in the partial apply forwarder.
bool forPartialApply = false;
void addRequirement(GenericRequirement requirement) {
switch (kind) {
case Kind::PartialApply:
RequirementsSet.insert(requirement);
break;
case Kind::AsyncFunction:
RequirementsVector.push_back(requirement);
break;
}
}

void addAbstractConditionalRequirements(
SpecializedProtocolConformance *specializedConformance);

public:
NecessaryBindings() = default;
Expand All @@ -70,24 +88,27 @@ class NecessaryBindings {

/// Get the requirement from the bindings at index i.
const GenericRequirement &operator[](size_t i) const {
return Requirements[i];
switch (kind) {
case Kind::PartialApply:
return RequirementsSet[i];
case Kind::AsyncFunction:
return RequirementsVector[i];
}
}

ProtocolConformanceRef
getConformance(const GenericRequirement &requirement) const {
return Conformances.lookup(requirement);
}

size_t size() const {
return Requirements.size();
}
size_t size() const { return getRequirements().size(); }

/// Add whatever information is necessary to reconstruct a witness table
/// reference for the given type.
void addProtocolConformance(CanType type, ProtocolConformanceRef conf);

/// Is the work to do trivial?
bool empty() const { return Requirements.empty(); }
bool empty() const { return getRequirements().empty(); }

/// Returns the required size of the bindings.
/// Pointer alignment is sufficient.
Expand All @@ -101,11 +122,17 @@ class NecessaryBindings {
/// Restore the necessary bindings from the given buffer.
void restore(IRGenFunction &IGF, Address buffer, MetadataState state) const;

const llvm::SetVector<GenericRequirement> &getRequirements() const {
return Requirements;
const llvm::ArrayRef<GenericRequirement> getRequirements() const {
switch (kind) {
case Kind::PartialApply:
return RequirementsSet.getArrayRef();
case Kind::AsyncFunction:
return RequirementsVector;
}
}

bool forAsyncFunction() { return !forPartialApply; }
bool forPartialApply() { return kind == Kind::PartialApply; }
bool forAsyncFunction() { return kind == Kind::AsyncFunction; }

private:
static NecessaryBindings computeBindings(IRGenModule &IGM,
Expand Down
38 changes: 19 additions & 19 deletions test/IRGen/async/partial_apply.sil
Original file line number Diff line number Diff line change
Expand Up @@ -372,25 +372,25 @@ bb0(%0 : $*A2<A3>):
return %5 : $@async @callee_guaranteed () -> (@owned A1, @error Error)
}

sil @capture_class : $@async @convention(thin) (@guaranteed A3) -> ()

// CHECK-LABEL: define{{.*}} swiftcc i8* @partial_apply_stack_in_coroutine(i8* {{.*}} %0, %T13partial_apply2A3C* %1)
sil @partial_apply_stack_in_coroutine : $@yield_once (@owned A3) -> () {
entry(%0: $A3):
%f = function_ref @capture_class : $@async @convention(thin) (@guaranteed A3) -> ()
%p = partial_apply [callee_guaranteed] [on_stack] %f(%0) : $@async @convention(thin) (@guaranteed A3) -> ()
apply %p() : $@noescape @async @callee_guaranteed () -> ()
dealloc_stack %p : $@noescape @async @callee_guaranteed () -> ()
%1000 = integer_literal $Builtin.Int32, 1000
yield (), resume resume, unwind unwind

resume:
%ret = tuple ()
return %ret : $()

unwind:
unwind
}
//sil @capture_class : $@async @convention(thin) (@guaranteed A3) -> ()
//
//// CHECK LABEL: define{{.*}} swiftcc i8* @partial_apply_stack_in_coroutine(i8* {{.*}} %0, %T13partial_apply2A3C* %1)
//sil @partial_apply_stack_in_coroutine : $@async @yield_once (@owned A3) -> () {
//entry(%0: $A3):
// %f = function_ref @capture_class : $@async @convention(thin) (@guaranteed A3) -> ()
// %p = partial_apply [callee_guaranteed] [on_stack] %f(%0) : $@async @convention(thin) (@guaranteed A3) -> ()
// apply %p() : $@noescape @async @callee_guaranteed () -> ()
// dealloc_stack %p : $@noescape @async @callee_guaranteed () -> ()
// %1000 = integer_literal $Builtin.Int32, 1000
// yield (), resume resume, unwind unwind
//
//resume:
// %ret = tuple ()
// return %ret : $()
//
//unwind:
// unwind
//}
sil_vtable A3 {}


Expand Down
8 changes: 4 additions & 4 deletions test/IRGen/async/run-call-classinstance-int64-to-void.sil
Original file line number Diff line number Diff line change
Expand Up @@ -30,12 +30,12 @@ class S {
// CHECK-LL: define hidden swiftcc void @classinstanceSInt64ToVoid(%swift.context* {{%[0-9]*}}) {{#[0-9]*}} {
sil hidden @classinstanceSInt64ToVoid : $@async @convention(method) (Int64, @guaranteed S) -> () {
bb0(%int : $Int64, %instance : $S):
%take_s = function_ref @take_S : $@convention(thin) (@guaranteed S) -> ()
%result = apply %take_s(%instance) : $@convention(thin) (@guaranteed S) -> ()
%take_s = function_ref @take_S : $@async @convention(thin) (@guaranteed S) -> ()
%result = apply %take_s(%instance) : $@async @convention(thin) (@guaranteed S) -> ()
return %result : $()
}

sil hidden @take_S : $@convention(thin) (@guaranteed S) -> () {
sil hidden @take_S : $@async @convention(thin) (@guaranteed S) -> () {
bb0(%instance : $S):
%any = alloc_stack $Any
strong_retain %instance : $S
Expand Down Expand Up @@ -83,7 +83,7 @@ sil_vtable S {
#S.deinit!deallocator: @S_deallocating_deinit
}

sil @main : $@convention(c) (Int32, UnsafeMutablePointer<Optional<UnsafeMutablePointer<Int8>>>) -> Int32 {
sil @main : $@async @convention(c) (Int32, UnsafeMutablePointer<Optional<UnsafeMutablePointer<Int8>>>) -> Int32 {
bb0(%0 : $Int32, %1 : $UnsafeMutablePointer<Optional<UnsafeMutablePointer<Int8>>>):

%s_type = metatype $@thick S.Type
Expand Down
8 changes: 4 additions & 4 deletions test/IRGen/async/run-call-classinstance-void-to-void.sil
Original file line number Diff line number Diff line change
Expand Up @@ -30,12 +30,12 @@ class S {
// CHECK-LL: define hidden swiftcc void @classinstanceSVoidToVoid(%swift.context* {{%[0-9]*}}) {{#[0-9]*}} {
sil hidden @classinstanceSVoidToVoid : $@async @convention(method) (@guaranteed S) -> () {
bb0(%instance : $S):
%take_s = function_ref @take_S : $@convention(thin) (@guaranteed S) -> ()
%result = apply %take_s(%instance) : $@convention(thin) (@guaranteed S) -> ()
%take_s = function_ref @take_S : $@async @convention(thin) (@guaranteed S) -> ()
%result = apply %take_s(%instance) : $@async @convention(thin) (@guaranteed S) -> ()
return %result : $()
}

sil hidden @take_S : $@convention(thin) (@guaranteed S) -> () {
sil hidden @take_S : $@async @convention(thin) (@guaranteed S) -> () {
bb0(%instance : $S):
%any = alloc_stack $Any
strong_retain %instance : $S
Expand Down Expand Up @@ -83,7 +83,7 @@ sil_vtable S {
#S.deinit!deallocator: @S_deallocating_deinit
}

sil @main : $@convention(c) (Int32, UnsafeMutablePointer<Optional<UnsafeMutablePointer<Int8>>>) -> Int32 {
sil @main : $@async @convention(c) (Int32, UnsafeMutablePointer<Optional<UnsafeMutablePointer<Int8>>>) -> Int32 {
bb0(%0 : $Int32, %1 : $UnsafeMutablePointer<Optional<UnsafeMutablePointer<Int8>>>):

%s_type = metatype $@thick S.Type
Expand Down
8 changes: 4 additions & 4 deletions test/IRGen/async/run-call-existential-to-void.sil
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ bb0(%existential : $*P):
return %result : $()
}

sil hidden @call : $@convention(thin) () -> () {
sil hidden @call : $@async @convention(thin) () -> () {
bb0:
%S_type = metatype $@thin S.Type
%int_literal = integer_literal $Builtin.Int64, 7384783
Expand All @@ -66,10 +66,10 @@ bb0:
return %result : $()
}

sil @main : $@convention(c) (Int32, UnsafeMutablePointer<Optional<UnsafeMutablePointer<Int8>>>) -> Int32 {
sil @main : $@async @convention(c) (Int32, UnsafeMutablePointer<Optional<UnsafeMutablePointer<Int8>>>) -> Int32 {
bb0(%0 : $Int32, %1 : $UnsafeMutablePointer<Optional<UnsafeMutablePointer<Int8>>>):
%call = function_ref @call : $@convention(thin) () -> () // CHECK: 7384783
%result = apply %call() : $@convention(thin) () -> ()
%call = function_ref @call : $@async @convention(thin) () -> () // CHECK: 7384783
%result = apply %call() : $@async @convention(thin) () -> ()

%2 = integer_literal $Builtin.Int32, 0
%3 = struct $Int32 (%2 : $Builtin.Int32)
Expand Down
Loading