-
Notifications
You must be signed in to change notification settings - Fork 10.5k
[Distributed] retain ad-hoc witnesses so that they are not optimized away in SIL #42252
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
Conversation
resolves rdar://88211172 ([Distributed] SILGen must emit uses of decodeNextArgument so IRGen can get it cross module on |
5583241
to
51ccba4
Compare
51ccba4
to
e53355e
Compare
0ab1ad8
to
a640186
Compare
...untime/distributed_actor_cross_module_final_class_adhoc_requirement_not_optimized_away.swift
Show resolved
Hide resolved
@@ -2956,20 +2957,20 @@ bool SILDeserializer::hasSILFunction(StringRef Name, | |||
IdentifierID replacedFunctionID; | |||
GenericSignatureID genericSigID; | |||
unsigned rawLinkage, isTransparent, isSerialized, isThunk, | |||
isWithoutactuallyEscapingThunk, isGlobal, inlineStrategy, | |||
isWithoutActuallyEscapingThunk, isGlobal, inlineStrategy, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
was just a typo, might as well fix
e54a4d2
to
b626c57
Compare
@swift-ci please smoke test |
@swift-ci please build toolchain macOS |
lib/SIL/IR/SILFunctionBuilder.cpp
Outdated
systemTy->getAnyNominal()); | ||
assert(decoderTy); | ||
|
||
auto decodeFunc = C.getDecodeNextArgumentOnDistributedInvocationDecoder( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nickpick. This is a lot of code inline. Does it make sense to sink the code into a method on actor (ClassDecl?)?
So that we have something like:
if (!constant.isDistributedThunk())
return;
auto *actor = decl->getDeclContext()->getSelfNominalTypeDecl();
if (!actor)
return;
auto decodeFunc = actor->ifActorGetDecodeNextArgumentOnDistributedInvocationDecode();
if (!decodeFunc)
return;
auto decodeRef = SILDeclRef(decodeFunc);
...
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Cool, yeah happy to do that -- I always (over)-worry about putting things on ClassDecl but that'll make it much nicer.
I'll refactor a bit, thanks for calling it out 👍
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Long method name but nicer:
if (auto decodeFunc =
getAssociatedDistributedInvocationDecoderDecodeNextArgumentFunction(
decl)) {
auto decodeRef = SILDeclRef(decodeFunc);
auto *adHocWitness = getOrCreateDeclaration(decodeFunc, decodeRef);
F->setReferencedAdHocRequirementWitnessFunction(adHocWitness);
}
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
lgtm
public class FakeInvocationDecoder : DistributedTargetInvocationDecoder { | ||
|
||
@available(SwiftStdlib 5.7, *) | ||
public final class FakeInvocationDecoder: DistributedTargetInvocationDecoder { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
How hard would it be to add enum and struct variants for the decoder so all possibilities are tested? I think we could gyb this and some other tests too?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'll make a radar for it but right now I think that's a bit of a pain... I have no idea about gyb tbh
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
As soon as we are keeping track of that I am fine, I just don’t want it to be broken without us noticing…
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Right yeah 👍
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
rdar://91735574
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM! I agree with @aschwaighofer that we should extract code for decode into a request but that could be done separately. More important I think to add tests for decoder being class/final class/struct/enum.
Cool, will add the tests. Manually is fine tbh... |
b626c57
to
d3ce178
Compare
lib/SIL/IR/SILFunctionBuilder.cpp
Outdated
} else if (constant.isDistributedThunk()) { | ||
if (auto decodeFuncDecl = | ||
getAssociatedDistributedInvocationDecoderDecodeNextArgumentFunction( | ||
decl)) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nit: you can do that in the follow-up - if there is no decodeNextArgument
we should fail here since the record of the thunk function is going to be ill-formed without it and that would lead to a crash in IRGen.
@swift-ci please test |
@@ -9,7 +9,7 @@ distributed actor DA { | |||
} | |||
|
|||
extension DA { | |||
// CHECK-LABEL: sil hidden [thunk] [distributed] [ossa] @$s17distributed_thunk2DAC1fyyYaKFTE : $@convention(method) @async (@guaranteed DA) -> @error Error | |||
// CHECK-LABEL: sil hidden [thunk] [distributed] [ref_adhoc_requirement_witness "$s11Distributed29LocalTestingInvocationDecoderC18decodeNextArgumentxyKSeRzSERzlF"] [ossa] @$s17distributed_thunk2DAC1fyyYaKFTE : $@convention(method) @async (@guaranteed DA) -> @error Error { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think I can make a gyb to test that struct/class/final class/enum all have ref_adhoc_requirement_witness
referenced after you land these changes.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Awesome, thanks -- I'll fix the SIL test now and land it then
d3ce178
to
00f7b6e
Compare
@swift-ci please test |
00f7b6e
to
b239007
Compare
@swift-ci please test |
This only fails in one of the Linux builds now...
in optimized linux builds it seems Could I ask you to help out here @xedin ? 🙏 |
I should be able to take a look on Monday. Pretty sure that it’s not Linux specific, PR testing on macOS doesn’t run optimized tests if I remember correctly. |
cecbae2
to
dacd40d
Compare
@swift-ci please test Linux platform |
…minated as unused
The symbol is always retained now, so the workaround to use witness table for non-final classes is no longer necessary.
…`decodeNextArgument`
dacd40d
to
fc662bc
Compare
@swift-ci please test |
canBeCalledIndirectly(f->getRepresentation())), | ||
mayHaveIndirectCallers( | ||
f->getDynamicallyReplacedFunction() || | ||
f->getReferencedAdHocRequirementWitnessFunction() || |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Oh i see... makes sense
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thank you so much @xedin ! 🙇
@@ -101,6 +101,9 @@ class DeadFunctionAndGlobalElimination { | |||
if (F->isDynamicallyReplaceable()) | |||
return true; | |||
|
|||
if (F->getReferencedAdHocRequirementWitnessFunction()) | |||
return true; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ah okey so here too, I thought it was an either or but Makes sense!
@@ -325,6 +328,9 @@ class DeadFunctionAndGlobalElimination { | |||
|
|||
LLVM_DEBUG(llvm::dbgs() << " scan function " << F->getName() << '\n'); | |||
|
|||
if (auto *adHocWitness = F->getReferencedAdHocRequirementWitnessFunction()) | |||
ensureAlive(adHocWitness); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
<3
emitVirtualMethodValue(IGF, decoderTy, SILDeclRef(decodeFn), methodTy); | ||
auto methodPtr = FunctionPointer::forDirect( | ||
classifyFunctionPointerKind(decodeSIL), fnPtr, | ||
/*secondaryValue=*/nullptr, signature); | ||
|
||
return {decoder, decoderTy, witnessTable, methodPtr, methodTy}; | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yess! 🥳
Since some of them (e.g. the decodeNextArgument specifically) are only used directly form IRGen, optimization thinks they are not used and may remove them. Making it impossible to use final classes (or structs sometimes?) to develop decoder types for distributed actors.