about summary refs log tree commit diff
path: root/tests/codegen
diff options
context:
space:
mode:
authorErik Desjardins <erikdesjardins@users.noreply.github.com>2024-02-28 00:09:24 -0500
committerErik Desjardins <erikdesjardins@users.noreply.github.com>2024-03-04 09:32:33 -0500
commit8ebd307d2a95840e193ff03aff21c87b5c643ef4 (patch)
treed0a733ea5935ef049ccf91dcb393aa5bb5839c57 /tests/codegen
parent7606c13961ddc1174b70638e934df0439b7dc515 (diff)
downloadrust-8ebd307d2a95840e193ff03aff21c87b5c643ef4.tar.gz
rust-8ebd307d2a95840e193ff03aff21c87b5c643ef4.zip
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.
Diffstat (limited to 'tests/codegen')
-rw-r--r--tests/codegen/dst-offset.rs69
-rw-r--r--tests/codegen/zst-offset.rs6
2 files changed, 72 insertions, 3 deletions
diff --git a/tests/codegen/dst-offset.rs b/tests/codegen/dst-offset.rs
new file mode 100644
index 00000000000..55212112b3d
--- /dev/null
+++ b/tests/codegen/dst-offset.rs
@@ -0,0 +1,69 @@
+//! This file tests that we correctly generate GEP instructions for DST
+//! field offsets.
+//@ compile-flags: -C no-prepopulate-passes -Copt-level=0
+
+#![crate_type = "lib"]
+
+use std::ptr::addr_of;
+
+// Hack to get the correct type for usize
+// CHECK: @helper([[USIZE:i[0-9]+]] %_1)
+#[no_mangle]
+pub fn helper(_: usize) {
+}
+
+struct Dst<T: ?Sized> {
+    x: u32,
+    y: u8,
+    z: T,
+}
+
+// CHECK: @dst_dyn_trait_offset(ptr align {{[0-9]+}} [[DATA_PTR:%.+]], ptr align {{[0-9]+}} [[VTABLE_PTR:%.+]])
+#[no_mangle]
+pub fn dst_dyn_trait_offset(s: &Dst<dyn Drop>) -> &dyn Drop {
+// The alignment of dyn trait is unknown, so we compute the offset based on align from the vtable.
+
+// CHECK: [[SIZE_PTR:%[0-9]+]] = getelementptr inbounds {{.+}} [[VTABLE_PTR]]
+// CHECK: load [[USIZE]], ptr [[SIZE_PTR]]
+// CHECK: [[ALIGN_PTR:%[0-9]+]] = getelementptr inbounds {{.+}} [[VTABLE_PTR]]
+// CHECK: load [[USIZE]], ptr [[ALIGN_PTR]]
+
+// CHECK: getelementptr inbounds i8, ptr [[DATA_PTR]]
+// CHECK-NEXT: insertvalue
+// CHECK-NEXT: insertvalue
+// CHECK-NEXT: ret
+    &s.z
+}
+
+// CHECK-LABEL: @dst_slice_offset
+#[no_mangle]
+pub fn dst_slice_offset(s: &Dst<[u16]>) -> &[u16] {
+// The alignment of [u16] is known, so we generate a GEP directly.
+
+// CHECK: start:
+// CHECK-NEXT: getelementptr inbounds i8, {{.+}}, [[USIZE]] 6
+// CHECK-NEXT: insertvalue
+// CHECK-NEXT: insertvalue
+// CHECK-NEXT: ret
+    &s.z
+}
+
+#[repr(packed)]
+struct PackedDstSlice {
+    x: u32,
+    y: u8,
+    z: [u16],
+}
+
+// CHECK-LABEL: @packed_dst_slice_offset
+#[no_mangle]
+pub fn packed_dst_slice_offset(s: &PackedDstSlice) -> *const [u16] {
+// The alignment of [u16] is known, so we generate a GEP directly.
+
+// CHECK: start:
+// CHECK-NEXT: getelementptr inbounds i8, {{.+}}, [[USIZE]] 5
+// CHECK-NEXT: insertvalue
+// CHECK-NEXT: insertvalue
+// CHECK-NEXT: ret
+    addr_of!(s.z)
+}
diff --git a/tests/codegen/zst-offset.rs b/tests/codegen/zst-offset.rs
index 65d9cf39c4c..b623d492d9d 100644
--- a/tests/codegen/zst-offset.rs
+++ b/tests/codegen/zst-offset.rs
@@ -13,7 +13,7 @@ pub fn helper(_: usize) {
 // CHECK-LABEL: @scalar_layout
 #[no_mangle]
 pub fn scalar_layout(s: &(u64, ())) {
-// CHECK: getelementptr i8, {{.+}}, [[USIZE]] 8
+// CHECK: getelementptr inbounds i8, {{.+}}, [[USIZE]] 8
     let x = &s.1;
     witness(&x); // keep variable in an alloca
 }
@@ -22,7 +22,7 @@ pub fn scalar_layout(s: &(u64, ())) {
 // CHECK-LABEL: @scalarpair_layout
 #[no_mangle]
 pub fn scalarpair_layout(s: &(u64, u32, ())) {
-// CHECK: getelementptr i8, {{.+}}, [[USIZE]] 12
+// CHECK: getelementptr inbounds i8, {{.+}}, [[USIZE]] 12
     let x = &s.2;
     witness(&x); // keep variable in an alloca
 }
@@ -34,7 +34,7 @@ pub struct U64x4(u64, u64, u64, u64);
 // CHECK-LABEL: @vector_layout
 #[no_mangle]
 pub fn vector_layout(s: &(U64x4, ())) {
-// CHECK: getelementptr i8, {{.+}}, [[USIZE]] 32
+// CHECK: getelementptr inbounds i8, {{.+}}, [[USIZE]] 32
     let x = &s.1;
     witness(&x); // keep variable in an alloca
 }