about summary refs log tree commit diff
path: root/tests/codegen
diff options
context:
space:
mode:
Diffstat (limited to 'tests/codegen')
-rw-r--r--tests/codegen/issues/issue-106369.rs15
-rw-r--r--tests/codegen/issues/issue-73258.rs38
-rw-r--r--tests/codegen/mem-replace-big-type.rs36
-rw-r--r--tests/codegen/mem-replace-direct-memcpy.rs21
-rw-r--r--tests/codegen/ptr-read-metadata.rs96
5 files changed, 200 insertions, 6 deletions
diff --git a/tests/codegen/issues/issue-106369.rs b/tests/codegen/issues/issue-106369.rs
new file mode 100644
index 00000000000..3fe7be4f144
--- /dev/null
+++ b/tests/codegen/issues/issue-106369.rs
@@ -0,0 +1,15 @@
+// compile-flags: -O
+// ignore-debug (the extra assertions get in the way)
+
+#![crate_type = "lib"]
+
+// From <https://github.com/rust-lang/rust/issues/106369#issuecomment-1369095304>
+
+// CHECK-LABEL: @issue_106369(
+#[no_mangle]
+pub unsafe fn issue_106369(ptr: *const &i32) -> bool {
+    // CHECK-NOT: icmp
+    // CHECK: ret i1 true
+    // CHECK-NOT: icmp
+    Some(std::ptr::read(ptr)).is_some()
+}
diff --git a/tests/codegen/issues/issue-73258.rs b/tests/codegen/issues/issue-73258.rs
new file mode 100644
index 00000000000..0134f929b29
--- /dev/null
+++ b/tests/codegen/issues/issue-73258.rs
@@ -0,0 +1,38 @@
+// compile-flags: -O
+// ignore-debug (the extra assertions get in the way)
+
+#![crate_type = "lib"]
+
+// Adapted from <https://github.com/rust-lang/rust/issues/73258#issue-637346014>
+
+#[derive(Clone, Copy)]
+#[repr(u8)]
+pub enum Foo {
+    A, B, C, D,
+}
+
+// CHECK-LABEL: @issue_73258(
+#[no_mangle]
+pub unsafe fn issue_73258(ptr: *const Foo) -> Foo {
+    // CHECK-NOT: icmp
+    // CHECK-NOT: call
+    // CHECK-NOT: br
+    // CHECK-NOT: select
+
+    // CHECK: %[[R:.+]] = load i8
+    // CHECK-SAME: !range !
+
+    // CHECK-NOT: icmp
+    // CHECK-NOT: call
+    // CHECK-NOT: br
+    // CHECK-NOT: select
+
+    // CHECK: ret i8 %[[R]]
+
+    // CHECK-NOT: icmp
+    // CHECK-NOT: call
+    // CHECK-NOT: br
+    // CHECK-NOT: select
+    let k: Option<Foo> = Some(ptr.read());
+    return k.unwrap();
+}
diff --git a/tests/codegen/mem-replace-big-type.rs b/tests/codegen/mem-replace-big-type.rs
new file mode 100644
index 00000000000..f6898e2f758
--- /dev/null
+++ b/tests/codegen/mem-replace-big-type.rs
@@ -0,0 +1,36 @@
+// This test ensures that `mem::replace::<T>` only ever calls `@llvm.memcpy`
+// with `size_of::<T>()` as the size, and never goes through any wrapper that
+// may e.g. multiply `size_of::<T>()` with a variable "count" (which is only
+// known to be `1` after inlining).
+
+// compile-flags: -C no-prepopulate-passes -Zinline-mir=no
+// ignore-debug: the debug assertions get in the way
+
+#![crate_type = "lib"]
+
+#[repr(C, align(8))]
+pub struct Big([u64; 7]);
+pub fn replace_big(dst: &mut Big, src: Big) -> Big {
+    // Before the `read_via_copy` intrinsic, this emitted six `memcpy`s.
+    std::mem::replace(dst, src)
+}
+
+// NOTE(eddyb) the `CHECK-NOT`s ensure that the only calls of `@llvm.memcpy` in
+// the entire output, are the direct calls we want, from `ptr::replace`.
+
+// CHECK-NOT: call void @llvm.memcpy
+
+// For a large type, we expect exactly three `memcpy`s
+// CHECK-LABEL: define internal void @{{.+}}mem{{.+}}replace{{.+}}sret(%Big)
+    // CHECK-NOT: alloca
+    // CHECK: alloca %Big
+    // CHECK-NOT: alloca
+    // CHECK-NOT: call void @llvm.memcpy
+    // CHECK: call void @llvm.memcpy.{{.+}}({{i8\*|ptr}} align 8 %{{.*}}, {{i8\*|ptr}} align 8 %{{.*}}, i{{.*}} 56, i1 false)
+    // CHECK-NOT: call void @llvm.memcpy
+    // CHECK: call void @llvm.memcpy.{{.+}}({{i8\*|ptr}} align 8 %{{.*}}, {{i8\*|ptr}} align 8 %{{.*}}, i{{.*}} 56, i1 false)
+    // CHECK-NOT: call void @llvm.memcpy
+    // CHECK: call void @llvm.memcpy.{{.+}}({{i8\*|ptr}} align 8 %{{.*}}, {{i8\*|ptr}} align 8 %{{.*}}, i{{.*}} 56, i1 false)
+    // CHECK-NOT: call void @llvm.memcpy
+
+// CHECK-NOT: call void @llvm.memcpy
diff --git a/tests/codegen/mem-replace-direct-memcpy.rs b/tests/codegen/mem-replace-direct-memcpy.rs
index e8bbf0e1bbd..83babab4f84 100644
--- a/tests/codegen/mem-replace-direct-memcpy.rs
+++ b/tests/codegen/mem-replace-direct-memcpy.rs
@@ -13,12 +13,21 @@ pub fn replace_byte(dst: &mut u8, src: u8) -> u8 {
 }
 
 // NOTE(eddyb) the `CHECK-NOT`s ensure that the only calls of `@llvm.memcpy` in
