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/gdb_debug_script_load.rs28
-rw-r--r--tests/codegen/hint/cold_path.rs54
-rw-r--r--tests/codegen/hint/likely.rs81
-rw-r--r--tests/codegen/hint/unlikely.rs80
-rw-r--r--tests/codegen/intrinsics/transmute-niched.rs122
-rw-r--r--tests/codegen/mainsubprogramstart.rs14
-rw-r--r--tests/codegen/overaligned-constant.rs2
-rw-r--r--tests/codegen/slice-init.rs55
-rw-r--r--tests/codegen/transmute-optimized.rs8
9 files changed, 366 insertions, 78 deletions
diff --git a/tests/codegen/gdb_debug_script_load.rs b/tests/codegen/gdb_debug_script_load.rs
index 30d518c0bcb..3e92eba10b1 100644
--- a/tests/codegen/gdb_debug_script_load.rs
+++ b/tests/codegen/gdb_debug_script_load.rs
@@ -4,14 +4,34 @@
 //@ ignore-wasm
 //@ ignore-emscripten
 
-//@ compile-flags: -g -C no-prepopulate-passes
+//@ compile-flags: -g -C no-prepopulate-passes -Cpanic=abort
 
-#![feature(start)]
+#![feature(lang_items)]
+#![no_std]
 
+#[panic_handler]
+fn panic_handler(_: &core::panic::PanicInfo) -> ! {
+    loop {}
+}
+
+#[no_mangle]
+extern "C" fn rust_eh_personality() {
+    loop {}
+}
+
+// Needs rustc to generate `main` as that's where the magic load is inserted.
+// IOW, we cannot write this test with `#![no_main]`.
 // CHECK-LABEL: @main
 // CHECK: load volatile i8, {{.+}} @__rustc_debug_gdb_scripts_section__
 
-#[start]
-fn start(_: isize, _: *const *const u8) -> isize {
+#[lang = "start"]
+fn lang_start<T: 'static>(
+    _main: fn() -> T,
+    _argc: isize,
+    _argv: *const *const u8,
+    _sigpipe: u8,
+) -> isize {
     return 0;
 }
