-
Notifications
You must be signed in to change notification settings - Fork 10.5k
Ensure we are using mapped SIL type for switch_enum case and not the original lowered one #73385
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
@swift-ci please test |
Tagging @fibrechannelscsi |
// switch_enum arguments during rewriting | ||
|
||
import Foundation; import _Differentiation | ||
struct O: Differentiable {var a: B.G; var b: Array<SIMD2<Float>>; var c: B.M; var d: B.M} |
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.
Is there a smaller reduction that doesn’t use Differentiable?
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 do not have one sadly. Differentiation tends to create switch_enum
's with large payloads having tuples with closures inside. So, this exposes all kinds of corner cases in LoadableByAddress
.
The type in question here is:
$(@callee_guaranteed (@guaranteed C<Float>) -> @owned Array<Float>.DifferentiableView, @callee_guaranteed (@guaranteed C<Float>) -> @owned Array<Float>.DifferentiableView, @callee_guaranteed (@guaranteed C<Float>) -> @owned Array<Float>.DifferentiableView, @callee_guaranteed (@guaranteed C<SIMD2<Float>>) -> @owned Array<SIMD2<Float>>.DifferentiableView, @callee_guaranteed (@guaranteed C<Float>) -> @owned Array<Float>.DifferentiableView, @callee_guaranteed (@guaranteed C<Float>) -> @owned Array<Float>.DifferentiableView, @callee_guaranteed (@guaranteed B.M.TangentVector) -> @owned B.M.TangentVector, @callee_guaranteed (@guaranteed B.M.TangentVector) -> @owned B.M.TangentVector))
that is mapped to:
$(@callee_guaranteed (@guaranteed C<Float>) -> @owned Array<Float>.DifferentiableView, @callee_guaranteed (@guaranteed C<Float>) -> @owned Array<Float>.DifferentiableView, @callee_guaranteed (@guaranteed C<Float>) -> @owned Array<Float>.DifferentiableView, @callee_guaranteed (@guaranteed C<SIMD2<Float>>) -> @owned Array<SIMD2<Float>>.DifferentiableView, @callee_guaranteed (@guaranteed C<Float>) -> @owned Array<Float>.DifferentiableView, @callee_guaranteed (@guaranteed C<Float>) -> @owned Array<Float>.DifferentiableView, @callee_guaranteed (@in_guaranteed B.M.TangentVector) -> @out B.M.TangentVector, @callee_guaranteed (@in_guaranteed B.M.TangentVector) -> @out B.M.TangentVector)
And everything seems to depend on the order of previous transformations. I cannot remove any single line in the reproducer to still trigger an assertion, looks like we need to hit some thresholds as in:
bool isLargeLoadableType(SILType ty) {
if (ty.isAddress() || ty.isClassOrClassMetatype()) {
return false;
}
auto canType = ty.getASTType();
if (canType->hasTypeParameter()) {
assert(genEnv && "Expected a GenericEnv");
canType = genEnv->mapTypeIntoContext(canType)->getCanonicalType();
}
if (canType.getAnyGeneric() || isa<TupleType>(canType)) {
assert(ty.isObject() &&
"Expected only two categories: address and object");
assert(!canType->hasTypeParameter());
const TypeInfo &TI = irgenModule->getTypeInfoForLowered(canType);
auto &nativeSchemaOrigParam = TI.nativeParameterValueSchema(*irgenModule);
if (nativeSchemaOrigParam.size() > 15)
return true;
auto explosionSchema = TI.getSchema();
if (explosionSchema.size() > 15)
return true;
}
return false;
}
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.
The thresholds in that function are just a property of the stored property layout of the type and it should be possible to hit them by declaring, eg, a struct with a tuple containing 100 elements.
@swift-ci please test |
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 for looking into that!
lib/IRGen/LoadableByAddress.cpp
Outdated
@@ -4077,9 +4087,15 @@ class RewriteUser : SILInstructionVisitor<RewriteUser> { | |||
"caseBB has a payload argument"); | |||
|
|||
SILBuilder caseBuilder = assignment.getBuilder(caseBB->begin()); | |||
SILType eltType = |
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 would prefer to keep the type lowering code out of this phase.
It should be possible to read lowered (mapped) types out of the "input" SIL to this phase.
In this case, the result type is the switch_enum's successor basic block argument type.
This should work, I think:
diff --git a/lib/IRGen/LoadableByAddress.cpp b/lib/IRGen/LoadableByAddress.cpp
index d76c9fc3310..2502d55bc70 100644
--- a/lib/IRGen/LoadableByAddress.cpp
+++ b/lib/IRGen/LoadableByAddress.cpp
@@ -4078,7 +4078,8 @@ protected:
SILBuilder caseBuilder = assignment.getBuilder(caseBB->begin());
auto *caseAddr =
- caseBuilder.createUncheckedTakeEnumDataAddr(loc, opdAddr, caseDecl);
+ caseBuilder.createUncheckedTakeEnumDataAddr(loc, opdAddr, caseDecl,
+ caseArg->getType().getAddressType());
if (assignment.isLargeLoadableType(caseArg->getType())) {
assignment.mapValueToAddress(caseArg, caseAddr);
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, indeed here!
@swift-ci please test |
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.
The code change looks good but it still needs a better test case.
A reproducer could look something like:
Unfortunately, if you run |
After few hours of experiments, I think I ended with smaller reproducer. Note that it needs to be used with disabled SIL verifier (-Xllvm -verify-continue-on-failure) due to exactly same issue as fixed in the PR (results are lowered as import Builtin
import Swift
typealias X = Int
typealias LargeX = (() -> X, () -> X, () -> X, () -> X, () -> X, () -> X, () -> X, () -> X, () -> X)
enum enum1 {
case bb0(LargeX)
}
enum enum2 {
case bb0(LargeX)
}
enum large_enum {
case bb1((enum1, X))
case bb2((enum2, X))
}
sil @test1 : $@convention(thin) (@guaranteed large_enum) -> () {
bb0(%arg : $large_enum):
%loc = alloc_stack $(@callee_guaranteed () -> @owned X, @callee_guaranteed () -> @owned X,
@callee_guaranteed () -> @owned X, @callee_guaranteed () -> @owned X,
@callee_guaranteed () -> @owned X, @callee_guaranteed () -> @owned X,
@callee_guaranteed () -> @owned X, @callee_guaranteed () -> @owned X,
@callee_guaranteed () -> @owned X)
switch_enum %arg : $large_enum, case #large_enum.bb1!enumelt: bb1, case #large_enum.bb2!enumelt: bb2
bb1(%e1 : $(enum1, X)):
%e11 = tuple_extract %e1 : $(enum1, X), 0
switch_enum %e11 : $enum1, case #enum1.bb0!enumelt: bb11
bb11(%p1 : $((@callee_guaranteed () -> @owned X, @callee_guaranteed () -> @owned X,
@callee_guaranteed () -> @owned X, @callee_guaranteed () -> @owned X,
@callee_guaranteed () -> @owned X, @callee_guaranteed () -> @owned X,
@callee_guaranteed () -> @owned X, @callee_guaranteed () -> @owned X,
@callee_guaranteed () -> @owned X))):
br bb3(%p1 : $((@callee_guaranteed () -> @owned X, @callee_guaranteed () -> @owned X,
@callee_guaranteed () -> @owned X, @callee_guaranteed () -> @owned X,
@callee_guaranteed () -> @owned X, @callee_guaranteed () -> @owned X,
@callee_guaranteed () -> @owned X, @callee_guaranteed () -> @owned X,
@callee_guaranteed () -> @owned X)))
bb2(%e2 : $(enum2, X)):
%e22 = tuple_extract %e2 : $(enum2, X), 0
switch_enum %e22 : $enum2, case #enum2.bb0!enumelt: bb22
bb22(%p2 : $((@callee_guaranteed () -> @owned X, @callee_guaranteed () -> @owned X,
@callee_guaranteed () -> @owned X, @callee_guaranteed () -> @owned X,
@callee_guaranteed () -> @owned X, @callee_guaranteed () -> @owned X,
@callee_guaranteed () -> @owned X, @callee_guaranteed () -> @owned X,
@callee_guaranteed () -> @owned X))):
br bb3(%p2 : $((@callee_guaranteed () -> @owned X, @callee_guaranteed () -> @owned X,
@callee_guaranteed () -> @owned X, @callee_guaranteed () -> @owned X,
@callee_guaranteed () -> @owned X, @callee_guaranteed () -> @owned X,
@callee_guaranteed () -> @owned X, @callee_guaranteed () -> @owned X,
@callee_guaranteed () -> @owned X)))
bb3(%p3 : $((@callee_guaranteed () -> @owned X, @callee_guaranteed () -> @owned X,
@callee_guaranteed () -> @owned X, @callee_guaranteed () -> @owned X,
@callee_guaranteed () -> @owned X, @callee_guaranteed () -> @owned X,
@callee_guaranteed () -> @owned X, @callee_guaranteed () -> @owned X,
@callee_guaranteed () -> @owned X))):
store %p3 to %loc : $*(@callee_guaranteed () -> @owned X, @callee_guaranteed () -> @owned X,
@callee_guaranteed () -> @owned X, @callee_guaranteed () -> @owned X,
@callee_guaranteed () -> @owned X, @callee_guaranteed () -> @owned X,
@callee_guaranteed () -> @owned X, @callee_guaranteed () -> @owned X,
@callee_guaranteed () -> @owned X)
dealloc_stack %loc : $*(@callee_guaranteed () -> @owned X, @callee_guaranteed () -> @owned X,
@callee_guaranteed () -> @owned X, @callee_guaranteed () -> @owned X,
@callee_guaranteed () -> @owned X, @callee_guaranteed () -> @owned X,
@callee_guaranteed () -> @owned X, @callee_guaranteed () -> @owned X,
@callee_guaranteed () -> @owned X)
%t = tuple ()
return %t : $()
} Are we ok with this? @slavapestov @aschwaighofer |
original lowered one. Fixes #73018
@swift-ci please test |
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 am fine with the test case
…original lowered one (swiftlang#73385) Fixes swiftlang#73018 (cherry picked from commit e7e2ad1) (cherry picked from commit 422fe83)
…original lowered one (swiftlang#73385) Fixes swiftlang#73018 (cherry picked from commit e7e2ad1)
Fixes #73018