-
-
Notifications
You must be signed in to change notification settings - Fork 15.3k
Implement ptr::{read,write}_unaligned via repr(packed)
#158427
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
Changes from all commits
Commits
Show all changes
2 commits
Select commit
Hold shift + click to select a range
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,71 @@ | ||
| //@ compile-flags: -Copt-level=3 | ||
| //@ only-64bit | ||
|
|
||
| #![crate_type = "lib"] | ||
|
|
||
| use std::num::NonZero; | ||
| use std::ptr::NonNull; | ||
|
|
||
| // CHECK-LABEL: nonnull ptr @read_unaligned_ptr(ptr{{.+}}%ptr) | ||
| #[no_mangle] | ||
| unsafe fn read_unaligned_ptr(ptr: *const NonNull<i16>) -> NonNull<i16> { | ||
| // CHECK: start: | ||
| // CHECK-NEXT: [[TEMP:%.+]] = load ptr, ptr %ptr, align 1 | ||
| // CHECK-SAME: !nonnull | ||
| // CHECK-SAME: !noundef | ||
| // CHECK-NEXT: ret ptr [[TEMP]] | ||
| ptr.read_unaligned() | ||
| } | ||
|
|
||
| // CHECK-LABEL: range(i16 1, 0) i16 @read_unaligned_i16(ptr{{.+}}%ptr) | ||
| #[no_mangle] | ||
| unsafe fn read_unaligned_i16(ptr: *const NonZero<i16>) -> NonZero<i16> { | ||
| // CHECK: start: | ||
| // CHECK-NEXT: [[TEMP:%.+]] = load i16, ptr %ptr, align 1 | ||
| // CHECK-NOT: !noundef | ||
| // CHECK-NOT: !range | ||
| // CHECK-NEXT: ret i16 [[TEMP]] | ||
| ptr.read_unaligned() | ||
| } | ||
|
|
||
| // CHECK-LABEL: void @typed_copy_unaligned_i32(ptr{{.+}}%src, ptr{{.+}}%dst) | ||
| #[no_mangle] | ||
| unsafe fn typed_copy_unaligned_i32(src: *const NonZero<i32>, dst: *mut NonZero<i32>) { | ||
| // CHECK: start: | ||
| // CHECK-NEXT: [[TEMP:%.+]] = load i32, ptr %src, align 1 | ||
| // CHECK-NOT: !noundef | ||
| // CHECK-NOT: !range | ||
| // CHECK-NEXT: store i32 [[TEMP]], ptr %dst, align 1 | ||
| // CHECK-NEXT: ret void | ||
| dst.write_unaligned(src.read_unaligned()) | ||
| } | ||
|
|
||
| // CHECK-LABEL: void @write_unaligned_i64(ptr{{.+}}%ptr, i64{{.+}}%val) | ||
| #[no_mangle] | ||
| unsafe fn write_unaligned_i64(ptr: *mut NonZero<i64>, val: NonZero<i64>) { | ||
| // CHECK: start: | ||
| // CHECK-NEXT: store i64 %val, ptr %ptr, align 1 | ||
| // CHECK-NEXT: ret void | ||
| ptr.write_unaligned(val) | ||
| } | ||
|
|
||
| #[repr(align(128))] | ||
| struct HugeBuffer([u64; 1 << 10]); | ||
|
|
||
| // CHECK-LABEL: void @read_unaligned_huge(ptr{{.+}}%_0, ptr{{.+}}%ptr) | ||
| #[no_mangle] | ||
| unsafe fn read_unaligned_huge(ptr: *const HugeBuffer) -> HugeBuffer { | ||
| // CHECK: start: | ||
| // CHECK-NEXT: call void @llvm.memcpy{{.+}} align 128 dereferenceable(8192) %_0, {{.+}} align 1 dereferenceable(8192) %ptr, i64 8192, | ||
| // CHECK-NEXT: ret void | ||
| ptr.read_unaligned() | ||
| } | ||
|
|
||
| // CHECK-LABEL: void @write_unaligned_huge(ptr{{.+}}%ptr, ptr{{.+}}%val) | ||
| #[no_mangle] | ||
| unsafe fn write_unaligned_huge(ptr: *mut HugeBuffer, val: HugeBuffer) { | ||
| // CHECK: start: | ||
| // CHECK-NEXT: call void @llvm.memcpy{{.+}} align 1 dereferenceable(8192) %ptr, {{.+}} align 128 dereferenceable(8192) %val, i64 8192, | ||
| // CHECK-NEXT: ret void | ||
| ptr.write_unaligned(val) | ||
| } | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,39 @@ | ||
| //@ compile-flags: -O -Zmir-opt-level=2 | ||
| //@ ignore-std-debug-assertions (there's one in `ptr::read`) | ||
|
|
||
| #![crate_type = "lib"] | ||
|
|
||
| // EMIT_MIR unaligned.unaligned_copy_manual.runtime-optimized.after.mir | ||
| pub unsafe fn unaligned_copy_manual(src: *const u128, dst: *mut u128) { | ||
| #[repr(packed)] | ||
| struct Packed<T>(T); | ||
|
|
||
| // CHECK-LABEL: fn unaligned_copy_manual(_1: *const u128, _2: *mut u128) -> () | ||
| // CHECK: [[SRCU:_.+]] = copy _1 as *const unaligned_copy_manual::Packed<u128> (PtrToPtr); | ||
| // CHECK: [[DSTU:_.+]] = copy _2 as *mut unaligned_copy_manual::Packed<u128> (PtrToPtr); | ||
| // CHECK: [[TEMP:_.+]] = copy ((*[[SRCU]]).0: u128); | ||
| // ((*[[DSTU]]).0: u128) = move [[TEMP]]; | ||
| let src = src.cast::<Packed<u128>>(); | ||
| let dst = dst.cast::<Packed<u128>>(); | ||
| unsafe { (*dst).0 = (*src).0 }; | ||
| } | ||
|
|
||
| // EMIT_MIR unaligned.unaligned_copy_generic.runtime-optimized.after.mir | ||
| pub unsafe fn unaligned_copy_generic<T>(src: *const T, dst: *mut T) { | ||
| // CHECK-LABEL: fn unaligned_copy_generic( | ||
| // CHECK: debug src => _1; | ||
| // CHECK: debug dst => _2; | ||
| // CHECK: debug val => [[VAL:_.+]]; | ||
| // CHECK: [[SRC_P:_.+]] = copy _1 as *const {{.+}}::Packed<T> (PtrToPtr); | ||
| // CHECK: [[PACKED1:_.+]] = copy (*[[SRC_P]]); | ||
| // CHECK: [[VAL]] = copy [[PACKED1]] as T (Transmute); | ||
| // CHECK: [[DST_P:_.+]] = copy _2 as *mut {{.+}}::Packed<T> (PtrToPtr); | ||
| // CHECK: [[PACKED2:_.+]] = {{.+}}::Packed::<T>(copy [[VAL]]); | ||
| // CHECK: (*[[DST_P]]) = copy [[PACKED2]]; | ||
| // CHECK-NOT: copy_nonoverlapping | ||
| // CHECK-NOT: drop | ||
| unsafe { | ||
| let val = std::ptr::read_unaligned(src); | ||
| std::ptr::write_unaligned(dst, val); | ||
| } | ||
| } |
57 changes: 57 additions & 0 deletions
57
tests/mir-opt/pre-codegen/unaligned.unaligned_copy_generic.runtime-optimized.after.mir
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,57 @@ | ||
| // MIR for `unaligned_copy_generic` after runtime-optimized | ||
|
|
||
| fn unaligned_copy_generic(_1: *const T, _2: *mut T) -> () { | ||
| debug src => _1; | ||
| debug dst => _2; | ||
| let mut _0: (); | ||
| let _5: T; | ||
| scope 1 { | ||
| debug val => _5; | ||
| scope 8 (inlined #[track_caller] write_unaligned::<T>) { | ||
| let _6: *mut std::ptr::Packed<T>; | ||
| scope 9 { | ||
| let _7: std::ptr::Packed<T>; | ||
| scope 10 { | ||
| scope 12 (inlined #[track_caller] std::ptr::write::<std::ptr::Packed<T>>) { | ||
| } | ||
| } | ||
| } | ||
| scope 11 (inlined std::ptr::mut_ptr::<impl *mut T>::cast::<std::ptr::Packed<T>>) { | ||
| } | ||
| } | ||
| } | ||
| scope 2 (inlined #[track_caller] read_unaligned::<T>) { | ||
| let _3: *const std::ptr::Packed<T>; | ||
| scope 3 { | ||
| let _4: std::ptr::Packed<T>; | ||
| scope 4 { | ||
| scope 7 (inlined transmute_neo::<std::ptr::Packed<T>, T>) { | ||
| } | ||
| } | ||
| scope 6 (inlined #[track_caller] std::ptr::read::<std::ptr::Packed<T>>) { | ||
| } | ||
| } | ||
| scope 5 (inlined std::ptr::const_ptr::<impl *const T>::cast::<std::ptr::Packed<T>>) { | ||
| } | ||
| } | ||
|
|
||
| bb0: { | ||
| StorageLive(_5); | ||
| StorageLive(_3); | ||
| _3 = copy _1 as *const std::ptr::Packed<T> (PtrToPtr); | ||
| StorageLive(_4); | ||
| _4 = copy (*_3); | ||
| _5 = copy _4 as T (Transmute); | ||
| StorageDead(_4); | ||
| StorageDead(_3); | ||
| StorageLive(_6); | ||
| _6 = copy _2 as *mut std::ptr::Packed<T> (PtrToPtr); | ||
| StorageLive(_7); | ||
| _7 = std::ptr::Packed::<T>(copy _5); | ||
| (*_6) = copy _7; | ||
| StorageDead(_7); | ||
| StorageDead(_6); | ||
| StorageDead(_5); | ||
| return; | ||
| } | ||
| } |
34 changes: 34 additions & 0 deletions
34
tests/mir-opt/pre-codegen/unaligned.unaligned_copy_manual.runtime-optimized.after.mir
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,34 @@ | ||
| // MIR for `unaligned_copy_manual` after runtime-optimized | ||
|
|
||
| fn unaligned_copy_manual(_1: *const u128, _2: *mut u128) -> () { | ||
| debug src => _1; | ||
| debug dst => _2; | ||
| let mut _0: (); | ||
| let _3: *const unaligned_copy_manual::Packed<u128>; | ||
| let mut _5: u128; | ||
| scope 1 { | ||
| debug src => _3; | ||
| let _4: *mut unaligned_copy_manual::Packed<u128>; | ||
| scope 2 { | ||
| debug dst => _4; | ||
| } | ||
| scope 4 (inlined std::ptr::mut_ptr::<impl *mut u128>::cast::<Packed<u128>>) { | ||
| } | ||
| } | ||
| scope 3 (inlined std::ptr::const_ptr::<impl *const u128>::cast::<Packed<u128>>) { | ||
| } | ||
|
|
||
| bb0: { | ||
| StorageLive(_3); | ||
| _3 = copy _1 as *const unaligned_copy_manual::Packed<u128> (PtrToPtr); | ||
| StorageLive(_4); | ||
| _4 = copy _2 as *mut unaligned_copy_manual::Packed<u128> (PtrToPtr); | ||
| StorageLive(_5); | ||
| _5 = copy ((*_3).0: u128); | ||
| ((*_4).0: u128) = move _5; | ||
| StorageDead(_5); | ||
| StorageDead(_4); | ||
| StorageDead(_3); | ||
| return; | ||
| } | ||
| } |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.
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.
Obviously it would be better to have metadata on these loads, but they're not there in nightly today either (https://rust.godbolt.org/z/753TYoa1Y) so this isn't a regression.
Should be better thanks to mir opts in future, though, without needing additional library changes.
View changes since the review
Uh oh!
There was an error while loading. Please reload this page.
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.
...or could also be fixed by rust-lang/compiler-team#1007 and using
repr(Rust), if that MCP lands.