-
Notifications
You must be signed in to change notification settings - Fork 10.5k
Fix unchecked_take_enum_data_addr has side effects. #31157
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
Fix unchecked_take_enum_data_addr has side effects. #31157
Conversation
@zoecarver This needs a test case showing the crash. |
096a45e
to
5503723
Compare
@gottesmm this doesn't crash without the mandatory combine patch (because without ownership the verifier doesn't care that it's not initialized) but, you can see that it's removed (incorrectly) in the non-OSSA SILCombine test I added. |
I can also get it to crash with mandatory inlining if that's better. |
@zoecarver I'd be down with mandatory inlining. |
Sorry, I didn't look closely enough. I can't get mandatory inlining to crash. I think SILCombine is the best we've got. |
5503723
to
f6e118d
Compare
Don't always return true (is trivially dead) for unchecked_take_enum_data_addr. It destroys the address operand so, it's not *always* trivially dead.
Actually, I forgot! We support OSSA in SILCombine now :D The test now crashes (on master). |
@gottesmm friendly ping :) |
@@ -132,11 +132,6 @@ bool swift::isInstructionTriviallyDead(SILInstruction *inst) { | |||
if (isa<DebugValueInst>(inst) || isa<DebugValueAddrInst>(inst)) | |||
return false; | |||
|
|||
// These invalidate enums so "write" memory, but that is not an essential | |||
// operation so we can remove these if they are trivially dead. | |||
if (isa<UncheckedTakeEnumDataAddrInst>(inst)) |
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 add a special case here for Optional. UncheckedTakeEnumDataAddrInst is only writable for certain multi-payload cases where to extract the payload one needs to "open" the enum. This is not true for optional. Also, even so, I don't understand what the crasher is here. Whats the crash specifically, can you post the 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.
Here's the error:
SIL memory lifetime failure in @unchecked_take_enum_data_addr_not_dead: memory is initialized at function return but shouldn't
memory location: %0 = argument of bb0 : $*FakeOptional<B>
at instruction: return %1 : $() // id: %2
in function:
// unchecked_take_enum_data_addr_not_dead
sil [ossa] @unchecked_take_enum_data_addr_not_dead : $@convention(thin) (@in FakeOptional<B>) -> () {
bb0(%0 : $*FakeOptional<B>):
%1 = tuple () // user: %2
return %1 : $() // id: %2
} // end sil function 'unchecked_take_enum_data_addr_not_dead'
Because unchecked_take_enum_data_addr
takes (or destroys) the operand. When the instruction is removed, the operand is still initialized.
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 add a special case for Optional
.
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.
Actually, I can't add a special case for optional. It's the same problem (not sure why I thought it wouldn't be at first...) but, it's still an @in
address. It needs to be destroyed somehow.
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.
We could promote it to a destroy_address
if the uses are empty. But, that's probably better done in sil-combine (or maybe DCE).
@zoecarver now that I am looking at this, I don't think this is the correct fix. I think more likely there was some sort of destroy_addr here or something like that. This instruction's write semantics really shouldn't be visible to the user in this way. I would go back and see what used to be at the end of the unchecked_take_enum_data. |
@gottesmm I'm not sure I completely understand what you mean. Unless I completely misunderstand, Here's the original king fisher reproducer. There's no
After
|
@zoecarver this is a question around the lifetime verifier and what we are verifying. The memory lifetime verifier is not the end all be all definition of correctness. It is just enforcing what it knows and is incomplete. I would argue that the right thing here is to look at why we don't have a destroy_addr. I think that is the right thing to ask here. Later on after ossa, we will just eliminate the destroy_addr. But in OSSA, we will want it. |
@gottesmm OK, I see what you mean. I'll look into it. Probably a SILGen change. |
Here's the issue: https://swift.godbolt.org/z/9n3PwS Essentially when we have a protocol and a trivial type in an enum and we try to switch over them, we destroy the protocol but not the trivial type. I think we should be destroying the enum value and not the enum "data". WDYT? Side note: there are some missed optimizations with copy_addr in the optimized version of that example. I'll try to fix those after I get this fixed. |
Closing in favor of #31779. |
Don't always return true (is trivially dead) for unchecked_take_enum_data_addr. It destroys the address operand so, it's not always trivially dead.
Fixes issue described in #31077.