diff options
Diffstat (limited to 'tests/codegen')
| -rw-r--r-- | tests/codegen/fewer-names.rs | 4 | ||||
| -rw-r--r-- | tests/codegen/inherit_overflow.rs | 2 | ||||
| -rw-r--r-- | tests/codegen/issues/issue-106369.rs | 15 | ||||
| -rw-r--r-- | tests/codegen/issues/issue-73258.rs | 38 | ||||
| -rw-r--r-- | tests/codegen/mem-replace-big-type.rs | 36 | ||||
| -rw-r--r-- | tests/codegen/mem-replace-direct-memcpy.rs | 21 | ||||
| -rw-r--r-- | tests/codegen/ptr-read-metadata.rs | 96 | ||||
| -rw-r--r-- | tests/codegen/var-names.rs | 4 | ||||
| -rw-r--r-- | tests/codegen/vec-as-ptr.rs | 19 |
9 files changed, 224 insertions, 11 deletions
diff --git a/tests/codegen/fewer-names.rs b/tests/codegen/fewer-names.rs index ac8cba06b48..7f383a5c149 100644 --- a/tests/codegen/fewer-names.rs +++ b/tests/codegen/fewer-names.rs @@ -13,8 +13,8 @@ pub fn sum(x: u32, y: u32) -> u32 { // NO-LABEL: define{{.*}}i32 @sum(i32 noundef %x, i32 noundef %y) // NO-NEXT: start: -// NO-NEXT: %z = add i32 %y, %x -// NO-NEXT: ret i32 %z +// NO-NEXT: %0 = add i32 %y, %x +// NO-NEXT: ret i32 %0 let z = x + y; z } diff --git a/tests/codegen/inherit_overflow.rs b/tests/codegen/inherit_overflow.rs index 0b0b890b2c9..39909d7abfd 100644 --- a/tests/codegen/inherit_overflow.rs +++ b/tests/codegen/inherit_overflow.rs @@ -4,7 +4,7 @@ //[NOASSERT] compile-flags: -Coverflow-checks=off // CHECK-LABEL: define{{.*}} @assertion -// ASSERT: call void @_ZN4core9panicking5panic17h +// ASSERT: call void @{{.*4core9panicking5panic}} // NOASSERT: ret i8 0 #[no_mangle] pub fn assertion() -> u8 { 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} diff --git a/tests/codegen/var-names.rs b/tests/codegen/var-names.rs index d4715efad73..53841df32e8 100644 --- a/tests/codegen/var-names.rs +++ b/tests/codegen/var-names.rs @@ -9,7 +9,7 @@ pub fn test(a: u32, b: u32) -> u32 { // CHECK: %c = add i32 %a, %b let d = c; let e = d * a; - // CHECK-NEXT: %e = mul i32 %c, %a + // CHECK-NEXT: %0 = mul i32 %c, %a e - // CHECK-NEXT: ret i32 %e + // CHECK-NEXT: ret i32 %0 } diff --git a/tests/codegen/vec-as-ptr.rs b/tests/codegen/vec-as-ptr.rs new file mode 100644 index 00000000000..8ff7ba9cb64 --- /dev/null +++ b/tests/codegen/vec-as-ptr.rs @@ -0,0 +1,19 @@ +// compile-flags: -O -Zmerge-functions=disabled + +#![crate_type = "lib"] + +// Test that even though we return a *const u8 not a &[u8] or a NonNull<u8>, LLVM knows that this +// pointer is nonnull. +// CHECK: nonnull {{i8\*|ptr}} @vec_as_ptr +#[no_mangle] +pub fn vec_as_ptr(v: &Vec<u8>) -> *const u8 { + v.as_ptr() +} + +// Test that even though we return a *const u8 not a &[u8] or a NonNull<u8>, LLVM knows that this +// pointer is nonnull. +// CHECK: nonnull {{i8\*|ptr}} @vec_as_mut_ptr +#[no_mangle] +pub fn vec_as_mut_ptr(v: &mut Vec<u8>) -> *mut u8 { + v.as_mut_ptr() +} |