-// the entire output, are the two direct calls we want, from `ptr::replace`.
+// the entire output, are the direct calls we want, from `ptr::replace`.
 
 // CHECK-NOT: call void @llvm.memcpy
-// CHECK: ; core::mem::replace
-// CHECK-NOT: call void @llvm.memcpy
-// CHECK: call void @llvm.memcpy.{{.+}}({{i8\*|ptr}} align 1 %{{.*}}, {{i8\*|ptr}} align 1 %{{.*}}, i{{.*}} 1, i1 false)
-// CHECK-NOT: call void @llvm.memcpy
-// CHECK: call void @llvm.memcpy.{{.+}}({{i8\*|ptr}} align 1 %{{.*}}, {{i8\*|ptr}} align 1 %{{.*}}, i{{.*}} 1, i1 false)
+
+// For a small type, we expect one each of `load`/`store`/`memcpy` instead
+// CHECK-LABEL: define internal noundef i8 @{{.+}}mem{{.+}}replace
+    // CHECK-NOT: alloca
+    // CHECK: alloca i8
+    // CHECK-NOT: alloca
+    // CHECK-NOT: call void @llvm.memcpy
+    // CHECK: load i8
+    // CHECK-NOT: call void @llvm.memcpy
+    // CHECK: store i8
+    // CHECK-NOT: call void @llvm.memcpy
+    // CHECK: call void @llvm.memcpy.{{.+}}({{i8\*|ptr}} align 1 %{{.*}}, {{i8\*|ptr}} align 1 %{{.*}}, i{{.*}} 1, i1 false)
+    // CHECK-NOT: call void @llvm.memcpy
+
 // CHECK-NOT: call void @llvm.memcpy
