diff options
Diffstat (limited to 'tests/codegen/issues')
49 files changed, 1242 insertions, 0 deletions
diff --git a/tests/codegen/issues/auxiliary/static_dllimport_aux.rs b/tests/codegen/issues/auxiliary/static_dllimport_aux.rs new file mode 100644 index 000000000..afb0dc42f --- /dev/null +++ b/tests/codegen/issues/auxiliary/static_dllimport_aux.rs @@ -0,0 +1,13 @@ +use std::sync::atomic::{AtomicPtr, Ordering}; + +#[inline(always)] +pub fn memrchr() { + fn detect() {} + + static CROSS_CRATE_STATIC_ITEM: AtomicPtr<()> = AtomicPtr::new(detect as *mut ()); + + unsafe { + let fun = CROSS_CRATE_STATIC_ITEM.load(Ordering::SeqCst); + std::mem::transmute::<*mut (), fn()>(fun)() + } +} diff --git a/tests/codegen/issues/issue-101048.rs b/tests/codegen/issues/issue-101048.rs new file mode 100644 index 000000000..efa4db93e --- /dev/null +++ b/tests/codegen/issues/issue-101048.rs @@ -0,0 +1,13 @@ +// compile-flags: -O +// min-llvm-version: 16 + +#![crate_type = "lib"] + +#[no_mangle] +pub fn all_zero(data: &[u64]) -> bool { + // CHECK-LABEL: @all_zero( + // CHECK: [[PHI:%.*]] = phi i1 + // CHECK-NOT: phi i8 + // CHECK-NOT: zext + data.iter().copied().fold(true, |acc, x| acc & (x == 0)) +} diff --git a/tests/codegen/issues/issue-101082.rs b/tests/codegen/issues/issue-101082.rs new file mode 100644 index 000000000..2cbe99942 --- /dev/null +++ b/tests/codegen/issues/issue-101082.rs @@ -0,0 +1,17 @@ +// compile-flags: -O +// min-llvm-version: 16 +// ignore-debug: the debug assertions get in the way + +#![crate_type = "lib"] + +#[no_mangle] +pub fn test() -> usize { + // CHECK-LABEL: @test( + // CHECK: ret {{i64|i32}} 165 + let values = [23, 16, 54, 3, 60, 9]; + let mut acc = 0; + for item in values { + acc += item; + } + acc +} diff --git a/tests/codegen/issues/issue-101814.rs b/tests/codegen/issues/issue-101814.rs new file mode 100644 index 000000000..13796352c --- /dev/null +++ b/tests/codegen/issues/issue-101814.rs @@ -0,0 +1,20 @@ +// compile-flags: -O +// min-llvm-version: 16 +// ignore-debug: the debug assertions get in the way + +#![crate_type = "lib"] + +#[no_mangle] +pub fn test(a: [i32; 10]) -> i32 { + // CHECK-LABEL: @test( + // CHECK: [[L1:%.+]] = load i32 + // CHECK: [[L2:%.+]] = load i32 + // CHECK: [[R:%.+]] = add i32 [[L1]], [[L2]] + // CHECK: ret i32 [[R]] + let mut sum = 0; + for v in a.iter().skip(8) { + sum += v; + } + + sum +} diff --git a/tests/codegen/issues/issue-103132.rs b/tests/codegen/issues/issue-103132.rs new file mode 100644 index 000000000..cc87d7cd2 --- /dev/null +++ b/tests/codegen/issues/issue-103132.rs @@ -0,0 +1,16 @@ +// compile-flags: -O -C overflow-checks +// min-llvm-version: 16 + +#![crate_type = "lib"] + +#[no_mangle] +pub fn test(arr: &[u8], weight: u32) { + // CHECK-LABEL: @test( + // CHECK-NOT: panic + let weight = weight.min(256 * 256 * 256); + + for x in arr { + assert!(weight <= 256 * 256 * 256); + let result = *x as u32 * weight; + } +} diff --git a/tests/codegen/issues/issue-103285-ptr-addr-overflow-check.rs b/tests/codegen/issues/issue-103285-ptr-addr-overflow-check.rs new file mode 100644 index 000000000..a3499babe --- /dev/null +++ b/tests/codegen/issues/issue-103285-ptr-addr-overflow-check.rs @@ -0,0 +1,16 @@ +// compile-flags: -O -C debug-assertions=yes + +#![crate_type = "lib"] +#![feature(strict_provenance)] + +#[no_mangle] +pub fn test(src: *const u8, dst: *const u8) -> usize { + // CHECK-LABEL: @test( + // CHECK-NOT: panic + let src_usize = src.addr(); + let dst_usize = dst.addr(); + if src_usize > dst_usize { + return src_usize - dst_usize; + } + return 0; +} diff --git a/tests/codegen/issues/issue-103327.rs b/tests/codegen/issues/issue-103327.rs new file mode 100644 index 000000000..cee00facc --- /dev/null +++ b/tests/codegen/issues/issue-103327.rs @@ -0,0 +1,18 @@ +// compile-flags: -O +// min-llvm-version: 16 + +#![crate_type = "lib"] + +#[no_mangle] +pub fn test(a: i32, b: i32) -> bool { + // CHECK-LABEL: @test( + // CHECK: ret i1 true + let c1 = (a >= 0) && (a <= 10); + let c2 = (b >= 0) && (b <= 20); + + if c1 & c2 { + a + 100 != b + } else { + true + } +} diff --git a/tests/codegen/issues/issue-103840.rs b/tests/codegen/issues/issue-103840.rs new file mode 100644 index 000000000..f19d7031b --- /dev/null +++ b/tests/codegen/issues/issue-103840.rs @@ -0,0 +1,9 @@ +// compile-flags: -O +#![crate_type = "lib"] + +pub fn foo(t: &mut Vec<usize>) { + // CHECK-NOT: __rust_dealloc + let mut taken = std::mem::take(t); + taken.pop(); + *t = taken; +} diff --git a/tests/codegen/issues/issue-105386-ub-in-debuginfo.rs b/tests/codegen/issues/issue-105386-ub-in-debuginfo.rs new file mode 100644 index 000000000..d54ac9e33 --- /dev/null +++ b/tests/codegen/issues/issue-105386-ub-in-debuginfo.rs @@ -0,0 +1,22 @@ +// compile-flags: --crate-type=lib -O -Cdebuginfo=2 -Cno-prepopulate-passes +// min-llvm-version: 15.0 # this test uses opaque pointer notation +#![feature(stmt_expr_attributes)] + +pub struct S([usize; 8]); + +#[no_mangle] +pub fn outer_function(x: S, y: S) -> usize { + (#[inline(always)]|| { + let _z = x; + y.0[0] + })() +} + +// Check that we do not attempt to load from the spilled arg before it is assigned to +// when generating debuginfo. +// CHECK-LABEL: @outer_function +// CHECK: [[spill:%.*]] = alloca %"[closure@{{.*.rs}}:9:23: 9:25]" +// CHECK-NOT: [[ptr_tmp:%.*]] = getelementptr inbounds %"[closure@{{.*.rs}}:9:23: 9:25]", ptr [[spill]] +// CHECK-NOT: [[load:%.*]] = load ptr, ptr +// CHECK: call void @llvm.lifetime.start{{.*}}({{.*}}, ptr [[spill]]) +// CHECK: call void @llvm.memcpy{{.*}}(ptr {{align .*}} [[spill]], ptr {{align .*}} %x diff --git a/tests/codegen/issues/issue-106369.rs b/tests/codegen/issues/issue-106369.rs new file mode 100644 index 000000000..3fe7be4f1 --- /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-13018.rs b/tests/codegen/issues/issue-13018.rs new file mode 100644 index 000000000..b70ea1f48 --- /dev/null +++ b/tests/codegen/issues/issue-13018.rs @@ -0,0 +1,11 @@ +// compile-flags: -O + +// A drop([...].clone()) sequence on an Rc should be a no-op +// In particular, no call to __rust_dealloc should be emitted +#![crate_type = "lib"] +use std::rc::Rc; + +pub fn foo(t: &Rc<Vec<usize>>) { +// CHECK-NOT: __rust_dealloc + drop(t.clone()); +} diff --git a/tests/codegen/issues/issue-15953.rs b/tests/codegen/issues/issue-15953.rs new file mode 100644 index 000000000..28d284289 --- /dev/null +++ b/tests/codegen/issues/issue-15953.rs @@ -0,0 +1,29 @@ +// Test that llvm generates `memcpy` for moving a value +// inside a function and moving an argument. + +struct Foo { + x: Vec<i32>, +} + +#[inline(never)] +#[no_mangle] +// CHECK: memcpy +fn interior(x: Vec<i32>) -> Vec<i32> { + let Foo { x } = Foo { x: x }; + x +} + +#[inline(never)] +#[no_mangle] +// CHECK: memcpy +fn exterior(x: Vec<i32>) -> Vec<i32> { + x +} + +fn main() { + let x = interior(Vec::new()); + println!("{:?}", x); + + let x = exterior(Vec::new()); + println!("{:?}", x); +} diff --git a/tests/codegen/issues/issue-27130.rs b/tests/codegen/issues/issue-27130.rs new file mode 100644 index 000000000..e5ee94e1f --- /dev/null +++ b/tests/codegen/issues/issue-27130.rs @@ -0,0 +1,21 @@ +// compile-flags: -O + +#![crate_type = "lib"] + +// CHECK-LABEL: @trim_in_place +#[no_mangle] +pub fn trim_in_place(a: &mut &[u8]) { + while a.first() == Some(&42) { + // CHECK-NOT: slice_index_order_fail + *a = &a[1..]; + } +} + +// CHECK-LABEL: @trim_in_place2 +#[no_mangle] +pub fn trim_in_place2(a: &mut &[u8]) { + while let Some(&42) = a.first() { + // CHECK-NOT: slice_index_order_fail + *a = &a[2..]; + } +} diff --git a/tests/codegen/issues/issue-32031.rs b/tests/codegen/issues/issue-32031.rs new file mode 100644 index 000000000..abef92c19 --- /dev/null +++ b/tests/codegen/issues/issue-32031.rs @@ -0,0 +1,23 @@ +// compile-flags: -C no-prepopulate-passes -Copt-level=0 + +#![crate_type = "lib"] + +#[no_mangle] +pub struct F32(f32); + +// CHECK: define{{.*}}float @add_newtype_f32(float %a, float %b) +#[inline(never)] +#[no_mangle] +pub fn add_newtype_f32(a: F32, b: F32) -> F32 { + F32(a.0 + b.0) +} + +#[no_mangle] +pub struct F64(f64); + +// CHECK: define{{.*}}double @add_newtype_f64(double %a, double %b) +#[inline(never)] +#[no_mangle] +pub fn add_newtype_f64(a: F64, b: F64) -> F64 { + F64(a.0 + b.0) +} diff --git a/tests/codegen/issues/issue-32364.rs b/tests/codegen/issues/issue-32364.rs new file mode 100644 index 000000000..85493a4bb --- /dev/null +++ b/tests/codegen/issues/issue-32364.rs @@ -0,0 +1,18 @@ +// Test that `extern "stdcall"` is properly translated. + +// only-x86 + +// compile-flags: -C no-prepopulate-passes + +struct Foo; + +impl Foo { +// CHECK: define internal x86_stdcallcc void @{{.*}}foo{{.*}}() + #[inline(never)] + pub extern "stdcall" fn foo<T>() { + } +} + +fn main() { + Foo::foo::<Foo>(); +} diff --git a/tests/codegen/issues/issue-34634.rs b/tests/codegen/issues/issue-34634.rs new file mode 100644 index 000000000..f53fa240c --- /dev/null +++ b/tests/codegen/issues/issue-34634.rs @@ -0,0 +1,16 @@ +// Test that `wrapping_div` only checks divisor once. +// This test checks that there is only a single compare against -1 and -1 is not present as a +// switch case (the second check present until rustc 1.12). +// This test also verifies that a single panic call is generated (for the division by zero case). + +// compile-flags: -O +#![crate_type = "lib"] + +// CHECK-LABEL: @f +#[no_mangle] +pub fn f(x: i32, y: i32) -> i32 { + // CHECK-COUNT-1: icmp eq i32 %y, -1 + // CHECK-COUNT-1: panic + // CHECK-NOT: i32 -1, label + x.wrapping_div(y) +} diff --git a/tests/codegen/issues/issue-34947-pow-i32.rs b/tests/codegen/issues/issue-34947-pow-i32.rs new file mode 100644 index 000000000..653da8e8b --- /dev/null +++ b/tests/codegen/issues/issue-34947-pow-i32.rs @@ -0,0 +1,13 @@ +// compile-flags: -O + +#![crate_type = "lib"] + +// CHECK-LABEL: @issue_34947 +#[no_mangle] +pub fn issue_34947(x: i32) -> i32 { + // CHECK: mul + // CHECK-NEXT: mul + // CHECK-NEXT: mul + // CHECK-NEXT: ret + x.pow(5) +} diff --git a/tests/codegen/issues/issue-37945.rs b/tests/codegen/issues/issue-37945.rs new file mode 100644 index 000000000..4f386d335 --- /dev/null +++ b/tests/codegen/issues/issue-37945.rs @@ -0,0 +1,35 @@ +// compile-flags: -O -Zmerge-functions=disabled +// ignore-32bit LLVM has a bug with them +// ignore-debug + +// Check that LLVM understands that `Iter` pointer is not null. Issue #37945. + +#![crate_type = "lib"] + +use std::slice::Iter; + +#[no_mangle] +pub fn is_empty_1(xs: Iter<f32>) -> bool { +// CHECK-LABEL: @is_empty_1( +// CHECK-NEXT: start: +// CHECK-NEXT: [[A:%.*]] = icmp ne {{i32\*|ptr}} {{%xs.0|%xs.1}}, null +// CHECK-NEXT: tail call void @llvm.assume(i1 [[A]]) +// The order between %xs.0 and %xs.1 on the next line doesn't matter +// and different LLVM versions produce different order. +// CHECK-NEXT: [[B:%.*]] = icmp eq {{i32\*|ptr}} {{%xs.0, %xs.1|%xs.1, %xs.0}} +// CHECK-NEXT: ret i1 [[B:%.*]] + {xs}.next().is_none() +} + +#[no_mangle] +pub fn is_empty_2(xs: Iter<f32>) -> bool { +// CHECK-LABEL: @is_empty_2 +// CHECK-NEXT: start: +// CHECK-NEXT: [[C:%.*]] = icmp ne {{i32\*|ptr}} {{%xs.0|%xs.1}}, null +// CHECK-NEXT: tail call void @llvm.assume(i1 [[C]]) +// The order between %xs.0 and %xs.1 on the next line doesn't matter +// and different LLVM versions produce different order. +// CHECK-NEXT: [[D:%.*]] = icmp eq {{i32\*|ptr}} {{%xs.0, %xs.1|%xs.1, %xs.0}} +// CHECK-NEXT: ret i1 [[D:%.*]] + xs.map(|&x| x).next().is_none() +} diff --git a/tests/codegen/issues/issue-44056-macos-tls-align.rs b/tests/codegen/issues/issue-44056-macos-tls-align.rs new file mode 100644 index 000000000..1a3923f1b --- /dev/null +++ b/tests/codegen/issues/issue-44056-macos-tls-align.rs @@ -0,0 +1,28 @@ +// +// only-macos +// no-system-llvm +// compile-flags: -O + +#![crate_type = "rlib"] +#![feature(thread_local)] + +// local_unnamed_addr does not appear when std is built with debug assertions. +// CHECK: @STATIC_VAR_1 = thread_local {{(local_unnamed_addr )?}}global <{ [32 x i8] }> zeroinitializer, section "__DATA,__thread_bss", align 4 +#[no_mangle] +#[thread_local] +static mut STATIC_VAR_1: [u32; 8] = [0; 8]; + +// CHECK: @STATIC_VAR_2 = thread_local {{(local_unnamed_addr )?}}global <{ [32 x i8] }> <{{[^>]*}}>, section "__DATA,__thread_data", align 4 +#[no_mangle] +#[thread_local] +static mut STATIC_VAR_2: [u32; 8] = [4; 8]; + +#[no_mangle] +pub unsafe fn f(x: &mut [u32; 8]) { + std::mem::swap(x, &mut STATIC_VAR_1) +} + +#[no_mangle] +pub unsafe fn g(x: &mut [u32; 8]) { + std::mem::swap(x, &mut STATIC_VAR_2) +} diff --git a/tests/codegen/issues/issue-45222.rs b/tests/codegen/issues/issue-45222.rs new file mode 100644 index 000000000..e9b05e648 --- /dev/null +++ b/tests/codegen/issues/issue-45222.rs @@ -0,0 +1,63 @@ +// compile-flags: -O +// ignore-debug: the debug assertions get in the way + +#![crate_type = "lib"] + +// verify that LLVM recognizes a loop involving 0..=n and will const-fold it. + +// Example from original issue #45222 + +fn foo2(n: u64) -> u64 { + let mut count = 0; + for _ in 0..n { + for j in (0..=n).rev() { + count += j; + } + } + count +} + +// CHECK-LABEL: @check_foo2 +#[no_mangle] +pub fn check_foo2() -> u64 { + // CHECK: ret i64 500005000000000 + foo2(100000) +} + +// Simplified example of #45222 +// +// Temporarily disabled in #68835 to fix a soundness hole. +// +// fn triangle_inc(n: u64) -> u64 { +// let mut count = 0; +// for j in 0 ..= n { +// count += j; +// } +// count +// } +// +// // COMMENTEDCHECK-LABEL: @check_triangle_inc +// #[no_mangle] +// pub fn check_triangle_inc() -> u64 { +// // COMMENTEDCHECK: ret i64 5000050000 +// triangle_inc(100000) +// } + +// Demo in #48012 + +fn foo3r(n: u64) -> u64 { + let mut count = 0; + (0..n).for_each(|_| { + (0..=n).rev().for_each(|j| { + count += j; + }) + }); + count +} + +// CHECK-LABEL: @check_foo3r +#[no_mangle] +pub fn check_foo3r() -> u64 { + // CHECK: ret i64 500050000000 + foo3r(10000) +} diff --git a/tests/codegen/issues/issue-45466.rs b/tests/codegen/issues/issue-45466.rs new file mode 100644 index 000000000..c79542767 --- /dev/null +++ b/tests/codegen/issues/issue-45466.rs @@ -0,0 +1,15 @@ +// compile-flags: -O +// ignore-debug: the debug assertions get in the way + +#![crate_type="rlib"] + +// CHECK-LABEL: @memzero +// CHECK-NOT: store +// CHECK: call void @llvm.memset +// CHECK-NOT: store +#[no_mangle] +pub fn memzero(data: &mut [u8]) { + for i in 0..data.len() { + data[i] = 0; + } +} diff --git a/tests/codegen/issues/issue-45964-bounds-check-slice-pos.rs b/tests/codegen/issues/issue-45964-bounds-check-slice-pos.rs new file mode 100644 index 000000000..1daa213fc --- /dev/null +++ b/tests/codegen/issues/issue-45964-bounds-check-slice-pos.rs @@ -0,0 +1,39 @@ +// This test case checks that slice::{r}position functions do not +// prevent optimizing away bounds checks + +// compile-flags: -O +// ignore-debug: the debug assertions get in the way + +#![crate_type="rlib"] + +// CHECK-LABEL: @test +#[no_mangle] +pub fn test(y: &[u32], x: &u32, z: &u32) -> bool { + let result = match y.iter().position(|a| a == x) { + Some(p) => Ok(p), + None => Err(()), + }; + + if let Ok(p) = result { + // CHECK-NOT: panic + y[p] == *z + } else { + false + } +} + +// CHECK-LABEL: @rtest +#[no_mangle] +pub fn rtest(y: &[u32], x: &u32, z: &u32) -> bool { + let result = match y.iter().rposition(|a| a == x) { + Some(p) => Ok(p), + None => Err(()), + }; + + if let Ok(p) = result { + // CHECK-NOT: panic + y[p] == *z + } else { + false + } +} diff --git a/tests/codegen/issues/issue-47278.rs b/tests/codegen/issues/issue-47278.rs new file mode 100644 index 000000000..9076274f4 --- /dev/null +++ b/tests/codegen/issues/issue-47278.rs @@ -0,0 +1,9 @@ +// -C no-prepopulate-passes +#![crate_type="staticlib"] + +#[repr(C)] +pub struct Foo(u64); + +// CHECK: define {{.*}} @foo( +#[no_mangle] +pub extern "C" fn foo(_: Foo) -> Foo { loop {} } diff --git a/tests/codegen/issues/issue-47442.rs b/tests/codegen/issues/issue-47442.rs new file mode 100644 index 000000000..6944336d3 --- /dev/null +++ b/tests/codegen/issues/issue-47442.rs @@ -0,0 +1,22 @@ +// check that we don't emit unneeded `resume` cleanup blocks for every +// destructor. + +// CHECK-NOT: Unwind + +#![feature(test)] +#![crate_type="rlib"] + +extern crate test; + +struct Foo {} + +impl Drop for Foo { + fn drop(&mut self) { + test::black_box(()); + } +} + +#[no_mangle] +pub fn foo() { + let _foo = Foo {}; +} diff --git a/tests/codegen/issues/issue-56267-2.rs b/tests/codegen/issues/issue-56267-2.rs new file mode 100644 index 000000000..4dc9ebfeb --- /dev/null +++ b/tests/codegen/issues/issue-56267-2.rs @@ -0,0 +1,18 @@ +// compile-flags: -C no-prepopulate-passes + +#![crate_type="rlib"] + +#[allow(dead_code)] +pub struct Foo<T> { + foo: u64, + bar: T, +} + +// The load from bar.1 should have alignment 4. Not checking +// other loads here, as the alignment will be platform-dependent. + +// CHECK: %{{.+}} = load i32, {{i32\*|ptr}} %{{.+}}, align 4 +#[no_mangle] +pub fn test(x: Foo<(i32, i32)>) -> (i32, i32) { + x.bar +} diff --git a/tests/codegen/issues/issue-56267.rs b/tests/codegen/issues/issue-56267.rs new file mode 100644 index 000000000..7bdd25779 --- /dev/null +++ b/tests/codegen/issues/issue-56267.rs @@ -0,0 +1,18 @@ +// compile-flags: -C no-prepopulate-passes + +#![crate_type="rlib"] + +#[allow(dead_code)] +pub struct Foo<T> { + foo: u64, + bar: T, +} + +// The store writing to bar.1 should have alignment 4. Not checking +// other stores here, as the alignment will be platform-dependent. + +// CHECK: store i32 [[TMP1:%.+]], {{i32\*|ptr}} [[TMP2:%.+]], align 4 +#[no_mangle] +pub fn test(x: (i32, i32)) -> Foo<(i32, i32)> { + Foo { foo: 0, bar: x } +} diff --git a/tests/codegen/issues/issue-56927.rs b/tests/codegen/issues/issue-56927.rs new file mode 100644 index 000000000..044d72181 --- /dev/null +++ b/tests/codegen/issues/issue-56927.rs @@ -0,0 +1,43 @@ +// compile-flags: -C no-prepopulate-passes + +#![crate_type="rlib"] + +#[repr(align(16))] +pub struct S { + arr: [u32; 4], +} + +// CHECK-LABEL: @test1 +// CHECK: store i32 0, {{i32\*|ptr}} %{{.+}}, align 16 +// CHECK: store i32 1, {{i32\*|ptr}} %{{.+}}, align 4 +// CHECK: store i32 2, {{i32\*|ptr}} %{{.+}}, align 8 +// CHECK: store i32 3, {{i32\*|ptr}} %{{.+}}, align 4 +#[no_mangle] +pub fn test1(s: &mut S) { + s.arr[0] = 0; + s.arr[1] = 1; + s.arr[2] = 2; + s.arr[3] = 3; +} + +// CHECK-LABEL: @test2 +// CHECK: store i32 4, {{i32\*|ptr}} %{{.+}}, align 4 +#[allow(unconditional_panic)] +#[no_mangle] +pub fn test2(s: &mut S) { + s.arr[usize::MAX / 4 + 1] = 4; +} + +// CHECK-LABEL: @test3 +// CHECK: store i32 5, {{i32\*|ptr}} %{{.+}}, align 4 +#[no_mangle] +pub fn test3(s: &mut S, i: usize) { + s.arr[i] = 5; +} + +// CHECK-LABEL: @test4 +// CHECK: store i32 6, {{i32\*|ptr}} %{{.+}}, align 4 +#[no_mangle] +pub fn test4(s: &mut S) { + s.arr = [6; 4]; +} diff --git a/tests/codegen/issues/issue-58881.rs b/tests/codegen/issues/issue-58881.rs new file mode 100644 index 000000000..00f8953d9 --- /dev/null +++ b/tests/codegen/issues/issue-58881.rs @@ -0,0 +1,21 @@ +// compile-flags: -C no-prepopulate-passes -Copt-level=0 +// +// only-x86_64 +// ignore-windows + +#![crate_type = "lib"] + +extern "C" { + fn variadic_fn(_: i32, ...); +} + +#[repr(C)] +struct Foo(u8); +#[repr(C)] +struct Bar(u64, u64, u64); + +// Ensure that emit arguments of the correct type. +pub unsafe fn test_call_variadic() { + // CHECK: call void (i32, ...) @variadic_fn(i32 0, i8 {{.*}}, {{%Bar\*|ptr}} {{.*}}) + variadic_fn(0, Foo(0), Bar(0, 0, 0)) +} diff --git a/tests/codegen/issues/issue-59352.rs b/tests/codegen/issues/issue-59352.rs new file mode 100644 index 000000000..d271fe027 --- /dev/null +++ b/tests/codegen/issues/issue-59352.rs @@ -0,0 +1,18 @@ +// This test is a mirror of mir-opt/issues/issue-59352.rs. The LLVM inliner doesn't inline +// `char::method::is_digit()` and `char::method::to_digit()`, probably because of their size. +// +// Currently, the MIR optimizer isn't capable of removing the unreachable panic in this test case. +// Once the optimizer can do that, mir-opt/issues/issue-59352.rs will need to be updated and this +// test case should be removed as it will become redundant. + +// mir-opt-level=3 enables inlining and enables LLVM to optimize away the unreachable panic call. +// compile-flags: -O -Z mir-opt-level=3 + +#![crate_type = "rlib"] + +// CHECK-LABEL: @num_to_digit +#[no_mangle] +pub fn num_to_digit(num: char) -> u32 { + // CHECK-NOT: panic + if num.is_digit(8) { num.to_digit(8).unwrap() } else { 0 } +} diff --git a/tests/codegen/issues/issue-69101-bounds-check.rs b/tests/codegen/issues/issue-69101-bounds-check.rs new file mode 100644 index 000000000..a3aca3a29 --- /dev/null +++ b/tests/codegen/issues/issue-69101-bounds-check.rs @@ -0,0 +1,44 @@ +// no-system-llvm +// compile-flags: -O +// ignore-debug: the debug assertions get in the way +#![crate_type = "lib"] + +// Make sure no bounds checks are emitted in the loop when upfront slicing +// ensures that the slices are big enough. +// In particular, bounds checks were not always optimized out if the upfront +// check was for a greater len than the loop requires. +// (i.e. `already_sliced_no_bounds_check` was not always optimized even when +// `already_sliced_no_bounds_check_exact` was) +// CHECK-LABEL: @already_sliced_no_bounds_check +#[no_mangle] +pub fn already_sliced_no_bounds_check(a: &[u8], b: &[u8], c: &mut [u8]) { + // CHECK: slice_end_index_len_fail + // CHECK-NOT: panic_bounds_check + let _ = (&a[..2048], &b[..2048], &mut c[..2048]); + for i in 0..1024 { + c[i] = a[i] ^ b[i]; + } +} + +// CHECK-LABEL: @already_sliced_no_bounds_check_exact +#[no_mangle] +pub fn already_sliced_no_bounds_check_exact(a: &[u8], b: &[u8], c: &mut [u8]) { + // CHECK: slice_end_index_len_fail + // CHECK-NOT: panic_bounds_check + let _ = (&a[..1024], &b[..1024], &mut c[..1024]); + for i in 0..1024 { + c[i] = a[i] ^ b[i]; + } +} + +// Make sure we're checking for the right thing: there can be a panic if the slice is too small. +// CHECK-LABEL: @already_sliced_bounds_check +#[no_mangle] +pub fn already_sliced_bounds_check(a: &[u8], b: &[u8], c: &mut [u8]) { + // CHECK: slice_end_index_len_fail + // CHECK: panic_bounds_check + let _ = (&a[..1023], &b[..2048], &mut c[..2048]); + for i in 0..1024 { + c[i] = a[i] ^ b[i]; + } +} diff --git a/tests/codegen/issues/issue-73031.rs b/tests/codegen/issues/issue-73031.rs new file mode 100644 index 000000000..a09c4bcfb --- /dev/null +++ b/tests/codegen/issues/issue-73031.rs @@ -0,0 +1,26 @@ +// compile-flags: -O +#![crate_type = "lib"] + +// Test that LLVM can eliminate the unreachable `All::None` branch. + +pub enum All { + None, + Foo, + Bar, +} + +// CHECK-LABEL: @issue_73031 +#[no_mangle] +pub fn issue_73031(a: &mut All, q: i32) -> i32 { + *a = if q == 5 { + All::Foo + } else { + All::Bar + }; + match *a { + // CHECK-NOT: panic + All::None => panic!(), + All::Foo => 1, + All::Bar => 2, + } +} diff --git a/tests/codegen/issues/issue-73258.rs b/tests/codegen/issues/issue-73258.rs new file mode 100644 index 000000000..0134f929b --- /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/issues/issue-73338-effecient-cmp.rs b/tests/codegen/issues/issue-73338-effecient-cmp.rs new file mode 100644 index 000000000..85c2bbfd0 --- /dev/null +++ b/tests/codegen/issues/issue-73338-effecient-cmp.rs @@ -0,0 +1,39 @@ +// This test checks that comparison operation +// generated by #[derive(PartialOrd)] +// doesn't contain jumps for C enums + +// compile-flags: -Copt-level=3 + +#![crate_type="lib"] + +#[repr(u32)] +#[derive(Copy, Clone, Eq, PartialEq, PartialOrd)] +pub enum Foo { + Zero, + One, + Two, +} + +#[no_mangle] +pub fn compare_less(a: Foo, b: Foo)->bool{ + // CHECK-NOT: br {{.*}} + a < b +} + +#[no_mangle] +pub fn compare_le(a: Foo, b: Foo)->bool{ + // CHECK-NOT: br {{.*}} + a <= b +} + +#[no_mangle] +pub fn compare_ge(a: Foo, b: Foo)->bool{ + // CHECK-NOT: br {{.*}} + a >= b +} + +#[no_mangle] +pub fn compare_greater(a: Foo, b: Foo)->bool{ + // CHECK-NOT: br {{.*}} + a > b +} diff --git a/tests/codegen/issues/issue-73396-bounds-check-after-position.rs b/tests/codegen/issues/issue-73396-bounds-check-after-position.rs new file mode 100644 index 000000000..8d07a67a1 --- /dev/null +++ b/tests/codegen/issues/issue-73396-bounds-check-after-position.rs @@ -0,0 +1,77 @@ +// compile-flags: -O +// ignore-debug: the debug assertions get in the way +#![crate_type = "lib"] + +// Make sure no bounds checks are emitted when slicing or indexing +// with an index from `position()` or `rposition()`. + +// CHECK-LABEL: @position_slice_to_no_bounds_check +#[no_mangle] +pub fn position_slice_to_no_bounds_check(s: &[u8]) -> &[u8] { + // CHECK-NOT: panic + // CHECK-NOT: slice_index_len_fail + if let Some(idx) = s.iter().position(|b| *b == b'\\') { + &s[..idx] + } else { + s + } +} + +// CHECK-LABEL: @position_slice_from_no_bounds_check +#[no_mangle] +pub fn position_slice_from_no_bounds_check(s: &[u8]) -> &[u8] { + // CHECK-NOT: panic + // CHECK-NOT: slice_index_len_fail + if let Some(idx) = s.iter().position(|b| *b == b'\\') { + &s[idx..] + } else { + s + } +} + +// CHECK-LABEL: @position_index_no_bounds_check +#[no_mangle] +pub fn position_index_no_bounds_check(s: &[u8]) -> u8 { + // CHECK-NOT: panic + // CHECK-NOT: slice_index_len_fail + if let Some(idx) = s.iter().position(|b| *b == b'\\') { + s[idx] + } else { + 42 + } +} +// CHECK-LABEL: @rposition_slice_to_no_bounds_check +#[no_mangle] +pub fn rposition_slice_to_no_bounds_check(s: &[u8]) -> &[u8] { + // CHECK-NOT: panic + // CHECK-NOT: slice_index_len_fail + if let Some(idx) = s.iter().rposition(|b| *b == b'\\') { + &s[..idx] + } else { + s + } +} + +// CHECK-LABEL: @rposition_slice_from_no_bounds_check +#[no_mangle] +pub fn rposition_slice_from_no_bounds_check(s: &[u8]) -> &[u8] { + // CHECK-NOT: panic + // CHECK-NOT: slice_index_len_fail + if let Some(idx) = s.iter().rposition(|b| *b == b'\\') { + &s[idx..] + } else { + s + } +} + +// CHECK-LABEL: @rposition_index_no_bounds_check +#[no_mangle] +pub fn rposition_index_no_bounds_check(s: &[u8]) -> u8 { + // CHECK-NOT: panic + // CHECK-NOT: slice_index_len_fail + if let Some(idx) = s.iter().rposition(|b| *b == b'\\') { + s[idx] + } else { + 42 + } +} diff --git a/tests/codegen/issues/issue-73827-bounds-check-index-in-subexpr.rs b/tests/codegen/issues/issue-73827-bounds-check-index-in-subexpr.rs new file mode 100644 index 000000000..1ad05906e --- /dev/null +++ b/tests/codegen/issues/issue-73827-bounds-check-index-in-subexpr.rs @@ -0,0 +1,17 @@ +// This test checks that bounds checks are elided when +// index is part of a (x | y) < C style condition + +// compile-flags: -O + +#![crate_type = "lib"] + +// CHECK-LABEL: @get +#[no_mangle] +pub fn get(array: &[u8; 8], x: usize, y: usize) -> u8 { + if x > 7 || y > 7 { + 0 + } else { + // CHECK-NOT: panic_bounds_check + array[y] + } +} diff --git a/tests/codegen/issues/issue-75525-bounds-checks.rs b/tests/codegen/issues/issue-75525-bounds-checks.rs new file mode 100644 index 000000000..2d363d8f7 --- /dev/null +++ b/tests/codegen/issues/issue-75525-bounds-checks.rs @@ -0,0 +1,26 @@ +// Regression test for #75525, verifies that no bounds checks are generated. + +// compile-flags: -O + +#![crate_type = "lib"] + +// CHECK-LABEL: @f0 +// CHECK-NOT: panic +#[no_mangle] +pub fn f0(idx: usize, buf: &[u8; 10]) -> u8 { + if idx < 8 { buf[idx + 1] } else { 0 } +} + +// CHECK-LABEL: @f1 +// CHECK-NOT: panic +#[no_mangle] +pub fn f1(idx: usize, buf: &[u8; 10]) -> u8 { + if idx > 5 && idx < 8 { buf[idx - 1] } else { 0 } +} + +// CHECK-LABEL: @f2 +// CHECK-NOT: panic +#[no_mangle] +pub fn f2(idx: usize, buf: &[u8; 10]) -> u8 { + if idx > 5 && idx < 8 { buf[idx] } else { 0 } +} diff --git a/tests/codegen/issues/issue-75546.rs b/tests/codegen/issues/issue-75546.rs new file mode 100644 index 000000000..470a9e040 --- /dev/null +++ b/tests/codegen/issues/issue-75546.rs @@ -0,0 +1,15 @@ +// compile-flags: -O +#![crate_type = "lib"] + +// Test that LLVM can eliminate the impossible `i == 0` check. + +// CHECK-LABEL: @issue_75546 +#[no_mangle] +pub fn issue_75546() { + let mut i = 1u32; + while i < u32::MAX { + // CHECK-NOT: panic + if i == 0 { panic!(); } + i += 1; + } +} diff --git a/tests/codegen/issues/issue-75659.rs b/tests/codegen/issues/issue-75659.rs new file mode 100644 index 000000000..9394868c0 --- /dev/null +++ b/tests/codegen/issues/issue-75659.rs @@ -0,0 +1,63 @@ +// This test checks that the call to memchr/slice_contains is optimized away +// when searching in small slices. + +// compile-flags: -O -Zinline-mir=false +// only-x86_64 + +#![crate_type = "lib"] + +// CHECK-LABEL: @foo1 +#[no_mangle] +pub fn foo1(x: u8, data: &[u8; 1]) -> bool { + // CHECK-NOT: memchr + // CHECK-NOT: slice_contains + data.contains(&x) +} + +// CHECK-LABEL: @foo2 +#[no_mangle] +pub fn foo2(x: u8, data: &[u8; 2]) -> bool { + // CHECK-NOT: memchr + // CHECK-NOT: slice_contains + data.contains(&x) +} + +// CHECK-LABEL: @foo3 +#[no_mangle] +pub fn foo3(x: u8, data: &[u8; 3]) -> bool { + // CHECK-NOT: memchr + // CHECK-NOT: slice_contains + data.contains(&x) +} + +// CHECK-LABEL: @foo4 +#[no_mangle] +pub fn foo4(x: u8, data: &[u8; 4]) -> bool { + // CHECK-NOT: memchr + // CHECK-NOT: slice_contains + data.contains(&x) +} + +// CHECK-LABEL: @foo8 +#[no_mangle] +pub fn foo8(x: u8, data: &[u8; 8]) -> bool { + // CHECK-NOT: memchr + // CHECK-NOT: slice_contains + data.contains(&x) +} + +// CHECK-LABEL: @foo8_i8 +#[no_mangle] +pub fn foo8_i8(x: i8, data: &[i8; 8]) -> bool { + // CHECK-NOT: memchr + // CHECK-NOT: slice_contains + !data.contains(&x) +} + +// Check that the general case isn't inlined +// CHECK-LABEL: @foo80 +#[no_mangle] +pub fn foo80(x: u8, data: &[u8; 80]) -> bool { + // CHECK: call core::slice::memchr + data.contains(&x) +} diff --git a/tests/codegen/issues/issue-75978.rs b/tests/codegen/issues/issue-75978.rs new file mode 100644 index 000000000..f335e92c3 --- /dev/null +++ b/tests/codegen/issues/issue-75978.rs @@ -0,0 +1,19 @@ +// compile-flags: -O +// min-llvm-version: 16 + +#![crate_type = "lib"] + +#[no_mangle] +pub fn test() -> u32 { + // CHECK-LABEL: @test( + // CHECK: ret i32 13 + let s = [1, 2, 3, 4, 5, 6, 7]; + + let mut iter = s.iter(); + let mut sum = 0; + while let Some(_) = iter.next() { + sum += iter.next().map_or(1, |&x| x) + } + + sum +} diff --git a/tests/codegen/issues/issue-77812.rs b/tests/codegen/issues/issue-77812.rs new file mode 100644 index 000000000..4cc824145 --- /dev/null +++ b/tests/codegen/issues/issue-77812.rs @@ -0,0 +1,32 @@ +// compile-flags: -O +#![crate_type = "lib"] + +// Test that LLVM can eliminate the unreachable `Variant::Zero` branch. + +#[derive(Copy, Clone, Eq, PartialEq)] +pub enum Variant { + Zero, + One, + Two, +} + +extern { + fn exf1(); + fn exf2(); +} + +pub static mut GLOBAL: Variant = Variant::Zero; + +// CHECK-LABEL: @issue_77812 +#[no_mangle] +pub unsafe fn issue_77812() { + let g = GLOBAL; + if g != Variant::Zero { + match g { + Variant::One => exf1(), + Variant::Two => exf2(), + // CHECK-NOT: panic + Variant::Zero => panic!(), + } + } +} diff --git a/tests/codegen/issues/issue-81408-dllimport-thinlto-windows.rs b/tests/codegen/issues/issue-81408-dllimport-thinlto-windows.rs new file mode 100644 index 000000000..0b6ab4f7e --- /dev/null +++ b/tests/codegen/issues/issue-81408-dllimport-thinlto-windows.rs @@ -0,0 +1,15 @@ +// compile-flags: -O -C lto=thin -C prefer-dynamic=no +// only-windows +// aux-build:static_dllimport_aux.rs + +// Test that on Windows, when performing ThinLTO, we do not mark cross-crate static items with +// dllimport because lld does not fix the symbol names for us. + +extern crate static_dllimport_aux; + +// CHECK-LABEL: @{{.+}}CROSS_CRATE_STATIC_ITEM{{.+}} = +// CHECK-SAME: external local_unnamed_addr global %"{{.+}}AtomicPtr + +pub fn main() { + static_dllimport_aux::memrchr(); +} diff --git a/tests/codegen/issues/issue-84268.rs b/tests/codegen/issues/issue-84268.rs new file mode 100644 index 000000000..7ca195447 --- /dev/null +++ b/tests/codegen/issues/issue-84268.rs @@ -0,0 +1,23 @@ +// compile-flags: -O --crate-type=rlib +#![feature(platform_intrinsics, repr_simd)] + +extern "platform-intrinsic" { + fn simd_fabs<T>(x: T) -> T; + fn simd_eq<T, U>(x: T, y: T) -> U; +} + +#[repr(simd)] +pub struct V([f32; 4]); + +#[repr(simd)] +pub struct M([i32; 4]); + +#[no_mangle] +// CHECK-LABEL: @is_infinite +pub fn is_infinite(v: V) -> M { + // CHECK: fabs + // CHECK: cmp oeq + unsafe { + simd_eq(simd_fabs(v), V([f32::INFINITY; 4])) + } +} diff --git a/tests/codegen/issues/issue-85872-multiple-reverse.rs b/tests/codegen/issues/issue-85872-multiple-reverse.rs new file mode 100644 index 000000000..591a1aca7 --- /dev/null +++ b/tests/codegen/issues/issue-85872-multiple-reverse.rs @@ -0,0 +1,20 @@ +// min-llvm-version: 15.0.0 +// compile-flags: -O + +#![crate_type = "lib"] + +#[no_mangle] +pub fn u16_be_to_arch(mut data: [u8; 2]) -> [u8; 2] { + // CHECK-LABEL: @u16_be_to_arch + // CHECK: @llvm.bswap.i16 + data.reverse(); + data +} + +#[no_mangle] +pub fn u32_be_to_arch(mut data: [u8; 4]) -> [u8; 4] { + // CHECK-LABEL: @u32_be_to_arch + // CHECK: @llvm.bswap.i32 + data.reverse(); + data +} diff --git a/tests/codegen/issues/issue-86106.rs b/tests/codegen/issues/issue-86106.rs new file mode 100644 index 000000000..9ccbcb24f --- /dev/null +++ b/tests/codegen/issues/issue-86106.rs @@ -0,0 +1,62 @@ +// min-llvm-version: 15.0 +// compile-flags: -C opt-level=3 -Z merge-functions=disabled + +// The below two functions ensure that both `String::new()` and `"".to_string()` +// produce the identical code. + +#![crate_type = "lib"] + +// CHECK-LABEL: define void @string_new +#[no_mangle] +pub fn string_new() -> String { + // CHECK-NOT: load i8 + // CHECK: store i{{32|64}} + // CHECK-NEXT: getelementptr + // CHECK-NEXT: store ptr + // CHECK-NEXT: getelementptr + // CHECK-NEXT: store i{{32|64}} + // CHECK-NEXT: ret void + String::new() +} + +// CHECK-LABEL: define void @empty_to_string +#[no_mangle] +pub fn empty_to_string() -> String { + // CHECK-NOT: load i8 + // CHECK: store i{{32|64}} + // CHECK-NEXT: getelementptr + // CHECK-NEXT: store ptr + // CHECK-NEXT: getelementptr + // CHECK-NEXT: store i{{32|64}} + // CHECK-NEXT: ret void + "".to_string() +} + +// The below two functions ensure that both `vec![]` and `vec![].clone()` +// produce the identical code. + +// CHECK-LABEL: @empty_vec +#[no_mangle] +pub fn empty_vec() -> Vec<u8> { + // CHECK: store i{{32|64}} + // CHECK-NOT: load i8 + // CHECK-NEXT: getelementptr + // CHECK-NEXT: store ptr + // CHECK-NEXT: getelementptr + // CHECK-NEXT: store i{{32|64}} + // CHECK-NEXT: ret void + vec![] +} + +// CHECK-LABEL: @empty_vec_clone +#[no_mangle] +pub fn empty_vec_clone() -> Vec<u8> { + // CHECK: store i{{32|64}} + // CHECK-NOT: load i8 + // CHECK-NEXT: getelementptr + // CHECK-NEXT: store ptr + // CHECK-NEXT: getelementptr + // CHECK-NEXT: store i{{32|64}} + // CHECK-NEXT: ret void + vec![].clone() +} diff --git a/tests/codegen/issues/issue-96274.rs b/tests/codegen/issues/issue-96274.rs new file mode 100644 index 000000000..28bfcce0d --- /dev/null +++ b/tests/codegen/issues/issue-96274.rs @@ -0,0 +1,17 @@ +// min-llvm-version: 15.0 +// compile-flags: -O + +#![crate_type = "lib"] +#![feature(inline_const)] + +use std::mem::MaybeUninit; + +pub fn maybe_uninit() -> [MaybeUninit<u8>; 3000] { + // CHECK-NOT: memset + [MaybeUninit::uninit(); 3000] +} + +pub fn maybe_uninit_const<T>() -> [MaybeUninit<T>; 8192] { + // CHECK-NOT: memset + [const { MaybeUninit::uninit() }; 8192] +} diff --git a/tests/codegen/issues/issue-96497-slice-size-nowrap.rs b/tests/codegen/issues/issue-96497-slice-size-nowrap.rs new file mode 100644 index 000000000..0413ed6b2 --- /dev/null +++ b/tests/codegen/issues/issue-96497-slice-size-nowrap.rs @@ -0,0 +1,29 @@ +// This test case checks that LLVM is aware that computing the size of a slice cannot wrap. +// The possibility of wrapping results in an additional branch when dropping boxed slices +// in some situations, see https://github.com/rust-lang/rust/issues/96497#issuecomment-1112865218 + +// compile-flags: -O +// min-llvm-version: 15.0 + +#![crate_type="lib"] + +// CHECK-LABEL: @simple_size_of_nowrap +#[no_mangle] +pub fn simple_size_of_nowrap(x: &[u32]) -> usize { + // Make sure the shift used to compute the size has a nowrap flag. + + // CHECK: [[A:%.*]] = shl nsw {{.*}}, 2 + // CHECK-NEXT: ret {{.*}} [[A]] + core::mem::size_of_val(x) +} + +// CHECK-LABEL: @drop_write +#[no_mangle] +pub fn drop_write(mut x: Box<[u32]>) { + // Check that this write is optimized out. + // This depends on the size calculation not wrapping, + // since otherwise LLVM can't tell that the memory is always deallocated if the slice len > 0. + + // CHECK-NOT: store i32 42 + x[1] = 42; +} diff --git a/tests/codegen/issues/issue-98156-const-arg-temp-lifetime.rs b/tests/codegen/issues/issue-98156-const-arg-temp-lifetime.rs new file mode 100644 index 000000000..12ace5fff --- /dev/null +++ b/tests/codegen/issues/issue-98156-const-arg-temp-lifetime.rs @@ -0,0 +1,27 @@ +// This test checks that temporaries for indirectly-passed arguments get lifetime markers. + +// compile-flags: -O -C no-prepopulate-passes -Zmir-opt-level=0 + +#![crate_type = "lib"] + +extern "Rust" { + fn f(x: [u8; 1024]); +} + +const A: [u8; 1024] = [0; 1024]; + +// CHECK-LABEL: @const_arg_indirect +#[no_mangle] +pub unsafe fn const_arg_indirect() { + // Ensure that the live ranges for the two argument temporaries don't overlap. + + // CHECK: call void @llvm.lifetime.start + // CHECK: call void @f + // CHECK: call void @llvm.lifetime.end + // CHECK: call void @llvm.lifetime.start + // CHECK: call void @f + // CHECK: call void @llvm.lifetime.end + + f(A); + f(A); +} diff --git a/tests/codegen/issues/issue-98294-get-mut-copy-from-slice-opt.rs b/tests/codegen/issues/issue-98294-get-mut-copy-from-slice-opt.rs new file mode 100644 index 000000000..7da29cd79 --- /dev/null +++ b/tests/codegen/issues/issue-98294-get-mut-copy-from-slice-opt.rs @@ -0,0 +1,19 @@ +// min-llvm-version: 15.0.0 +// ignore-debug: The debug assertions get in the way +// compile-flags: -O + +#![crate_type = "lib"] + +// There should be no calls to panic / len_mismatch_fail. + +#[no_mangle] +pub fn test(a: &mut [u8], offset: usize, bytes: &[u8]) { + // CHECK-LABEL: @test( + // CHECK-NOT: call + // CHECK: call void @llvm.memcpy + // CHECK-NOT: call + // CHECK: } + if let Some(dst) = a.get_mut(offset..offset + bytes.len()) { + dst.copy_from_slice(bytes); + } +} diff --git a/tests/codegen/issues/issue-99960.rs b/tests/codegen/issues/issue-99960.rs new file mode 100644 index 000000000..e9c9367fa --- /dev/null +++ b/tests/codegen/issues/issue-99960.rs @@ -0,0 +1,15 @@ +// compile-flags: -O +// min-llvm-version: 16 + +#![crate_type = "lib"] + +#[no_mangle] +pub fn test(dividend: i64, divisor: i64) -> Option<i64> { + // CHECK-LABEL: @test( + // CHECK-NOT: panic + if dividend > i64::min_value() && divisor != 0 { + Some(dividend / divisor) + } else { + None + } +} |