-
-
Notifications
You must be signed in to change notification settings - Fork 14.9k
Add a layout_of_val intrinsic for when you want both size_of_val+align_of_val
#152786
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
Changes from 2 commits
a10bd19
9cabb08
c504f7e
117929b
fdaf983
e7802c3
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -36,8 +36,9 @@ pub fn size_and_align_of_dst<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>( | |
| // Size is always <= isize::MAX. | ||
| let size_bound = bx.data_layout().ptr_sized_integer().signed_max() as u128; | ||
| bx.range_metadata(size, WrappingRange { start: 0, end: size_bound }); | ||
| // Alignment is always nonzero. | ||
| bx.range_metadata(align, WrappingRange { start: 1, end: !0 }); | ||
| // Alignment is always a power of two, thus 1..=0x800…000. | ||
| let align_bound = size_bound + 1; | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. In fact the bound is
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Oh, really good point 👍 I was stuck still thinking of it as a load of I don't know how much it'll really matter, since |
||
| bx.range_metadata(align, WrappingRange { start: 1, end: align_bound }); | ||
|
|
||
| (size, align) | ||
| } | ||
|
|
@@ -157,7 +158,12 @@ pub fn size_and_align_of_dst<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>( | |
| // Furthermore, `align >= unsized_align`, and therefore we only need to do: | ||
| // let full_size = (unsized_offset_unadjusted + unsized_size).align_to(full_align); | ||
|
|
||
| let full_size = bx.add(unsized_offset_unadjusted, unsized_size); | ||
| // This is the size *before* rounding up, which cannot exceed the size *after* | ||
| // rounding up, which itself cannot exceed `isize::MAX`. Thus the addition | ||
| // itself cannot overflow `isize::MAX`, let alone `usize::MAX`. | ||
| // (The range attribute from loading the size from the vtable is enough to prove | ||
| // `nuw`, but not `nsw`, which we only know from Rust's layout rules.) | ||
| let full_size = bx.unchecked_suadd(unsized_offset_unadjusted, unsized_size); | ||
|
|
||
| // Issue #27023: must add any necessary padding to `size` | ||
| // (to make it a multiple of `align`) before returning it. | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,77 @@ | ||
| //@ compile-flags: -Copt-level=3 -C no-prepopulate-passes -Z inline-mir | ||
| //@ only-64bit (so I don't need to worry about usize) | ||
| //@ needs-deterministic-layouts | ||
|
|
||
| // Note that the layout algorithm currently puts the align before the size, | ||
| // because the *type* for the size doesn't have a niche. This test may need | ||
| // to be updated if the in-memory field order of `Layout` ever changes. | ||
|
|
||
| #![crate_type = "lib"] | ||
| #![feature(core_intrinsics)] | ||
|
|
||
| use std::alloc::Layout; | ||
| use std::intrinsics::layout_of_val; | ||
|
|
||
| // CHECK-LABEL: @thin_metadata( | ||
| #[no_mangle] | ||
| pub unsafe fn thin_metadata(ptr: *const [u32; 2]) -> Layout { | ||
| // CHECK: [[LAYOUT:%.+]] = alloca [16 x i8], align 8 | ||
| // CHECK-NOT: load | ||
| // CHECK-NOT: store | ||
| // CHECK: store i64 4, ptr [[LAYOUT]], align 8 | ||
| // CHECK-NEXT: [[SIZEP:%.+]] = getelementptr inbounds i8, ptr [[LAYOUT]], i64 8 | ||
| // CHECK-NEXT: store i64 8, ptr [[SIZEP]], align 8 | ||
| // CHECK-NOT: store | ||
| layout_of_val(ptr) | ||
| } | ||
|
|
||
| // CHECK-LABEL: @slice_metadata(ptr noundef %ptr.0, i64 noundef %ptr.1) | ||
| #[no_mangle] | ||
| pub unsafe fn slice_metadata(ptr: *const [u32]) -> Layout { | ||
| // CHECK: [[LAYOUT:%.+]] = alloca [16 x i8], align 8 | ||
| // CHECK-NOT: load | ||
| // CHECK-NOT: store | ||
| // CHECK: [[BYTES:%.+]] = mul nuw nsw i64 %ptr.1, 4 | ||
| // CHECK-NEXT: store i64 4, ptr [[LAYOUT]], align 8 | ||
| // CHECK-NEXT: [[SIZEP:%.+]] = getelementptr inbounds i8, ptr [[LAYOUT]], i64 8 | ||
| // CHECK-NEXT: store i64 [[BYTES]], ptr [[SIZEP]], align 8 | ||
| // CHECK-NOT: store | ||
| layout_of_val(ptr) | ||
| } | ||
|
|
||
| pub struct WithTail<T: ?Sized>([u32; 3], T); | ||
|
|
||
| // CHECK-LABEL: @dst_metadata | ||
| // CHECK-SAME: (ptr noundef %ptr.0, ptr{{.+}}%ptr.1) | ||
| #[no_mangle] | ||
| pub unsafe fn dst_metadata(ptr: *const WithTail<dyn std::fmt::Debug>) -> Layout { | ||
| // CHECK: [[LAYOUT:%.+]] = alloca [16 x i8], align 8 | ||
| // CHECK-NOT: load | ||
| // CHECK-NOT: store | ||
| // CHECK: [[DST_SIZEP:%.+]] = getelementptr inbounds i8, ptr %ptr.1, i64 8 | ||
| // CHECK-NEXT: [[DST_SIZE:%.+]] = load i64, ptr [[DST_SIZEP]], align 8, | ||
| // CHECK-SAME: !range [[SIZE_RANGE:.+]], !invariant.load | ||
| // CHECK-NEXT: [[DST_ALIGNP:%.+]] = getelementptr inbounds i8, ptr %ptr.1, i64 16 | ||
| // CHECK-NEXT: [[DST_ALIGN:%.+]] = load i64, ptr [[DST_ALIGNP]], align 8, | ||
| // CHECK-SAME: !range [[ALIGN_RANGE:!.+]], !invariant.load | ||
|
|
||
| // CHECK-NEXT: [[STRUCT_MORE:%.+]] = icmp ugt i64 4, [[DST_ALIGN]] | ||
| // CHECK-NEXT: [[ALIGN:%.+]] = select i1 [[STRUCT_MORE]], i64 4, i64 [[DST_ALIGN]] | ||
|
|
||
| // CHECK-NEXT: [[MINSIZE:%.+]] = add nuw nsw i64 12, [[DST_SIZE]] | ||
| // CHECK-NEXT: [[ALIGN_M1:%.+]] = sub i64 [[ALIGN]], 1 | ||
| // CHECK-NEXT: [[MAXSIZE:%.+]] = add i64 [[MINSIZE]], [[ALIGN_M1]] | ||
| // CHECK-NEXT: [[ALIGN_NEG:%.+]] = sub i64 0, [[ALIGN]] | ||
| // CHECK-NEXT: [[SIZE:%.+]] = and i64 [[MAXSIZE]], [[ALIGN_NEG]] | ||
|
|
||
| // CHECK-NEXT: store i64 [[ALIGN]], ptr [[LAYOUT]], align 8 | ||
| // CHECK-NEXT: [[LAYOUT_SIZEP:%.+]] = getelementptr inbounds i8, ptr [[LAYOUT]], i64 8 | ||
| // CHECK-NEXT: store i64 [[SIZE]], ptr [[LAYOUT_SIZEP]], align 8 | ||
| // CHECK-NOT: store | ||
| layout_of_val(ptr) | ||
| } | ||
|
|
||
| // CHECK-LABEL: declare | ||
|
|
||
| // CHECK: [[ALIGN_RANGE]] = !{i64 1, i64 -[[#0x7FFFFFFFFFFFFFFF]] | ||
| // CHECK: [[SIZE_RANGE]] = !{i64 0, i64 -[[#0x8000000000000000]] |
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're still relying on the in-source field order here. That deserves a comment on both ends (here and in the library). Or can the field lookup here be done by name?