+
+fn main() {}
diff --git a/tests/codegen/hint/cold_path.rs b/tests/codegen/hint/cold_path.rs
new file mode 100644
index 00000000000..dac72073f85
--- /dev/null
+++ b/tests/codegen/hint/cold_path.rs
@@ -0,0 +1,54 @@
+//@ compile-flags: -O
+#![crate_type = "lib"]
+#![feature(cold_path)]
+
+use std::hint::cold_path;
+
+#[inline(never)]
+#[no_mangle]
+pub fn path_a() {
+    println!("path a");
+}
+
+#[inline(never)]
+#[no_mangle]
+pub fn path_b() {
+    println!("path b");
+}
+
+#[no_mangle]
+pub fn test1(x: bool) {
+    if x {
+        path_a();
+    } else {
+        cold_path();
+        path_b();
+    }
+
+    // CHECK-LABEL: @test1(
+    // CHECK: br i1 %x, label %bb1, label %bb2, !prof ![[NUM:[0-9]+]]
+    // CHECK: bb2:
+    // CHECK: path_b
+    // CHECK: bb1:
+    // CHECK: path_a
+}
+
+#[no_mangle]
+pub fn test2(x: i32) {
+    match x > 0 {
+        true => path_a(),
+        false => {
+            cold_path();
+            path_b()
+        }
+    }
+
+    // CHECK-LABEL: @test2(
+    // CHECK: br i1 %_2, label %bb2, label %bb1, !prof ![[NUM]]
+    // CHECK: bb1:
+    // CHECK: path_b
+    // CHECK: bb2:
+    // CHECK: path_a
+}
+
+// CHECK: ![[NUM]] = !{!"branch_weights", {{(!"expected", )?}}i32 2000, i32 1}
diff --git a/tests/codegen/hint/likely.rs b/tests/codegen/hint/likely.rs
new file mode 100644
index 00000000000..2f589cc99d2
--- /dev/null
+++ b/tests/codegen/hint/likely.rs
@@ -0,0 +1,81 @@
+//@ compile-flags: -O
+#![crate_type = "lib"]
+#![feature(likely_unlikely)]
+
+use std::hint::likely;
+
+#[inline(never)]
+#[no_mangle]
+pub fn path_a() {
+    println!("path a");
+}
+
+#[inline(never)]
+#[no_mangle]
+pub fn path_b() {
+    println!("path b");
+}
+
+#[no_mangle]
+pub fn test1(x: bool) {
+    if likely(x) {
+        path_a();
+    } else {
+        path_b();
+    }
+
+    // CHECK-LABEL: @test1(
+    // CHECK: br i1 %x, label %bb2, label %bb3, !prof ![[NUM:[0-9]+]]
+    // CHECK: bb3:
+    // CHECK: path_b
+    // CHECK: bb2:
+    // CHECK: path_a
+}
+
+#[no_mangle]
+pub fn test2(x: i32) {
+    match likely(x > 0) {
+        true => path_a(),
+        false => path_b(),
+    }
+
+    // CHECK-LABEL: @test2(
+    // CHECK: br i1 %_2, label %bb2, label %bb3, !prof ![[NUM]]
+    // CHECK: bb3:
+    // CHECK: path_b
+    // CHECK: bb2:
+    // CHECK: path_a
+}
+
+#[no_mangle]
+pub fn test3(x: i8) {
+    match likely(x < 7) {
+        true => path_a(),
+        _ => path_b(),
+    }
+
+    // CHECK-LABEL: @test3(
+    // CHECK: br i1 %_2, label %bb2, label %bb3, !prof ![[NUM]]
+    // CHECK: bb3:
+    // CHECK: path_b
+    // CHECK: bb2:
+    // CHECK: path_a
+}
+
+#[no_mangle]
+pub fn test4(x: u64) {
+    match likely(x != 33) {
+        false => path_a(),
+        _ => path_b(),
+    }
+
+    // CHECK-LABEL: @test4(
+    // CHECK: br i1 %0, label %bb3, label %bb2, !prof ![[NUM2:[0-9]+]]
+    // CHECK: bb3:
+    // CHECK: path_a
+    // CHECK: bb2:
+    // CHECK: path_b
+}
+
+// CHECK: ![[NUM]] = !{!"branch_weights", {{(!"expected", )?}}i32 2000, i32 1}
+// CHECK: ![[NUM2]] = !{!"branch_weights", {{(!"expected", )?}}i32 1, i32 2000}
diff --git a/tests/codegen/hint/unlikely.rs b/tests/codegen/hint/unlikely.rs
new file mode 100644
index 00000000000..328533f3081
--- /dev/null
+++ b/tests/codegen/hint/unlikely.rs
@@ -0,0 +1,80 @@
+//@ compile-flags: -O
+#![crate_type = "lib"]
+#![feature(likely_unlikely)]
+
+use std::hint::unlikely;
+
+#[inline(never)]
+#[no_mangle]
+pub fn path_a() {
+    println!("path a");
+}
+
+#[inline(never)]
+#[no_mangle]
+pub fn path_b() {
+    println!("path b");
+}
+
+#[no_mangle]
+pub fn test1(x: bool) {
+    if unlikely(x) {
+        path_a();
+    } else {
+        path_b();
+    }
+
+    // CHECK-LABEL: @test1(
+    // CHECK: br i1 %x, label %bb2, label %bb4, !prof ![[NUM:[0-9]+]]
+    // CHECK: bb4:
+    // CHECK: path_b
+    // CHECK: bb2:
+    // CHECK: path_a
+}
+
+#[no_mangle]
+pub fn test2(x: i32) {
+    match unlikely(x > 0) {
+        true => path_a(),
+        false => path_b(),
+    }
+
+    // CHECK-LABEL: @test2(
+    // CHECK: br i1 %_2, label %bb2, label %bb4, !prof ![[NUM]]
+    // CHECK: bb4:
+    // CHECK: path_b
+    // CHECK: bb2:
+    // CHECK: path_a
+}
+
+#[no_mangle]
+pub fn test3(x: i8) {
+    match unlikely(x < 7) {
+        true => path_a(),
+        _ => path_b(),
+    }
+
+    // CHECK-LABEL: @test3(
+    // CHECK: br i1 %_2, label %bb2, label %bb4, !prof ![[NUM]]
+    // CHECK: bb4:
+    // CHECK: path_b
+    // CHECK: bb2:
+    // CHECK: path_a
+}
+
+#[no_mangle]
+pub fn test4(x: u64) {
+    match unlikely(x != 33) {
+        false => path_a(),
+        _ => path_b(),
+    }
+
+    // CHECK-LABEL: @test4(
+    // CHECK: br i1 %0, label %bb4, label %bb2, !prof ![[NUM2:[0-9]+]]
+    // CHECK: bb4:
+    // CHECK: path_a
+    // CHECK: bb2:
+    // CHECK: path_b
+}
+
+// CHECK: ![[NUM]] = !{!"branch_weights", {{(!"expected", )?}}i32 1, i32 2000}
diff --git a/tests/codegen/intrinsics/transmute-niched.rs b/tests/codegen/intrinsics/transmute-niched.rs
index f5b7bd2efea..88119ccb8b2 100644
--- a/tests/codegen/intrinsics/transmute-niched.rs
+++ b/tests/codegen/intrinsics/transmute-niched.rs
@@ -17,12 +17,13 @@ pub enum SmallEnum {
 // CHECK-LABEL: @check_to_enum(
 #[no_mangle]
 pub unsafe fn check_to_enum(x: i8) -> SmallEnum {
-    // OPT: %0 = icmp uge i8 %x, 10
-    // OPT: call void @llvm.assume(i1 %0)
-    // OPT: %1 = icmp ule i8 %x, 12
+    // CHECK-NOT: icmp
+    // CHECK-NOT: assume
+    // OPT: %0 = sub i8 %x, 10
+    // OPT: %1 = icmp ule i8 %0, 2
     // OPT: call void @llvm.assume(i1 %1)
-    // DBG-NOT: icmp
-    // DBG-NOT: assume
+    // CHECK-NOT: icmp
+    // CHECK-NOT: assume
     // CHECK: ret i8 %x
 
     transmute(x)
@@ -31,12 +32,13 @@ pub unsafe fn check_to_enum(x: i8) -> SmallEnum {
 // CHECK-LABEL: @check_from_enum(
 #[no_mangle]
 pub unsafe fn check_from_enum(x: SmallEnum) -> i8 {
-    // OPT: %0 = icmp uge i8 %x, 10
-    // OPT: call void @llvm.assume(i1 %0)
-    // OPT: %1 = icmp ule i8 %x, 12
+    // CHECK-NOT: icmp
+    // CHECK-NOT: assume
+    // OPT: %0 = sub i8 %x, 10
+    // OPT: %1 = icmp ule i8 %0, 2
     // OPT: call void @llvm.assume(i1 %1)
-    // DBG-NOT: icmp
-    // DBG-NOT: assume
+    // CHECK-NOT: icmp
+    // CHECK-NOT: assume
     // CHECK: ret i8 %x
 
     transmute(x)
@@ -45,12 +47,13 @@ pub unsafe fn check_from_enum(x: SmallEnum) -> i8 {
 // CHECK-LABEL: @check_to_ordering(
 #[no_mangle]
 pub unsafe fn check_to_ordering(x: u8) -> std::cmp::Ordering {
-    // OPT: %0 = icmp uge i8 %x, -1
-    // OPT: %1 = icmp ule i8 %x, 1
-    // OPT: %2 = or i1 %0, %1
-    // OPT: call void @llvm.assume(i1 %2)
-    // DBG-NOT: icmp
-    // DBG-NOT: assume
+    // CHECK-NOT: icmp
+    // CHECK-NOT: assume
+    // OPT: %0 = sub i8 %x, -1
+    // OPT: %1 = icmp ule i8 %0, 2
+    // OPT: call void @llvm.assume(i1 %1)
+    // CHECK-NOT: icmp
+    // CHECK-NOT: assume
     // CHECK: ret i8 %x
 
     transmute(x)
@@ -59,12 +62,13 @@ pub unsafe fn check_to_ordering(x: u8) -> std::cmp::Ordering {
 // CHECK-LABEL: @check_from_ordering(
 #[no_mangle]
 pub unsafe fn check_from_ordering(x: std::cmp::Ordering) -> u8 {
-    // OPT: %0 = icmp uge i8 %x, -1
-    // OPT: %1 = icmp ule i8 %x, 1
-    // OPT: %2 = or i1 %0, %1
-    // OPT: call void @llvm.assume(i1 %2)
-    // DBG-NOT: icmp
-    // DBG-NOT: assume
+    // CHECK-NOT: icmp
+    // CHECK-NOT: assume
+    // OPT: %0 = sub i8 %x, -1
+    // OPT: %1 = icmp ule i8 %0, 2
+    // OPT: call void @llvm.assume(i1 %1)
+    // CHECK-NOT: icmp
+    // CHECK-NOT: assume
     // CHECK: ret i8 %x
 
     transmute(x)
@@ -98,14 +102,15 @@ pub enum Minus100ToPlus100 {
 // CHECK-LABEL: @check_enum_from_char(
 #[no_mangle]
 pub unsafe fn check_enum_from_char(x: char) -> Minus100ToPlus100 {
+    // CHECK-NOT: icmp
+    // CHECK-NOT: assume
     // OPT: %0 = icmp ule i32 %x, 1114111
     // OPT: call void @llvm.assume(i1 %0)
-    // OPT: %1 = icmp uge i32 %x, -100
-    // OPT: %2 = icmp ule i32 %x, 100
-    // OPT: %3 = or i1 %1, %2
-    // OPT: call void @llvm.assume(i1 %3)
-    // DBG-NOT: icmp
-    // DBG-NOT: assume
+    // OPT: %1 = sub i32 %x, -100
+    // OPT: %2 = icmp ule i32 %1, 200
+    // OPT: call void @llvm.assume(i1 %2)
+    // CHECK-NOT: icmp
+    // CHECK-NOT: assume
     // CHECK: ret i32 %x
 
     transmute(x)
@@ -114,14 +119,15 @@ pub unsafe fn check_enum_from_char(x: char) -> Minus100ToPlus100 {
 // CHECK-LABEL: @check_enum_to_char(
 #[no_mangle]
 pub unsafe fn check_enum_to_char(x: Minus100ToPlus100) -> char {
-    // OPT: %0 = icmp uge i32 %x, -100
-    // OPT: %1 = icmp ule i32 %x, 100
-    // OPT: %2 = or i1 %0, %1
+    // CHECK-NOT: icmp
+    // CHECK-NOT: assume
+    // OPT: %0 = sub i32 %x, -100
+    // OPT: %1 = icmp ule i32 %0, 200
+    // OPT: call void @llvm.assume(i1 %1)
+    // OPT: %2 = icmp ule i32 %x, 1114111
     // OPT: call void @llvm.assume(i1 %2)
-    // OPT: %3 = icmp ule i32 %x, 1114111
-    // OPT: call void @llvm.assume(i1 %3)
-    // DBG-NOT: icmp
-    // DBG-NOT: assume
+    // CHECK-NOT: icmp
+    // CHECK-NOT: assume
     // CHECK: ret i32 %x
 
     transmute(x)
@@ -130,16 +136,20 @@ pub unsafe fn check_enum_to_char(x: Minus100ToPlus100) -> char {
 // CHECK-LABEL: @check_swap_pair(
 #[no_mangle]
 pub unsafe fn check_swap_pair(x: (char, NonZero<u32>)) -> (NonZero<u32>, char) {
+    // CHECK-NOT: icmp
+    // CHECK-NOT: assume
     // OPT: %0 = icmp ule i32 %x.0, 1114111
     // OPT: call void @llvm.assume(i1 %0)
-    // OPT: %1 = icmp uge i32 %x.0, 1
-    // OPT: call void @llvm.assume(i1 %1)
-    // OPT: %2 = icmp uge i32 %x.1, 1
+    // OPT: %1 = sub i32 %x.0, 1
+    // OPT: %2 = icmp ule i32 %1, -2
     // OPT: call void @llvm.assume(i1 %2)
-    // OPT: %3 = icmp ule i32 %x.1, 1114111
-    // OPT: call void @llvm.assume(i1 %3)
-    // DBG-NOT: icmp
-    // DBG-NOT: assume
+    // OPT: %3 = sub i32 %x.1, 1
+    // OPT: %4 = icmp ule i32 %3, -2
+    // OPT: call void @llvm.assume(i1 %4)
+    // OPT: %5 = icmp ule i32 %x.1, 1114111
+    // OPT: call void @llvm.assume(i1 %5)
+    // CHECK-NOT: icmp
+    // CHECK-NOT: assume
     // CHECK: %[[P1:.+]] = insertvalue { i32, i32 } poison, i32 %x.0, 0
     // CHECK: %[[P2:.+]] = insertvalue { i32, i32 } %[[P1]], i32 %x.1, 1
     // CHECK: ret { i32, i32 } %[[P2]]
@@ -150,14 +160,15 @@ pub unsafe fn check_swap_pair(x: (char, NonZero<u32>)) -> (NonZero<u32>, char) {
 // CHECK-LABEL: @check_bool_from_ordering(
 #[no_mangle]
 pub unsafe fn check_bool_from_ordering(x: std::cmp::Ordering) -> bool {
-    // OPT: %0 = icmp uge i8 %x, -1
-    // OPT: %1 = icmp ule i8 %x, 1
-    // OPT: %2 = or i1 %0, %1
+    // CHECK-NOT: icmp
+    // CHECK-NOT: assume
+    // OPT: %0 = sub i8 %x, -1
+    // OPT: %1 = icmp ule i8 %0, 2
+    // OPT: call void @llvm.assume(i1 %1)
+    // OPT: %2 = icmp ule i8 %x, 1
     // OPT: call void @llvm.assume(i1 %2)
-    // OPT: %3 = icmp ule i8 %x, 1
-    // OPT: call void @llvm.assume(i1 %3)
-    // DBG-NOT: icmp
-    // DBG-NOT: assume
+    // CHECK-NOT: icmp
+    // CHECK-NOT: assume
     // CHECK: %[[R:.+]] = trunc i8 %x to i1
     // CHECK: ret i1 %[[R]]
 
@@ -168,14 +179,15 @@ pub unsafe fn check_bool_from_ordering(x: std::cmp::Ordering) -> bool {
 #[no_mangle]
 pub unsafe fn check_bool_to_ordering(x: bool) -> std::cmp::Ordering {
     // CHECK: %_0 = zext i1 %x to i8
+    // CHECK-NOT: icmp
+    // CHECK-NOT: assume
     // OPT: %0 = icmp ule i8 %_0, 1
     // OPT: call void @llvm.assume(i1 %0)
-    // OPT: %1 = icmp uge i8 %_0, -1
-    // OPT: %2 = icmp ule i8 %_0, 1
-    // OPT: %3 = or i1 %1, %2
-    // OPT: call void @llvm.assume(i1 %3)
-    // DBG-NOT: icmp
-    // DBG-NOT: assume
+    // OPT: %1 = sub i8 %_0, -1
+    // OPT: %2 = icmp ule i8 %1, 2
+    // OPT: call void @llvm.assume(i1 %2)
+    // CHECK-NOT: icmp
+    // CHECK-NOT: assume
     // CHECK: ret i8 %_0
 
     transmute(x)
diff --git a/tests/codegen/mainsubprogramstart.rs b/tests/codegen/mainsubprogramstart.rs
deleted file mode 100644
index 0bcb311644d..00000000000
--- a/tests/codegen/mainsubprogramstart.rs
+++ /dev/null
@@ -1,14 +0,0 @@
-//@ ignore-apple
-//@ ignore-wasi wasi codegens the main symbol differently
-
-//@ compile-flags: -g -C no-prepopulate-passes
-
-#![feature(start)]
-
-// CHECK-LABEL: @main
-// CHECK: {{.*}}DISubprogram{{.*}}name: "start",{{.*}}DI{{(SP)?}}FlagMainSubprogram{{.*}}
-
-#[start]
-fn start(_: isize, _: *const *const u8) -> isize {
-    return 0;
-}
diff --git a/tests/codegen/overaligned-constant.rs b/tests/codegen/overaligned-constant.rs
index 7cd8d19c211..e5540aca387 100644
--- a/tests/codegen/overaligned-constant.rs
+++ b/tests/codegen/overaligned-constant.rs
@@ -17,8 +17,6 @@ pub fn overaligned_constant() {
     // CHECK-LABEL: @overaligned_constant
     // CHECK: [[full:%_.*]] = alloca [32 x i8], align 8
     // CHECK: call void @llvm.memcpy.p0.p0.i64(ptr align 8 [[full]], ptr align 8 @0, i64 32, i1 false)
-    // CHECK: %b.0 = load i32, ptr @0, align 4
-    // CHECK: %b.1 = load i32, ptr getelementptr inbounds ({{.*}}), align 4
     let mut s = S(1);
 
     s.0 = 3;
diff --git a/tests/codegen/slice-init.rs b/tests/codegen/slice-init.rs
index 1c2dd3e8875..b36a5b5de3d 100644
--- a/tests/codegen/slice-init.rs
+++ b/tests/codegen/slice-init.rs
@@ -2,6 +2,8 @@
 
 #![crate_type = "lib"]
 
+use std::mem::MaybeUninit;
+
 // CHECK-LABEL: @zero_sized_elem
 #[no_mangle]
 pub fn zero_sized_elem() {
@@ -76,17 +78,64 @@ pub fn u16_init_one_bytes() -> [u16; N] {
     [const { u16::from_be_bytes([1, 1]) }; N]
 }
 
-// FIXME: undef bytes can just be initialized with the same value as the
-// defined bytes, if the defines bytes are all the same.
 // CHECK-LABEL: @option_none_init
 #[no_mangle]
 pub fn option_none_init() -> [Option<u8>; N] {
     // CHECK-NOT: select
+    // CHECK-NOT: br
+    // CHECK-NOT: switch
+    // CHECK-NOT: icmp
+    // CHECK: call void @llvm.memset.p0
+    [const { None }; N]
+}
+
+// If there is partial provenance or some bytes are initialized and some are not,
+// we can't really do better than initialize bytes or groups of bytes together.
+// CHECK-LABEL: @option_maybe_uninit_init
+#[no_mangle]
+pub fn option_maybe_uninit_init() -> [MaybeUninit<u16>; N] {
+    // CHECK-NOT: select
+    // CHECK: br label %repeat_loop_header{{.*}}
+    // CHECK-NOT: switch
+    // CHECK: icmp
+    // CHECK-NOT: call void @llvm.memset.p0
+    [const {
+        let mut val: MaybeUninit<u16> = MaybeUninit::uninit();
+        let ptr = val.as_mut_ptr() as *mut u8;
+        unsafe {
+            ptr.write(0);
+        }
+        val
+    }; N]
+}
+
+#[repr(packed)]
+struct Packed {
+    start: u8,
+    ptr: &'static (),
+    rest: u16,
+    rest2: u8,
+}
+
+// If there is partial provenance or some bytes are initialized and some are not,
+// we can't really do better than initialize bytes or groups of bytes together.
+// CHECK-LABEL: @option_maybe_uninit_provenance
+#[no_mangle]
+pub fn option_maybe_uninit_provenance() -> [MaybeUninit<Packed>; N] {
+    // CHECK-NOT: select
     // CHECK: br label %repeat_loop_header{{.*}}
     // CHECK-NOT: switch
     // CHECK: icmp
     // CHECK-NOT: call void @llvm.memset.p0
-    [None; N]
+    [const {
+        let mut val: MaybeUninit<Packed> = MaybeUninit::uninit();
+        unsafe {
+            let ptr = &raw mut (*val.as_mut_ptr()).ptr;
+            static HAS_ADDR: () = ();
+            ptr.write_unaligned(&HAS_ADDR);
+        }
+        val
+    }; N]
 }
 
 // Use an opaque function to prevent rustc from removing useless drops.
diff --git a/tests/codegen/transmute-optimized.rs b/tests/codegen/transmute-optimized.rs
index 11bd0523788..de54eecf0c0 100644
--- a/tests/codegen/transmute-optimized.rs
+++ b/tests/codegen/transmute-optimized.rs
@@ -110,3 +110,11 @@ pub fn char_is_negative(c: char) -> bool {
     let x: i32 = unsafe { std::mem::transmute(c) };
     x < 0
 }
+
+// CHECK-LABEL: i1 @transmute_to_char_is_negative(i32
+#[no_mangle]
+pub fn transmute_to_char_is_negative(x: i32) -> bool {
+    // CHECK: ret i1 false
+    let _c: char = unsafe { std::mem::transmute(x) };
+    x < 0
+}