Uh oh!
There was an error while loading. Please reload this page.
Move alignment checks to codegen - #117473
Conversation
This comment has been minimized.
This comment has been minimized.
c0b5969 to
487ffa6Compare
This comment has been minimized.
This comment has been minimized.
487ffa6 to
f976ac6Compare
This comment has been minimized.
This comment has been minimized.
Uh oh!
There was an error while loading. Please reload this page.
f976ac6 to
b8cc419Compare
This comment has been minimized.
This comment has been minimized.
b8cc419 to
f6feccfCompare
This comment has been minimized.
This comment has been minimized.
f6feccf to
72aaa7dCompare
This comment has been minimized.
This comment has been minimized.
72aaa7d to
df639edCompare
This comment was marked as outdated.
This comment was marked as outdated.
df639ed to
9fc6ddeCompare
This comment has been minimized.
This comment has been minimized.
9fc6dde to
4c33915Compare
This comment has been minimized.
This comment has been minimized.
4c33915 to
165048aComparesaethlin
commented
Nov 12, 2023
@bors try @rust-timer queue |
This comment has been minimized.
This comment has been minimized.
bors
commented
Nov 12, 2023
…=<try> Move alignment checks to codegen Implementing UB checks entirely in a MIR transform is quite limiting, we don't know for sure what all our types are so we need to make a lot of sacrifices. For example in here we used to emit MIR to compute the alignment mask at runtime, because the pointee type could be generic. Implementing the checks in codegen frees us from that requirement, because we get to deal with monomorphized types. But I don't think we can move these checks entirely into codegen, because inserting the check needs to insert a new terminator into a basic block, which splits the previous basic block into two. We can't add control flow like this in codegen, but we can in MIR. So now the MIR transform just inserts a `TerminatorKind::UbCheck` which is effectively a `Goto` that also reads an `Operand` (because it either goes to the target block or terminates), and codegen expands that new terminator into the actual check. --- Also I'm writing this with the expectation that I implement the niche checks in the same manner, because they have the same problem with polymorphic MIR, possibly worse. r? `@ghost`
bors
commented
Nov 12, 2023
☀️ Try build successful - checks-actions |
This comment has been minimized.
This comment has been minimized.
rust-timer
commented
Nov 12, 2023
Finished benchmarking commit (8d257b9): comparison URL. Overall result: no relevant changes - no action neededBenchmarking this pull request likely means that it is perf-sensitive, so we're automatically marking it as not fit for rolling up. While you can manually mark this PR as fit for rollup, we strongly recommend not doing so since this PR may lead to changes in compiler perf. @bors rollup=never Instruction countThis benchmark run did not return any relevant results for this metric. Max RSS (memory usage)ResultsThis is a less reliable metric that may be of interest but was not used to determine the overall result at the top of this comment.
CyclesResultsThis is a less reliable metric that may be of interest but was not used to determine the overall result at the top of this comment.
Binary sizeResultsThis is a less reliable metric that may be of interest but was not used to determine the overall result at the top of this comment.
Bootstrap: 674.671s -> 673.178s (-0.22%) |
rustbot
commented
Apr 7, 2024
This PR changes MIR cc @oli-obk, @RalfJung, @JakobDegen, @davidtwco, @celinval, @vakaras The Miri subtree was changed cc @rust-lang/miri Some changes occurred to MIR optimizations cc @rust-lang/wg-mir-opt Some changes occurred in compiler/rustc_codegen_cranelift cc @bjorn3 This PR changes Stable MIR cc @oli-obk, @celinval, @ouz-a Some changes occurred in compiler/rustc_codegen_gcc |
| RemainderByZero(Operand), | ||
| ResumedAfterReturn(CoroutineKind), | ||
| ResumedAfterPanic(CoroutineKind), | ||
| MisalignedPointerDereference { required: Operand, found: Operand }, |
There was a problem hiding this comment.
Can you please just mark this as deprecated for now instead or removing it? Thanks
770ca3d to
fa98120Comparebors
commented
May 10, 2024
☔ The latest upstream changes (presumably #124972) made this pull request unmergeable. Please resolve the merge conflicts. |
celinval
commented
May 10, 2024
Has anyone considered creating MIR passes on monomorphic MIR? I see a pattern of pushing things to codegen that should really be implemented as instrumentation passes. The code generator shouldn't be creating new basic blocks. |
saethlin
commented
May 10, 2024
Yes. Many times. Nobody is happy with the amount of cleverness in codegen. MIR is monomorphized on-the-fly as an optimization, because otherwise we'd have to clone all MIR bodies at codegen so that we can mutate them. Or we could probably have a really complicated accessor for the MIR like |
fa98120 to
52f2d3fCompare
This comment has been minimized.
This comment has been minimized.
celinval
commented
May 10, 2024
Do you know what the overhead would be if we clone the bodies lazily, just for functions that need transformation? For example, I'm assuming these checks would only be required in functions that perform unsafe operations. |
saethlin
commented
May 11, 2024
I think you have a bit of an optimistic view of the situation based on only looking at the changes in this PR. Consider also #121174. And also, if we had such a change I would like to use it to do SimplifyCfg on monomorphic MIR, to clean up the result of this traversal strategy: rust/compiler/rustc_codegen_ssa/src/mir/mod.rs Lines 270 to 281 in 6e1d947 I know from looking at the IR we produce that the mono-reachable traversal produces goto chains. Like everything else here, that optimization is possible to implement in a lazy fashion without some MIR to mutate, but it would be complicated. |
52f2d3f to
0bc84faComparesaethlin
commented
May 12, 2024
Based on what I'm seeing in #125025, maybe cloning all the MIR is not too expensive. |
celinval
commented
May 13, 2024
That's similar to our findings when we migrated to using StableMIR in Kani. StableMIR supports monomorphic bodies for instances. |
RalfJung
commented
May 14, 2024
FWIW, MIR also supports monomorphic bodies -- in the MIR-to-MiniRust translation, we monomorphize the entire MIR body before translating it. |
celinval
commented
May 14, 2024
Yes, that's how StableMIR is implemented too, but I believe you still need to clone the body. |
| pub fn pointers_to_check<F>( | ||
| statement: &mir::Statement<'_>, | ||
| required_align_of: F, |
There was a problem hiding this comment.
Why is the API design here so that a large part of the logic lies with the caller? Is this expected to be used differently from different places in the future? Or was it just to avoid passing self?
oli-obk
commented
Jun 28, 2024
Please add a codegen test that shows how we now also have alignment checks in generic code that didn't have them before |
bors
commented
Jul 20, 2024
☔ The latest upstream changes (presumably #128002) made this pull request unmergeable. Please resolve the merge conflicts. |
saethlin
commented
Jul 21, 2024
It turns out that since we're only checking that reads and writes are done to a place based on an aligned pointer, we actually don't run into the unsized pointee case anymore. Previously this pass was designed to check all derefs, not just reads and writes. That means that some of the pass logic can be cleaned up, though it still needs a carve-out for unsized locals. |
oli-obk
commented
Jul 24, 2024
r? mir-opt I'm going on leave next week |
I have closed this PR because after thinking about the "where do we put the UB checks implementation" question a lot, I've come down on the side of not maintaining two implementations wins out. It's depressing that the only way to do that is to put them in a MIR transform, but that's the state of things and I don't have the resources on my own to change it.
Implementing UB checks entirely in a MIR transform is quite limiting. Since MIR transforms work on polymorphic MIR we don't know for sure what all our types are, and sometimes we just have to give up on inserting a check. For example we used to emit MIR to compute the alignment mask at runtime, because the pointee type could be generic. and we used to skip alignment checks where we weren't sure the pointee was sized. Implementing the checks in codegen frees us from those problems, because we get to deal with monomorphized types.
Initially I implemented this by stripping down the MIR pass to insert a new terminator, which codegen would lower to a check if it saw fit. That's the perf run that has no regression: #117473 (comment). Since then, I've decided that the better strategy is to do this entirely in codegen. Only touching codegen dramatically reduces the amount of code in the compiler that this needs to touch, and it means we will insert checks into functions from the standard library which get codegenned in a crate compiled with debug assertions. Previously,
*misaligned_ptrwould be checked, butmisaligned_ptr.read()would not. With this PR, now it is. With this PR, we get checks inptr::read. That's this perf run: #117473 (comment)The only thing that jumps out at me about this codegen change is that between any two statements, codegen can change which backend block it is generating code for without changing the current MIR block. We already do insert blocks on the fly for panics, but in that case we don't stay in the new block.
I'm writing this with the expectation that I implement the niche checks in the same manner, because they have the same problem with polymorphic MIR, possibly worse.
I did a GitHub code search and the only users of the old opt-out which was
-Zmir-enable-passes=-CheckAlignmentwere turning it off because of the problem withi686-pc-windows-msvc, but that shouldn't be a problem anymore because we don't emit alignment checks on that target. Note that-Zmir-enable-passes=-CheckAlignmentwill silently stop doing anything. We never check that the passes given to-Zmir-enable-passesactually match the names of any actual passes.If the new checks cause issues, users now have the opt-out from #123411:
-Zub-checks=no.