From ced6c93a73a16ac4c8dad7b005a9ae0e4fb79a3d Mon Sep 17 00:00:00 2001 From: Maybe Waffle Date: Thu, 15 Jun 2023 12:45:43 +0000 Subject: [PATCH] Add more tail call tests --- tests/codegen/explicit-tail-calls.rs | 28 +++++++ .../explicit-tail-calls/become-c-variadic.rs | 20 +++++ .../ui/explicit-tail-calls/caller-location.rs | 18 +++++ tests/ui/explicit-tail-calls/fibonacci.rs | 25 +++++++ tests/ui/explicit-tail-calls/ll.rs | 74 +++++++++++++++++++ tests/ui/explicit-tail-calls/slice-fold.rs | 34 +++++++++ 6 files changed, 199 insertions(+) create mode 100644 tests/ui/explicit-tail-calls/become-c-variadic.rs create mode 100644 tests/ui/explicit-tail-calls/caller-location.rs create mode 100644 tests/ui/explicit-tail-calls/fibonacci.rs create mode 100644 tests/ui/explicit-tail-calls/ll.rs create mode 100644 tests/ui/explicit-tail-calls/slice-fold.rs diff --git a/tests/codegen/explicit-tail-calls.rs b/tests/codegen/explicit-tail-calls.rs index 0faa3b25abbdf..ca41018521038 100644 --- a/tests/codegen/explicit-tail-calls.rs +++ b/tests/codegen/explicit-tail-calls.rs @@ -2,6 +2,7 @@ // min-llvm-version: 15.0 (for opaque pointers) #![crate_type = "lib"] #![feature(explicit_tail_calls)] +#![feature(c_variadic)] /// Something that is likely to be passed indirectly #[repr(C)] @@ -70,6 +71,33 @@ fn pair_g() -> (u32, u8) { } +#[no_mangle] +// CHECK-LABEL: @extern_c_f(i32 noundef %x) +pub extern "C" fn extern_c_f(x: u32) -> u8 { + unsafe { + // CHECK: %0 = musttail call noundef i8 @extern_c_g(i32 noundef %x) + // CHECK: ret i8 %0 + become extern_c_g(x); + } +} + +extern "C" { + fn extern_c_g(x: u32) -> u8; +} + + +#[no_mangle] +// CHECK-LABEL: @c_variadic_f(i8 noundef %x, ...) +pub unsafe extern "C" fn c_variadic_f(x: u8, ...) { + // CHECK: musttail call void (i8, ...) @c_variadic_g(i8 noundef %_3, ...) + // CHECK: ret void + become c_variadic_g(x + 1) +} + +#[no_mangle] +pub unsafe extern "C" fn c_variadic_g(_: u8, ...) {} + + #[no_mangle] /// Does `src + dst` in a recursive way // CHECK-LABEL: @flow( diff --git a/tests/ui/explicit-tail-calls/become-c-variadic.rs b/tests/ui/explicit-tail-calls/become-c-variadic.rs new file mode 100644 index 0000000000000..68a84f7b060a8 --- /dev/null +++ b/tests/ui/explicit-tail-calls/become-c-variadic.rs @@ -0,0 +1,20 @@ +// run-pass +#![feature(explicit_tail_calls)] +#![feature(c_variadic)] + +pub unsafe extern "C" fn c_variadic_f(x: u8, mut args: ...) { + assert_eq!(x, 12); + let (a, b) = (args.arg::(), args.arg::()); + become c_variadic_g(x + 1, a, b, 3u32); +} + +pub unsafe extern "C" fn c_variadic_g(x: u8, mut args: ...) { + assert_eq!(x, 13); + assert_eq!(args.arg::(), 1); + assert_eq!(args.arg::(), 2); + assert_eq!(args.arg::(), 3); +} + +fn main() { + unsafe { c_variadic_f(12u8, 1u32, 2u32) }; +} diff --git a/tests/ui/explicit-tail-calls/caller-location.rs b/tests/ui/explicit-tail-calls/caller-location.rs new file mode 100644 index 0000000000000..4f25c8dbdf330 --- /dev/null +++ b/tests/ui/explicit-tail-calls/caller-location.rs @@ -0,0 +1,18 @@ +// run-pass +#![feature(explicit_tail_calls)] +use std::panic::Location; + +fn main() { + assert_eq!(get_caller_location().line(), 6); + assert_eq!(get_caller_location().line(), 7); +} + +#[track_caller] +fn get_caller_location() -> &'static Location<'static> { + #[track_caller] + fn inner() -> &'static Location<'static> { + become Location::caller() + } + + become inner() +} diff --git a/tests/ui/explicit-tail-calls/fibonacci.rs b/tests/ui/explicit-tail-calls/fibonacci.rs new file mode 100644 index 0000000000000..f1f3eac180bda --- /dev/null +++ b/tests/ui/explicit-tail-calls/fibonacci.rs @@ -0,0 +1,25 @@ +// run-pass + +fn fibonacci(n: u32) -> u128 { + fibonacci_impl(n, 0, 1) +} + +fn fibonacci_impl(left: u32, prev_prev: u128, prev: u128) -> u128 { + match left { + 0 => prev_prev, + 1 => prev, + _ => fibonacci_impl(left - 1, prev, prev_prev + prev), + } +} + +fn main() { + let expected = + [0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144, 233, 377, 610, 987, 1597, 2584, 4181]; + assert!((0..20).map(fibonacci).eq(expected)); + + // This is the highest fibonacci number that fits in a u128 + assert_eq!( + std::hint::black_box(fibonacci(std::hint::black_box(186))), + 332825110087067562321196029789634457848 + ); +} diff --git a/tests/ui/explicit-tail-calls/ll.rs b/tests/ui/explicit-tail-calls/ll.rs new file mode 100644 index 0000000000000..4cc20d3b81cde --- /dev/null +++ b/tests/ui/explicit-tail-calls/ll.rs @@ -0,0 +1,74 @@ +// revisions: tail nose +//[tail] run-pass +//[nose] run-fail +#![feature(explicit_tail_calls)] + +fn main() { + with_smol_stack(|| List::from_elem((), 1024 * 32).rec_drop()); +} + +struct List { + next: Option>>, +} + +struct Node { + elem: T, + next: Option>>, +} + +impl List { + fn from_elem(elem: T, n: usize) -> Self + where + T: Clone, + { + List { next: None }.prepend_n(elem, n) + } + + fn prepend_n(self, elem: T, n: usize) -> Self + where + T: Clone, + { + match n { + 0 => self, + 1 => Self { next: p(Node { elem, next: self.next }) }, + _ => { + #[cfg(tail)] + become Self { next: p(Node { elem: elem.clone(), next: self.next }) } + .prepend_n(elem, n - 1); + + #[cfg(nose)] + return Self { next: p(Node { elem: elem.clone(), next: self.next }) } + .prepend_n(elem, n - 1); + } + } + } + + fn rec_drop(self) { + if let Some(node) = self.next { + node.rec_drop() + } + } +} + +impl Node { + fn rec_drop(self) { + if let Some(node) = self.next { + _ = node.elem; + become node.rec_drop() + } + } +} + +fn p(v: T) -> Option> { + Some(Box::new(v)) +} + +fn with_smol_stack(f: impl FnOnce() + Send + 'static) { + std::thread::Builder::new() + .stack_size(1024 /* bytes */) + .name("smol thread".to_owned()) + .spawn(f) + .unwrap() + .join() + .unwrap(); +} diff --git a/tests/ui/explicit-tail-calls/slice-fold.rs b/tests/ui/explicit-tail-calls/slice-fold.rs new file mode 100644 index 0000000000000..fb71d8fe25f76 --- /dev/null +++ b/tests/ui/explicit-tail-calls/slice-fold.rs @@ -0,0 +1,34 @@ +// run-pass +#![feature(explicit_tail_calls)] + +fn fold(slice: &[T], x: S, mut f: impl FnMut(S, &T) -> S) -> S { + match slice { + [] => x, + [head, tail @ ..] => become fold(tail, f(x, head), f), + } +} + +fn main() { + let numbers = [ + 11, 49, 81, 32, 33, 52, 121, 28, 64, 106, 99, 101, 110, 84, 123, 66, 80, 88, 94, 21, 65, + 85, 3, 54, 46, 69, 116, 26, 72, 114, 71, 86, 125, 70, 42, 68, 40, 91, 56, 22, 36, 115, 117, + 120, 18, 105, 30, 74, 63, 108, 43, 25, 122, 55, 104, 92, 12, 37, 20, 58, 35, 95, 98, 53, + 93, 100, 5, 112, 8, 78, 126, 102, 90, 97, 13, 51, 118, 62, 128, 34, 38, 4, 24, 6, 59, 48, + 44, 73, 7, 107, 61, 60, 14, 16, 111, 119, 96, 17, 57, 45, 15, 79, 10, 1, 124, 39, 9, 19, + 109, 127, 41, 47, 87, 76, 89, 50, 2, 23, 29, 27, 75, 103, 113, 77, 83, 67, 31, 82, 11, 71, + 67, 39, 64, 66, 100, 9, 92, 21, 35, 12, 6, 91, 62, 85, 13, 79, 98, 95, 30, 24, 38, 3, 78, + 99, 60, 25, 15, 82, 75, 97, 80, 2, 8, 16, 7, 19, 57, 26, 81, 33, 5, 47, 58, 68, 93, 52, 69, + 53, 49, 87, 73, 84, 76, 63, 48, 14, 34, 10, 56, 41, 20, 59, 96, 61, 42, 74, 88, 17, 43, 72, + 50, 37, 1, 70, 83, 45, 89, 90, 94, 18, 4, 31, 44, 36, 23, 29, 46, 55, 40, 77, 28, 32, 86, + 65, 54, 27, 22, 51, 8, 21, 36, 65, 66, 20, 6, 77, 94, 55, 32, 45, 12, 98, 28, 91, 64, 18, + 43, 70, 13, 73, 69, 85, 2, 39, 4, 11, 84, 71, 74, 23, 10, 40, 83, 9, 72, 62, 63, 25, 53, + 15, 96, 95, 68, 37, 79, 26, 76, 87, 89, 81, 51, 61, 5, 34, 44, 1, 46, 17, 86, 78, 82, 27, + 56, 41, 47, 90, 75, 92, 22, 50, 54, 97, 67, 57, 59, 42, 100, 35, 7, 24, 3, 19, 38, 58, 93, + 30, 49, 14, 99, 33, 48, 80, 31, 88, 52, 16, 29, 60, + ]; + + let expected = numbers.iter().sum(); + let res = fold(&numbers, 0, |s, &e| s + e); + + assert_eq!(res, expected); +}