Skip to content

Commit 8ebd307

Browse files
use GEP inbounds for ZST and DST field offsets
For the former, it's fine for `inbounds` offsets to be one-past-the-end, so it's okay even if the ZST is 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. https://llvm.org/docs/LangRef.html#getelementptr-instruction For the latter, even DST fields must always be inside the layout (or to its end for ZSTs), so using inbounds is also fine there.
1 parent 7606c13 commit 8ebd307

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)