Skip to content

Commit

Permalink
Add more tail call tests
Browse files Browse the repository at this point in the history
  • Loading branch information
WaffleLapkin committed Jun 15, 2023
1 parent c8b602a commit ced6c93
Show file tree
Hide file tree
Showing 6 changed files with 199 additions and 0 deletions.
28 changes: 28 additions & 0 deletions tests/codegen/explicit-tail-calls.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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)]
Expand Down Expand Up @@ -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(
Expand Down
20 changes: 20 additions & 0 deletions tests/ui/explicit-tail-calls/become-c-variadic.rs
Original file line number Diff line number Diff line change
@@ -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::<u32>(), args.arg::<u32>());
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::<u32>(), 1);
assert_eq!(args.arg::<u32>(), 2);
assert_eq!(args.arg::<u32>(), 3);
}

fn main() {
unsafe { c_variadic_f(12u8, 1u32, 2u32) };
}
18 changes: 18 additions & 0 deletions tests/ui/explicit-tail-calls/caller-location.rs
Original file line number Diff line number Diff line change
@@ -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()
}
25 changes: 25 additions & 0 deletions tests/ui/explicit-tail-calls/fibonacci.rs
Original file line number Diff line number Diff line change
@@ -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
);
}
74 changes: 74 additions & 0 deletions tests/ui/explicit-tail-calls/ll.rs
Original file line number Diff line number Diff line change
@@ -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<T> {
next: Option<Box<Node<T>>>,
}

struct Node<T> {
elem: T,
next: Option<Box<Node<T>>>,
}

impl<T> List<T> {
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<T> Node<T> {
fn rec_drop(self) {
if let Some(node) = self.next {
_ = node.elem;
become node.rec_drop()
}
}
}

fn p<T>(v: T) -> Option<Box<T>> {
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();
}
34 changes: 34 additions & 0 deletions tests/ui/explicit-tail-calls/slice-fold.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
// run-pass
#![feature(explicit_tail_calls)]

fn fold<T, S>(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);
}

0 comments on commit ced6c93

Please sign in to comment.