diff --git a/tests/codegen/ptr-read-metadata.rs b/tests/codegen/ptr-read-metadata.rs
new file mode 100644
index 00000000000..e1e3272662c
--- /dev/null
+++ b/tests/codegen/ptr-read-metadata.rs
@@ -0,0 +1,96 @@
+// compile-flags: -O -Z merge-functions=disabled
+// no-system-llvm
+// ignore-debug (the extra assertions get in the way)
+
+#![crate_type = "lib"]
+
+// Ensure that various forms of reading pointers correctly annotate the `load`s
+// with `!noundef` and `!range` metadata to enable extra optimization.
+
+use std::mem::MaybeUninit;
+
+// CHECK-LABEL: define noundef i8 @copy_byte(
+#[no_mangle]
+pub unsafe fn copy_byte(p: *const u8) -> u8 {
+    // CHECK-NOT: load
+    // CHECK: load i8, ptr %p, align 1
+    // CHECK-SAME: !noundef !
+    // CHECK-NOT: load
+    *p
+}
+
+// CHECK-LABEL: define noundef i8 @read_byte(
+#[no_mangle]
+pub unsafe fn read_byte(p: *const u8) -> u8 {
+    // CHECK-NOT: load
+    // CHECK: load i8, ptr %p, align 1
+    // CHECK-SAME: !noundef !
+    // CHECK-NOT: load
+    p.read()
+}
+
+// CHECK-LABEL: define i8 @read_byte_maybe_uninit(
+#[no_mangle]
+pub unsafe fn read_byte_maybe_uninit(p: *const MaybeUninit<u8>) -> MaybeUninit<u8> {
+    // CHECK-NOT: load
+    // CHECK: load i8, ptr %p, align 1
+    // CHECK-NOT: noundef
+    // CHECK-NOT: load
+    p.read()
+}
+
+// CHECK-LABEL: define noundef i8 @read_byte_assume_init(
+#[no_mangle]
+pub unsafe fn read_byte_assume_init(p: &MaybeUninit<u8>) -> u8 {
+    // CHECK-NOT: load
+    // CHECK: load i8, ptr %p, align 1
+    // CHECK-SAME: !noundef !
+    // CHECK-NOT: load
+    p.assume_init_read()
+}
+
+// CHECK-LABEL: define noundef i32 @copy_char(
+#[no_mangle]
+pub unsafe fn copy_char(p: *const char) -> char {
+    // CHECK-NOT: load
+    // CHECK: load i32, ptr %p
+    // CHECK-SAME: !range ![[RANGE:[0-9]+]]
+    // CHECK-SAME: !noundef !
+    // CHECK-NOT: load
+    *p
+}
+
+// CHECK-LABEL: define noundef i32 @read_char(
+#[no_mangle]
+pub unsafe fn read_char(p: *const char) -> char {
+    // CHECK-NOT: load
+    // CHECK: load i32, ptr %p
+    // CHECK-SAME: !range ![[RANGE]]
+    // CHECK-SAME: !noundef !
+    // CHECK-NOT: load
+    p.read()
+}
+
+// CHECK-LABEL: define i32 @read_char_maybe_uninit(
+#[no_mangle]
+pub unsafe fn read_char_maybe_uninit(p: *const MaybeUninit<char>) -> MaybeUninit<char> {
+    // CHECK-NOT: load
+    // CHECK: load i32, ptr %p
+    // CHECK-NOT: range
+    // CHECK-NOT: noundef
+    // CHECK-NOT: load
+    p.read()
+}
+
+// CHECK-LABEL: define noundef i32 @read_char_assume_init(
+#[no_mangle]
+pub unsafe fn read_char_assume_init(p: &MaybeUninit<char>) -> char {
+    // CHECK-NOT: load
+    // CHECK: load i32, ptr %p
+    // CHECK-SAME: !range ![[RANGE]]
+    // CHECK-SAME: !noundef !
+    // CHECK-NOT: load
+    p.assume_init_read()
+}
+
+// CHECK: ![[RANGE]] = !{i32 0, i32 1114112}