Skip to content

Commit 54c6dee

Browse files
committed
Auto merge of rust-lang#122048 - erikdesjardins:inbounds, r=<try>
Use GEP inbounds for ZST and DST field offsets ZST field offsets have been non-`inbounds` since I made [this old layout change](https://github.com/rust-lang/rust/pull/73453/files#diff-160634de1c336f2cf325ff95b312777326f1ab29fec9b9b21d5ee9aae215ecf5). Before that, they would have been `inbounds` due to using `struct_gep`. Using `inbounds` for ZSTs likely doesn't matter for performance, but I'd like to remove the special case. DST field offsets have been non-`inbounds` since the alignment-aware DST field offset computation was first [implemented](erikdesjardins@a2557d4#diff-04fd352da30ca186fe0bb71cc81a503d1eb8a02ca17a3769e1b95981cd20964aR1188) in 1.6 (back then `GEPi()` would be used for `inbounds`), but I don't think there was any reason for it. Split out from rust-lang#121577 / rust-lang#121665. r? `@oli-obk` cc `@RalfJung` -- is there some weird situation where field offsets can't be `inbounds`? Note that it's fine for `inbounds` offsets to be one-past-the-end, so it's okay even if there's a ZST as the last field in the layout: > The base pointer has an in bounds address of an allocated object, which means that it points into an allocated object, or to its end. [(link)](https://llvm.org/docs/LangRef.html#getelementptr-instruction) For rust-lang/unsafe-code-guidelines#93, zero-offset GEP is (now) always `inbounds`: > Note that getelementptr with all-zero indices is always considered to be inbounds, even if the base pointer does not point to an allocated object. [(link)](https://llvm.org/docs/LangRef.html#getelementptr-instruction)
2 parents b6d2d84 + 8ebd307 commit 54c6dee

File tree

3 files changed

+73
-9
lines changed

3 files changed

+73
-9
lines changed

compiler/rustc_codegen_ssa/src/mir/place.rs

+1-6
Original file line numberDiff line numberDiff line change
@@ -104,10 +104,6 @@ impl<'a, 'tcx, V: CodegenObject> PlaceRef<'tcx, V> {
104104
let mut simple = || {
105105
let llval = if offset.bytes() == 0 {
106106
self.llval
107-
} else if field.is_zst() {
108-
// FIXME(erikdesjardins): it should be fine to use inbounds for ZSTs too;
109-
// keeping this logic for now to preserve previous behavior.
110-
bx.ptradd(self.llval, bx.const_usize(offset.bytes()))
111107
} else {
112108
bx.inbounds_ptradd(self.llval, bx.const_usize(offset.bytes()))
113109
};
@@ -168,8 +164,7 @@ impl<'a, 'tcx, V: CodegenObject> PlaceRef<'tcx, V> {
168164
debug!("struct_field_ptr: DST field offset: {:?}", offset);
169165

170166
// Adjust pointer.
171-
// FIXME(erikdesjardins): should be able to use inbounds here too.
172-
let ptr = bx.ptradd(self.llval, offset);
167+
let ptr = bx.inbounds_ptradd(self.llval, offset);
173168

174169
PlaceRef { llval: ptr, llextra: self.llextra, layout: field, align: effective_field_align }
175170
}

tests/codegen/dst-offset.rs

+69
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
//! This file tests that we correctly generate GEP instructions for DST
2+
//! field offsets.
3+
//@ compile-flags: -C no-prepopulate-passes -Copt-level=0
4+
5+
#![crate_type = "lib"]
6+
7+
use std::ptr::addr_of;
8+
9+
// Hack to get the correct type for usize
10+
// CHECK: @helper([[USIZE:i[0-9]+]] %_1)
11+
#[no_mangle]
12+
pub fn helper(_: usize) {
13+
}
14+
15+
struct Dst<T: ?Sized> {
16+
x: u32,
17+
y: u8,
18+
z: T,
19+
}
20+
21+
// CHECK: @dst_dyn_trait_offset(ptr align {{[0-9]+}} [[DATA_PTR:%.+]], ptr align {{[0-9]+}} [[VTABLE_PTR:%.+]])
22+
#[no_mangle]
23+
pub fn dst_dyn_trait_offset(s: &Dst<dyn Drop>) -> &dyn Drop {
24+
// The alignment of dyn trait is unknown, so we compute the offset based on align from the vtable.
25+
26+
// CHECK: [[SIZE_PTR:%[0-9]+]] = getelementptr inbounds {{.+}} [[VTABLE_PTR]]
27+
// CHECK: load [[USIZE]], ptr [[SIZE_PTR]]
28+
// CHECK: [[ALIGN_PTR:%[0-9]+]] = getelementptr inbounds {{.+}} [[VTABLE_PTR]]
29+
// CHECK: load [[USIZE]], ptr [[ALIGN_PTR]]
30+
31+
// CHECK: getelementptr inbounds i8, ptr [[DATA_PTR]]
32+
// CHECK-NEXT: insertvalue
33+
// CHECK-NEXT: insertvalue
34+
// CHECK-NEXT: ret
35+
&s.z
36+
}
37+
38+
// CHECK-LABEL: @dst_slice_offset
39+
#[no_mangle]
40+
pub fn dst_slice_offset(s: &Dst<[u16]>) -> &[u16] {
41+
// The alignment of [u16] is known, so we generate a GEP directly.
42+
43+
// CHECK: start:
44+
// CHECK-NEXT: getelementptr inbounds i8, {{.+}}, [[USIZE]] 6
45+
// CHECK-NEXT: insertvalue
46+
// CHECK-NEXT: insertvalue
47+
// CHECK-NEXT: ret
48+
&s.z
49+
}
50+
51+
#[repr(packed)]
52+
struct PackedDstSlice {
53+
x: u32,
54+
y: u8,
55+
z: [u16],
56+
}
57+
58+
// CHECK-LABEL: @packed_dst_slice_offset
59+
#[no_mangle]
60+
pub fn packed_dst_slice_offset(s: &PackedDstSlice) -> *const [u16] {
61+
// The alignment of [u16] is known, so we generate a GEP directly.
62+
63+
// CHECK: start:
64+
// CHECK-NEXT: getelementptr inbounds i8, {{.+}}, [[USIZE]] 5
65+
// CHECK-NEXT: insertvalue
66+
// CHECK-NEXT: insertvalue
67+
// CHECK-NEXT: ret
68+
addr_of!(s.z)
69+
}

tests/codegen/zst-offset.rs

+3-3
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ pub fn helper(_: usize) {
1313
// CHECK-LABEL: @scalar_layout
1414
#[no_mangle]
1515
pub fn scalar_layout(s: &(u64, ())) {
16-
// CHECK: getelementptr i8, {{.+}}, [[USIZE]] 8
16+
// CHECK: getelementptr inbounds i8, {{.+}}, [[USIZE]] 8
1717
let x = &s.1;
1818
witness(&x); // keep variable in an alloca
1919
}
@@ -22,7 +22,7 @@ pub fn scalar_layout(s: &(u64, ())) {
2222
// CHECK-LABEL: @scalarpair_layout
2323
#[no_mangle]
2424
pub fn scalarpair_layout(s: &(u64, u32, ())) {
25-
// CHECK: getelementptr i8, {{.+}}, [[USIZE]] 12
25+
// CHECK: getelementptr inbounds i8, {{.+}}, [[USIZE]] 12
2626
let x = &s.2;
2727
witness(&x); // keep variable in an alloca
2828
}
@@ -34,7 +34,7 @@ pub struct U64x4(u64, u64, u64, u64);
3434
// CHECK-LABEL: @vector_layout
3535
#[no_mangle]
3636
pub fn vector_layout(s: &(U64x4, ())) {
37-
// CHECK: getelementptr i8, {{.+}}, [[USIZE]] 32
37+
// CHECK: getelementptr inbounds i8, {{.+}}, [[USIZE]] 32
3838
let x = &s.1;
3939
witness(&x); // keep variable in an alloca
4040
}

0 commit comments

Comments
 (0)