Inline FnOnce once again
This commit is contained in:
parent
e081b7b77e
commit
d33946c3ab
23 changed files with 391 additions and 116 deletions
|
@ -625,13 +625,6 @@ fn try_inlining<'tcx, I: Inliner<'tcx>>(
|
||||||
return Err("implementation limitation -- return type mismatch");
|
return Err("implementation limitation -- return type mismatch");
|
||||||
}
|
}
|
||||||
if callsite.fn_sig.abi() == ExternAbi::RustCall {
|
if callsite.fn_sig.abi() == ExternAbi::RustCall {
|
||||||
// FIXME: Don't inline user-written `extern "rust-call"` functions,
|
|
||||||
// since this is generally perf-negative on rustc, and we hope that
|
|
||||||
// LLVM will inline these functions instead.
|
|
||||||
if callee_body.spread_arg.is_some() {
|
|
||||||
return Err("user-written rust-call functions");
|
|
||||||
}
|
|
||||||
|
|
||||||
let (self_arg, arg_tuple) = match &args[..] {
|
let (self_arg, arg_tuple) = match &args[..] {
|
||||||
[arg_tuple] => (None, arg_tuple),
|
[arg_tuple] => (None, arg_tuple),
|
||||||
[self_arg, arg_tuple] => (Some(self_arg), arg_tuple),
|
[self_arg, arg_tuple] => (Some(self_arg), arg_tuple),
|
||||||
|
@ -641,18 +634,23 @@ fn try_inlining<'tcx, I: Inliner<'tcx>>(
|
||||||
let self_arg_ty = self_arg.map(|self_arg| self_arg.node.ty(&caller_body.local_decls, tcx));
|
let self_arg_ty = self_arg.map(|self_arg| self_arg.node.ty(&caller_body.local_decls, tcx));
|
||||||
|
|
||||||
let arg_tuple_ty = arg_tuple.node.ty(&caller_body.local_decls, tcx);
|
let arg_tuple_ty = arg_tuple.node.ty(&caller_body.local_decls, tcx);
|
||||||
|
let arg_tys = if callee_body.spread_arg.is_some() {
|
||||||
|
std::slice::from_ref(&arg_tuple_ty)
|
||||||
|
} else {
|
||||||
let ty::Tuple(arg_tuple_tys) = *arg_tuple_ty.kind() else {
|
let ty::Tuple(arg_tuple_tys) = *arg_tuple_ty.kind() else {
|
||||||
bug!("Closure arguments are not passed as a tuple");
|
bug!("Closure arguments are not passed as a tuple");
|
||||||
};
|
};
|
||||||
|
arg_tuple_tys.as_slice()
|
||||||
|
};
|
||||||
|
|
||||||
for (arg_ty, input) in
|
for (arg_ty, input) in
|
||||||
self_arg_ty.into_iter().chain(arg_tuple_tys).zip(callee_body.args_iter())
|
self_arg_ty.into_iter().chain(arg_tys.iter().copied()).zip(callee_body.args_iter())
|
||||||
{
|
{
|
||||||
let input_type = callee_body.local_decls[input].ty;
|
let input_type = callee_body.local_decls[input].ty;
|
||||||
if !util::sub_types(tcx, inliner.typing_env(), input_type, arg_ty) {
|
if !util::sub_types(tcx, inliner.typing_env(), input_type, arg_ty) {
|
||||||
trace!(?arg_ty, ?input_type);
|
trace!(?arg_ty, ?input_type);
|
||||||
debug!("failed to normalize tuple argument type");
|
debug!("failed to normalize tuple argument type");
|
||||||
return Err("implementation limitation -- arg mismatch");
|
return Err("implementation limitation");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
@ -1059,8 +1057,7 @@ fn make_call_args<'tcx, I: Inliner<'tcx>>(
|
||||||
|
|
||||||
closure_ref_arg.chain(tuple_tmp_args).collect()
|
closure_ref_arg.chain(tuple_tmp_args).collect()
|
||||||
} else {
|
} else {
|
||||||
// FIXME(edition_2024): switch back to a normal method call.
|
args.into_iter()
|
||||||
<_>::into_iter(args)
|
|
||||||
.map(|a| create_temp_if_necessary(inliner, a.node, callsite, caller_body, return_block))
|
.map(|a| create_temp_if_necessary(inliner, a.node, callsite, caller_body, return_block))
|
||||||
.collect()
|
.collect()
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,23 +7,42 @@
|
||||||
let mut _0: ();
|
let mut _0: ();
|
||||||
let mut _3: &mut std::boxed::Box<dyn std::ops::FnMut<I, Output = ()>>;
|
let mut _3: &mut std::boxed::Box<dyn std::ops::FnMut<I, Output = ()>>;
|
||||||
let mut _4: I;
|
let mut _4: I;
|
||||||
|
+ scope 1 (inlined <Box<dyn FnMut<I, Output = ()>> as FnMut<I>>::call_mut) {
|
||||||
|
+ let mut _5: &mut dyn std::ops::FnMut<I, Output = ()>;
|
||||||
|
+ let mut _6: std::boxed::Box<dyn std::ops::FnMut<I, Output = ()>>;
|
||||||
|
+ let mut _7: *const dyn std::ops::FnMut<I, Output = ()>;
|
||||||
|
+ }
|
||||||
|
|
||||||
bb0: {
|
bb0: {
|
||||||
StorageLive(_3);
|
StorageLive(_3);
|
||||||
_3 = &mut _1;
|
_3 = &mut _1;
|
||||||
StorageLive(_4);
|
StorageLive(_4);
|
||||||
_4 = move _2;
|
_4 = move _2;
|
||||||
_0 = <Box<dyn FnMut<I, Output = ()>> as FnMut<I>>::call_mut(move _3, move _4) -> [return: bb1, unwind unreachable];
|
- _0 = <Box<dyn FnMut<I, Output = ()>> as FnMut<I>>::call_mut(move _3, move _4) -> [return: bb1, unwind unreachable];
|
||||||
|
+ StorageLive(_6);
|
||||||
|
+ StorageLive(_7);
|
||||||
|
+ StorageLive(_5);
|
||||||
|
+ _6 = copy (*_3);
|
||||||
|
+ _7 = copy ((_6.0: std::ptr::Unique<dyn std::ops::FnMut<I, Output = ()>>).0: std::ptr::NonNull<dyn std::ops::FnMut<I, Output = ()>>) as *const dyn std::ops::FnMut<I, Output = ()> (Transmute);
|
||||||
|
+ _5 = &mut (*_7);
|
||||||
|
+ _0 = <dyn FnMut<I, Output = ()> as FnMut<I>>::call_mut(move _5, move _4) -> [return: bb2, unwind unreachable];
|
||||||
}
|
}
|
||||||
|
|
||||||
bb1: {
|
bb1: {
|
||||||
StorageDead(_4);
|
- StorageDead(_4);
|
||||||
StorageDead(_3);
|
- StorageDead(_3);
|
||||||
drop(_1) -> [return: bb2, unwind unreachable];
|
- drop(_1) -> [return: bb2, unwind unreachable];
|
||||||
|
+ return;
|
||||||
}
|
}
|
||||||
|
|
||||||
bb2: {
|
bb2: {
|
||||||
return;
|
- return;
|
||||||
|
+ StorageDead(_5);
|
||||||
|
+ StorageDead(_7);
|
||||||
|
+ StorageDead(_6);
|
||||||
|
+ StorageDead(_4);
|
||||||
|
+ StorageDead(_3);
|
||||||
|
+ drop(_1) -> [return: bb1, unwind unreachable];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -7,31 +7,54 @@
|
||||||
let mut _0: ();
|
let mut _0: ();
|
||||||
let mut _3: &mut std::boxed::Box<dyn std::ops::FnMut<I, Output = ()>>;
|
let mut _3: &mut std::boxed::Box<dyn std::ops::FnMut<I, Output = ()>>;
|
||||||
let mut _4: I;
|
let mut _4: I;
|
||||||
|
+ scope 1 (inlined <Box<dyn FnMut<I, Output = ()>> as FnMut<I>>::call_mut) {
|
||||||
|
+ let mut _5: &mut dyn std::ops::FnMut<I, Output = ()>;
|
||||||
|
+ let mut _6: std::boxed::Box<dyn std::ops::FnMut<I, Output = ()>>;
|
||||||
|
+ let mut _7: *const dyn std::ops::FnMut<I, Output = ()>;
|
||||||
|
+ }
|
||||||
|
|
||||||
bb0: {
|
bb0: {
|
||||||
StorageLive(_3);
|
StorageLive(_3);
|
||||||
_3 = &mut _1;
|
_3 = &mut _1;
|
||||||
StorageLive(_4);
|
StorageLive(_4);
|
||||||
_4 = move _2;
|
_4 = move _2;
|
||||||
_0 = <Box<dyn FnMut<I, Output = ()>> as FnMut<I>>::call_mut(move _3, move _4) -> [return: bb1, unwind: bb3];
|
- _0 = <Box<dyn FnMut<I, Output = ()>> as FnMut<I>>::call_mut(move _3, move _4) -> [return: bb1, unwind: bb3];
|
||||||
|
+ StorageLive(_6);
|
||||||
|
+ StorageLive(_7);
|
||||||
|
+ StorageLive(_5);
|
||||||
|
+ _6 = copy (*_3);
|
||||||
|
+ _7 = copy ((_6.0: std::ptr::Unique<dyn std::ops::FnMut<I, Output = ()>>).0: std::ptr::NonNull<dyn std::ops::FnMut<I, Output = ()>>) as *const dyn std::ops::FnMut<I, Output = ()> (Transmute);
|
||||||
|
+ _5 = &mut (*_7);
|
||||||
|
+ _0 = <dyn FnMut<I, Output = ()> as FnMut<I>>::call_mut(move _5, move _4) -> [return: bb4, unwind: bb2];
|
||||||
}
|
}
|
||||||
|
|
||||||
bb1: {
|
bb1: {
|
||||||
StorageDead(_4);
|
- StorageDead(_4);
|
||||||
StorageDead(_3);
|
- StorageDead(_3);
|
||||||
drop(_1) -> [return: bb2, unwind: bb4];
|
- drop(_1) -> [return: bb2, unwind: bb4];
|
||||||
|
+ return;
|
||||||
}
|
}
|
||||||
|
|
||||||
bb2: {
|
- bb2: {
|
||||||
return;
|
- return;
|
||||||
|
+ bb2 (cleanup): {
|
||||||
|
+ drop(_1) -> [return: bb3, unwind terminate(cleanup)];
|
||||||
}
|
}
|
||||||
|
|
||||||
bb3 (cleanup): {
|
bb3 (cleanup): {
|
||||||
drop(_1) -> [return: bb4, unwind terminate(cleanup)];
|
- drop(_1) -> [return: bb4, unwind terminate(cleanup)];
|
||||||
|
+ resume;
|
||||||
}
|
}
|
||||||
|
|
||||||
bb4 (cleanup): {
|
- bb4 (cleanup): {
|
||||||
resume;
|
- resume;
|
||||||
|
+ bb4: {
|
||||||
|
+ StorageDead(_5);
|
||||||
|
+ StorageDead(_7);
|
||||||
|
+ StorageDead(_6);
|
||||||
|
+ StorageDead(_4);
|
||||||
|
+ StorageDead(_3);
|
||||||
|
+ drop(_1) -> [return: bb1, unwind: bb3];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -8,6 +8,6 @@ use std::marker::Tuple;
|
||||||
// EMIT_MIR dont_ice_on_generic_rust_call.call.Inline.diff
|
// EMIT_MIR dont_ice_on_generic_rust_call.call.Inline.diff
|
||||||
pub fn call<I: Tuple>(mut mock: Box<dyn FnMut<I, Output = ()>>, input: I) {
|
pub fn call<I: Tuple>(mut mock: Box<dyn FnMut<I, Output = ()>>, input: I) {
|
||||||
// CHECK-LABEL: fn call(
|
// CHECK-LABEL: fn call(
|
||||||
// CHECK-NOT: inlined
|
// CHECK: (inlined <Box<dyn FnMut<I, Output = ()>> as FnMut<I>>::call_mut)
|
||||||
mock.call_mut(input)
|
mock.call_mut(input)
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,6 +7,11 @@
|
||||||
let _2: ();
|
let _2: ();
|
||||||
let mut _3: &std::boxed::Box<dyn std::ops::Fn(i32)>;
|
let mut _3: &std::boxed::Box<dyn std::ops::Fn(i32)>;
|
||||||
let mut _4: (i32,);
|
let mut _4: (i32,);
|
||||||
|
+ scope 1 (inlined <Box<dyn Fn(i32)> as Fn<(i32,)>>::call) {
|
||||||
|
+ let mut _5: &dyn std::ops::Fn(i32);
|
||||||
|
+ let mut _6: std::boxed::Box<dyn std::ops::Fn(i32)>;
|
||||||
|
+ let mut _7: *const dyn std::ops::Fn(i32);
|
||||||
|
+ }
|
||||||
|
|
||||||
bb0: {
|
bb0: {
|
||||||
StorageLive(_2);
|
StorageLive(_2);
|
||||||
|
@ -14,19 +19,34 @@
|
||||||
_3 = &_1;
|
_3 = &_1;
|
||||||
StorageLive(_4);
|
StorageLive(_4);
|
||||||
_4 = (const 1_i32,);
|
_4 = (const 1_i32,);
|
||||||
_2 = <Box<dyn Fn(i32)> as Fn<(i32,)>>::call(move _3, move _4) -> [return: bb1, unwind unreachable];
|
- _2 = <Box<dyn Fn(i32)> as Fn<(i32,)>>::call(move _3, move _4) -> [return: bb1, unwind unreachable];
|
||||||
|
+ StorageLive(_6);
|
||||||
|
+ StorageLive(_7);
|
||||||
|
+ StorageLive(_5);
|
||||||
|
+ _6 = copy (*_3);
|
||||||
|
+ _7 = copy ((_6.0: std::ptr::Unique<dyn std::ops::Fn(i32)>).0: std::ptr::NonNull<dyn std::ops::Fn(i32)>) as *const dyn std::ops::Fn(i32) (Transmute);
|
||||||
|
+ _5 = &(*_7);
|
||||||
|
+ _2 = <dyn Fn(i32) as Fn<(i32,)>>::call(move _5, move _4) -> [return: bb2, unwind unreachable];
|
||||||
}
|
}
|
||||||
|
|
||||||
bb1: {
|
bb1: {
|
||||||
|
+ return;
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ bb2: {
|
||||||
|
+ StorageDead(_5);
|
||||||
|
+ StorageDead(_7);
|
||||||
|
+ StorageDead(_6);
|
||||||
StorageDead(_4);
|
StorageDead(_4);
|
||||||
StorageDead(_3);
|
StorageDead(_3);
|
||||||
StorageDead(_2);
|
StorageDead(_2);
|
||||||
_0 = const ();
|
_0 = const ();
|
||||||
drop(_1) -> [return: bb2, unwind unreachable];
|
- drop(_1) -> [return: bb2, unwind unreachable];
|
||||||
}
|
- }
|
||||||
|
-
|
||||||
bb2: {
|
- bb2: {
|
||||||
return;
|
- return;
|
||||||
|
+ drop(_1) -> [return: bb1, unwind unreachable];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -7,6 +7,11 @@
|
||||||
let _2: ();
|
let _2: ();
|
||||||
let mut _3: &std::boxed::Box<dyn std::ops::Fn(i32)>;
|
let mut _3: &std::boxed::Box<dyn std::ops::Fn(i32)>;
|
||||||
let mut _4: (i32,);
|
let mut _4: (i32,);
|
||||||
|
+ scope 1 (inlined <Box<dyn Fn(i32)> as Fn<(i32,)>>::call) {
|
||||||
|
+ let mut _5: &dyn std::ops::Fn(i32);
|
||||||
|
+ let mut _6: std::boxed::Box<dyn std::ops::Fn(i32)>;
|
||||||
|
+ let mut _7: *const dyn std::ops::Fn(i32);
|
||||||
|
+ }
|
||||||
|
|
||||||
bb0: {
|
bb0: {
|
||||||
StorageLive(_2);
|
StorageLive(_2);
|
||||||
|
@ -14,27 +19,47 @@
|
||||||
_3 = &_1;
|
_3 = &_1;
|
||||||
StorageLive(_4);
|
StorageLive(_4);
|
||||||
_4 = (const 1_i32,);
|
_4 = (const 1_i32,);
|
||||||
_2 = <Box<dyn Fn(i32)> as Fn<(i32,)>>::call(move _3, move _4) -> [return: bb1, unwind: bb3];
|
- _2 = <Box<dyn Fn(i32)> as Fn<(i32,)>>::call(move _3, move _4) -> [return: bb1, unwind: bb3];
|
||||||
|
+ StorageLive(_6);
|
||||||
|
+ StorageLive(_7);
|
||||||
|
+ StorageLive(_5);
|
||||||
|
+ _6 = copy (*_3);
|
||||||
|
+ _7 = copy ((_6.0: std::ptr::Unique<dyn std::ops::Fn(i32)>).0: std::ptr::NonNull<dyn std::ops::Fn(i32)>) as *const dyn std::ops::Fn(i32) (Transmute);
|
||||||
|
+ _5 = &(*_7);
|
||||||
|
+ _2 = <dyn Fn(i32) as Fn<(i32,)>>::call(move _5, move _4) -> [return: bb4, unwind: bb2];
|
||||||
}
|
}
|
||||||
|
|
||||||
bb1: {
|
bb1: {
|
||||||
StorageDead(_4);
|
- StorageDead(_4);
|
||||||
StorageDead(_3);
|
- StorageDead(_3);
|
||||||
StorageDead(_2);
|
- StorageDead(_2);
|
||||||
_0 = const ();
|
- _0 = const ();
|
||||||
drop(_1) -> [return: bb2, unwind: bb4];
|
- drop(_1) -> [return: bb2, unwind: bb4];
|
||||||
|
+ return;
|
||||||
}
|
}
|
||||||
|
|
||||||
bb2: {
|
- bb2: {
|
||||||
return;
|
- return;
|
||||||
|
+ bb2 (cleanup): {
|
||||||
|
+ drop(_1) -> [return: bb3, unwind terminate(cleanup)];
|
||||||
}
|
}
|
||||||
|
|
||||||
bb3 (cleanup): {
|
bb3 (cleanup): {
|
||||||
drop(_1) -> [return: bb4, unwind terminate(cleanup)];
|
- drop(_1) -> [return: bb4, unwind terminate(cleanup)];
|
||||||
|
+ resume;
|
||||||
}
|
}
|
||||||
|
|
||||||
bb4 (cleanup): {
|
- bb4 (cleanup): {
|
||||||
resume;
|
- resume;
|
||||||
|
+ bb4: {
|
||||||
|
+ StorageDead(_5);
|
||||||
|
+ StorageDead(_7);
|
||||||
|
+ StorageDead(_6);
|
||||||
|
+ StorageDead(_4);
|
||||||
|
+ StorageDead(_3);
|
||||||
|
+ StorageDead(_2);
|
||||||
|
+ _0 = const ();
|
||||||
|
+ drop(_1) -> [return: bb1, unwind: bb3];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -5,6 +5,6 @@
|
||||||
// EMIT_MIR inline_box_fn.call.Inline.diff
|
// EMIT_MIR inline_box_fn.call.Inline.diff
|
||||||
fn call(x: Box<dyn Fn(i32)>) {
|
fn call(x: Box<dyn Fn(i32)>) {
|
||||||
// CHECK-LABEL: fn call(
|
// CHECK-LABEL: fn call(
|
||||||
// CHECK-NOT: inlined
|
// CHECK: (inlined <Box<dyn Fn(i32)> as Fn<(i32,)>>::call)
|
||||||
x(1);
|
x(1);
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,9 +5,15 @@
|
||||||
let mut _0: ();
|
let mut _0: ();
|
||||||
let _1: ();
|
let _1: ();
|
||||||
+ let mut _2: fn() {f};
|
+ let mut _2: fn() {f};
|
||||||
|
+ let mut _4: ();
|
||||||
+ scope 1 (inlined call::<fn() {f}>) {
|
+ scope 1 (inlined call::<fn() {f}>) {
|
||||||
+ debug f => _2;
|
+ debug f => _2;
|
||||||
+ let _3: ();
|
+ let _3: ();
|
||||||
|
+ scope 2 (inlined <fn() {f} as FnOnce<()>>::call_once - shim(fn() {f})) {
|
||||||
|
+ scope 3 (inlined f) {
|
||||||
|
+ let _5: ();
|
||||||
|
+ }
|
||||||
|
+ }
|
||||||
+ }
|
+ }
|
||||||
|
|
||||||
bb0: {
|
bb0: {
|
||||||
|
@ -16,10 +22,15 @@
|
||||||
+ StorageLive(_2);
|
+ StorageLive(_2);
|
||||||
+ _2 = f;
|
+ _2 = f;
|
||||||
+ StorageLive(_3);
|
+ StorageLive(_3);
|
||||||
+ _3 = <fn() {f} as FnOnce<()>>::call_once(move _2, const ()) -> [return: bb1, unwind unreachable];
|
+ StorageLive(_4);
|
||||||
|
+ _4 = const ();
|
||||||
|
+ StorageLive(_5);
|
||||||
|
+ _5 = call::<fn() {f}>(f) -> [return: bb1, unwind unreachable];
|
||||||
}
|
}
|
||||||
|
|
||||||
bb1: {
|
bb1: {
|
||||||
|
+ StorageDead(_5);
|
||||||
|
+ StorageDead(_4);
|
||||||
+ StorageDead(_3);
|
+ StorageDead(_3);
|
||||||
+ StorageDead(_2);
|
+ StorageDead(_2);
|
||||||
StorageDead(_1);
|
StorageDead(_1);
|
||||||
|
|
|
@ -5,9 +5,15 @@
|
||||||
let mut _0: ();
|
let mut _0: ();
|
||||||
let _1: ();
|
let _1: ();
|
||||||
+ let mut _2: fn() {f};
|
+ let mut _2: fn() {f};
|
||||||
|
+ let mut _4: ();
|
||||||
+ scope 1 (inlined call::<fn() {f}>) {
|
+ scope 1 (inlined call::<fn() {f}>) {
|
||||||
+ debug f => _2;
|
+ debug f => _2;
|
||||||
+ let _3: ();
|
+ let _3: ();
|
||||||
|
+ scope 2 (inlined <fn() {f} as FnOnce<()>>::call_once - shim(fn() {f})) {
|
||||||
|
+ scope 3 (inlined f) {
|
||||||
|
+ let _5: ();
|
||||||
|
+ }
|
||||||
|
+ }
|
||||||
+ }
|
+ }
|
||||||
|
|
||||||
bb0: {
|
bb0: {
|
||||||
|
@ -16,10 +22,15 @@
|
||||||
+ StorageLive(_2);
|
+ StorageLive(_2);
|
||||||
+ _2 = f;
|
+ _2 = f;
|
||||||
+ StorageLive(_3);
|
+ StorageLive(_3);
|
||||||
+ _3 = <fn() {f} as FnOnce<()>>::call_once(move _2, const ()) -> [return: bb1, unwind continue];
|
+ StorageLive(_4);
|
||||||
|
+ _4 = const ();
|
||||||
|
+ StorageLive(_5);
|
||||||
|
+ _5 = call::<fn() {f}>(f) -> [return: bb1, unwind continue];
|
||||||
}
|
}
|
||||||
|
|
||||||
bb1: {
|
bb1: {
|
||||||
|
+ StorageDead(_5);
|
||||||
|
+ StorageDead(_4);
|
||||||
+ StorageDead(_3);
|
+ StorageDead(_3);
|
||||||
+ StorageDead(_2);
|
+ StorageDead(_2);
|
||||||
StorageDead(_1);
|
StorageDead(_1);
|
||||||
|
|
|
@ -5,6 +5,7 @@
|
||||||
let mut _0: ();
|
let mut _0: ();
|
||||||
let _1: (!, !);
|
let _1: (!, !);
|
||||||
+ let mut _2: fn() -> ! {sleep};
|
+ let mut _2: fn() -> ! {sleep};
|
||||||
|
+ let mut _7: ();
|
||||||
+ scope 1 (inlined call_twice::<!, fn() -> ! {sleep}>) {
|
+ scope 1 (inlined call_twice::<!, fn() -> ! {sleep}>) {
|
||||||
+ debug f => _2;
|
+ debug f => _2;
|
||||||
+ let mut _3: &fn() -> ! {sleep};
|
+ let mut _3: &fn() -> ! {sleep};
|
||||||
|
@ -17,6 +18,10 @@
|
||||||
+ debug b => _6;
|
+ debug b => _6;
|
||||||
+ }
|
+ }
|
||||||
+ }
|
+ }
|
||||||
|
+ scope 4 (inlined <fn() -> ! {sleep} as Fn<()>>::call - shim(fn() -> ! {sleep})) {
|
||||||
|
+ scope 5 (inlined sleep) {
|
||||||
|
+ }
|
||||||
|
+ }
|
||||||
+ }
|
+ }
|
||||||
|
|
||||||
bb0: {
|
bb0: {
|
||||||
|
@ -28,24 +33,13 @@
|
||||||
+ StorageLive(_6);
|
+ StorageLive(_6);
|
||||||
+ StorageLive(_3);
|
+ StorageLive(_3);
|
||||||
+ _3 = &_2;
|
+ _3 = &_2;
|
||||||
+ _4 = <fn() -> ! {sleep} as Fn<()>>::call(move _3, const ()) -> [return: bb1, unwind unreachable];
|
+ StorageLive(_7);
|
||||||
|
+ _7 = const ();
|
||||||
|
+ goto -> bb1;
|
||||||
+ }
|
+ }
|
||||||
+
|
+
|
||||||
+ bb1: {
|
+ bb1: {
|
||||||
+ StorageDead(_3);
|
+ goto -> bb1;
|
||||||
+ StorageLive(_5);
|
|
||||||
+ _5 = &_2;
|
|
||||||
+ _6 = <fn() -> ! {sleep} as Fn<()>>::call(move _5, const ()) -> [return: bb2, unwind unreachable];
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
+ bb2: {
|
|
||||||
+ StorageDead(_5);
|
|
||||||
+ _1 = (copy _4, copy _6);
|
|
||||||
+ drop(_2) -> [return: bb3, unwind unreachable];
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
+ bb3: {
|
|
||||||
+ unreachable;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -5,6 +5,7 @@
|
||||||
let mut _0: ();
|
let mut _0: ();
|
||||||
let _1: (!, !);
|
let _1: (!, !);
|
||||||
+ let mut _2: fn() -> ! {sleep};
|
+ let mut _2: fn() -> ! {sleep};
|
||||||
|
+ let mut _8: ();
|
||||||
+ scope 1 (inlined call_twice::<!, fn() -> ! {sleep}>) {
|
+ scope 1 (inlined call_twice::<!, fn() -> ! {sleep}>) {
|
||||||
+ debug f => _2;
|
+ debug f => _2;
|
||||||
+ let mut _3: &fn() -> ! {sleep};
|
+ let mut _3: &fn() -> ! {sleep};
|
||||||
|
@ -18,6 +19,10 @@
|
||||||
+ debug b => _6;
|
+ debug b => _6;
|
||||||
+ }
|
+ }
|
||||||
+ }
|
+ }
|
||||||
|
+ scope 4 (inlined <fn() -> ! {sleep} as Fn<()>>::call - shim(fn() -> ! {sleep})) {
|
||||||
|
+ scope 5 (inlined sleep) {
|
||||||
|
+ }
|
||||||
|
+ }
|
||||||
+ }
|
+ }
|
||||||
|
|
||||||
bb0: {
|
bb0: {
|
||||||
|
@ -29,40 +34,13 @@
|
||||||
+ StorageLive(_4);
|
+ StorageLive(_4);
|
||||||
+ StorageLive(_3);
|
+ StorageLive(_3);
|
||||||
+ _3 = &_2;
|
+ _3 = &_2;
|
||||||
+ _4 = <fn() -> ! {sleep} as Fn<()>>::call(move _3, const ()) -> [return: bb1, unwind: bb5];
|
+ StorageLive(_8);
|
||||||
|
+ _8 = const ();
|
||||||
|
+ goto -> bb1;
|
||||||
+ }
|
+ }
|
||||||
+
|
+
|
||||||
+ bb1: {
|
+ bb1: {
|
||||||
+ StorageDead(_3);
|
+ goto -> bb1;
|
||||||
+ StorageLive(_5);
|
|
||||||
+ _5 = &_2;
|
|
||||||
+ _6 = <fn() -> ! {sleep} as Fn<()>>::call(move _5, const ()) -> [return: bb2, unwind: bb4];
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
+ bb2: {
|
|
||||||
+ StorageDead(_5);
|
|
||||||
+ StorageLive(_7);
|
|
||||||
+ _7 = move _4;
|
|
||||||
+ _1 = (move _7, copy _6);
|
|
||||||
+ StorageDead(_7);
|
|
||||||
+ StorageDead(_4);
|
|
||||||
+ drop(_2) -> [return: bb3, unwind continue];
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
+ bb3: {
|
|
||||||
+ unreachable;
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
+ bb4 (cleanup): {
|
|
||||||
+ drop(_4) -> [return: bb5, unwind terminate(cleanup)];
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
+ bb5 (cleanup): {
|
|
||||||
+ drop(_2) -> [return: bb6, unwind terminate(cleanup)];
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
+ bb6 (cleanup): {
|
|
||||||
+ resume;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -26,7 +26,8 @@ pub fn g(i: i32) -> u32 {
|
||||||
pub fn h() {
|
pub fn h() {
|
||||||
// CHECK-LABEL: fn h(
|
// CHECK-LABEL: fn h(
|
||||||
// CHECK: (inlined call_twice::<!, fn() -> ! {sleep}>)
|
// CHECK: (inlined call_twice::<!, fn() -> ! {sleep}>)
|
||||||
// CHECK-NOT: inlined
|
// CHECK: (inlined <fn() -> ! {sleep} as Fn<()>>::call - shim(fn() -> ! {sleep}))
|
||||||
|
// CHECK: (inlined sleep)
|
||||||
call_twice(sleep);
|
call_twice(sleep);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -9,6 +9,10 @@
|
||||||
let _4: fn() {foo};
|
let _4: fn() {foo};
|
||||||
let mut _5: ();
|
let mut _5: ();
|
||||||
+ scope 1 (inlined hide_foo) {
|
+ scope 1 (inlined hide_foo) {
|
||||||
|
+ }
|
||||||
|
+ scope 2 (inlined <fn() {foo} as Fn<()>>::call - shim(fn() {foo})) {
|
||||||
|
+ scope 3 (inlined foo) {
|
||||||
|
+ }
|
||||||
+ }
|
+ }
|
||||||
|
|
||||||
bb0: {
|
bb0: {
|
||||||
|
@ -23,22 +27,20 @@
|
||||||
StorageLive(_5);
|
StorageLive(_5);
|
||||||
_5 = ();
|
_5 = ();
|
||||||
- _2 = <fn() {foo} as Fn<()>>::call(move _3, move _5) -> [return: bb2, unwind unreachable];
|
- _2 = <fn() {foo} as Fn<()>>::call(move _3, move _5) -> [return: bb2, unwind unreachable];
|
||||||
+ _2 = <fn() {foo} as Fn<()>>::call(move _3, move _5) -> [return: bb1, unwind unreachable];
|
- }
|
||||||
}
|
-
|
||||||
|
|
||||||
- bb2: {
|
- bb2: {
|
||||||
+ bb1: {
|
|
||||||
StorageDead(_5);
|
StorageDead(_5);
|
||||||
StorageDead(_3);
|
StorageDead(_3);
|
||||||
StorageDead(_4);
|
StorageDead(_4);
|
||||||
StorageDead(_2);
|
StorageDead(_2);
|
||||||
_0 = const ();
|
_0 = const ();
|
||||||
- drop(_1) -> [return: bb3, unwind unreachable];
|
- drop(_1) -> [return: bb3, unwind unreachable];
|
||||||
+ drop(_1) -> [return: bb2, unwind unreachable];
|
+ drop(_1) -> [return: bb1, unwind unreachable];
|
||||||
}
|
}
|
||||||
|
|
||||||
- bb3: {
|
- bb3: {
|
||||||
+ bb2: {
|
+ bb1: {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,6 +9,10 @@
|
||||||
let _4: fn() {foo};
|
let _4: fn() {foo};
|
||||||
let mut _5: ();
|
let mut _5: ();
|
||||||
+ scope 1 (inlined hide_foo) {
|
+ scope 1 (inlined hide_foo) {
|
||||||
|
+ }
|
||||||
|
+ scope 2 (inlined <fn() {foo} as Fn<()>>::call - shim(fn() {foo})) {
|
||||||
|
+ scope 3 (inlined foo) {
|
||||||
|
+ }
|
||||||
+ }
|
+ }
|
||||||
|
|
||||||
bb0: {
|
bb0: {
|
||||||
|
@ -23,33 +27,29 @@
|
||||||
StorageLive(_5);
|
StorageLive(_5);
|
||||||
_5 = ();
|
_5 = ();
|
||||||
- _2 = <fn() {foo} as Fn<()>>::call(move _3, move _5) -> [return: bb2, unwind: bb4];
|
- _2 = <fn() {foo} as Fn<()>>::call(move _3, move _5) -> [return: bb2, unwind: bb4];
|
||||||
+ _2 = <fn() {foo} as Fn<()>>::call(move _3, move _5) -> [return: bb1, unwind: bb3];
|
- }
|
||||||
}
|
-
|
||||||
|
|
||||||
- bb2: {
|
- bb2: {
|
||||||
+ bb1: {
|
|
||||||
StorageDead(_5);
|
StorageDead(_5);
|
||||||
StorageDead(_3);
|
StorageDead(_3);
|
||||||
StorageDead(_4);
|
StorageDead(_4);
|
||||||
StorageDead(_2);
|
StorageDead(_2);
|
||||||
_0 = const ();
|
_0 = const ();
|
||||||
- drop(_1) -> [return: bb3, unwind: bb5];
|
- drop(_1) -> [return: bb3, unwind: bb5];
|
||||||
+ drop(_1) -> [return: bb2, unwind: bb4];
|
+ drop(_1) -> [return: bb1, unwind: bb2];
|
||||||
}
|
}
|
||||||
|
|
||||||
- bb3: {
|
- bb3: {
|
||||||
+ bb2: {
|
+ bb1: {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
- bb4 (cleanup): {
|
- bb4 (cleanup): {
|
||||||
- drop(_1) -> [return: bb5, unwind terminate(cleanup)];
|
- drop(_1) -> [return: bb5, unwind terminate(cleanup)];
|
||||||
+ bb3 (cleanup): {
|
- }
|
||||||
+ drop(_1) -> [return: bb4, unwind terminate(cleanup)];
|
-
|
||||||
}
|
|
||||||
|
|
||||||
- bb5 (cleanup): {
|
- bb5 (cleanup): {
|
||||||
+ bb4 (cleanup): {
|
+ bb2 (cleanup): {
|
||||||
resume;
|
resume;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,10 +9,9 @@ pub fn bar<P>(
|
||||||
_baz: P,
|
_baz: P,
|
||||||
) {
|
) {
|
||||||
// CHECK-LABEL: fn bar(
|
// CHECK-LABEL: fn bar(
|
||||||
// CHECK: let mut {{.*}}: &fn() {foo};
|
|
||||||
// CHECK: let {{.*}}: fn() {foo};
|
|
||||||
// CHECK: (inlined hide_foo)
|
// CHECK: (inlined hide_foo)
|
||||||
// CHECK-NOT: inlined
|
// CHECK: (inlined <fn() {foo} as Fn<()>>::call - shim(fn() {foo}))
|
||||||
|
// CHECK: (inlined foo)
|
||||||
hide_foo()();
|
hide_foo()();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
19
tests/mir-opt/inline_fn_call_for_fn_def.rs
Normal file
19
tests/mir-opt/inline_fn_call_for_fn_def.rs
Normal file
|
@ -0,0 +1,19 @@
|
||||||
|
//@ test-mir-pass: Inline
|
||||||
|
//@ compile-flags: --crate-type=lib -C panic=abort
|
||||||
|
|
||||||
|
// EMIT_MIR inline_fn_call_for_fn_def.test.Inline.diff
|
||||||
|
|
||||||
|
fn inline_fn(x: impl FnOnce() -> i32) -> i32 {
|
||||||
|
x()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn yield_number() -> i32 {
|
||||||
|
64
|
||||||
|
}
|
||||||
|
|
||||||
|
fn test() -> i32 {
|
||||||
|
// CHECK: (inlined inline_fn::<fn() -> i32 {yield_number}>)
|
||||||
|
// CHECK: (inlined <fn() -> i32 {yield_number} as FnOnce<()>>::call_once - shim(fn() -> i32 {yield_number}))
|
||||||
|
// CHECK: (inlined yield_number)
|
||||||
|
inline_fn(yield_number)
|
||||||
|
}
|
34
tests/mir-opt/inline_fn_call_for_fn_def.test.Inline.diff
Normal file
34
tests/mir-opt/inline_fn_call_for_fn_def.test.Inline.diff
Normal file
|
@ -0,0 +1,34 @@
|
||||||
|
- // MIR for `test` before Inline
|
||||||
|
+ // MIR for `test` after Inline
|
||||||
|
|
||||||
|
fn test() -> i32 {
|
||||||
|
let mut _0: i32;
|
||||||
|
-
|
||||||
|
- bb0: {
|
||||||
|
- _0 = inline_fn::<fn() -> i32 {yield_number}>(yield_number) -> [return: bb1, unwind unreachable];
|
||||||
|
+ let mut _1: fn() -> i32 {yield_number};
|
||||||
|
+ scope 1 (inlined inline_fn::<fn() -> i32 {yield_number}>) {
|
||||||
|
+ let mut _2: fn() -> i32 {yield_number};
|
||||||
|
+ let mut _3: ();
|
||||||
|
+ scope 2 (inlined <fn() -> i32 {yield_number} as FnOnce<()>>::call_once - shim(fn() -> i32 {yield_number})) {
|
||||||
|
+ scope 3 (inlined yield_number) {
|
||||||
|
+ }
|
||||||
|
+ }
|
||||||
|
}
|
||||||
|
|
||||||
|
- bb1: {
|
||||||
|
+ bb0: {
|
||||||
|
+ StorageLive(_1);
|
||||||
|
+ _1 = yield_number;
|
||||||
|
+ StorageLive(_2);
|
||||||
|
+ _2 = move _1;
|
||||||
|
+ StorageLive(_3);
|
||||||
|
+ _3 = ();
|
||||||
|
+ _0 = const 64_i32;
|
||||||
|
+ StorageDead(_3);
|
||||||
|
+ StorageDead(_2);
|
||||||
|
+ StorageDead(_1);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -0,0 +1,68 @@
|
||||||
|
// MIR for `num_to_digit` after PreCodegen
|
||||||
|
|
||||||
|
fn num_to_digit(_1: char) -> u32 {
|
||||||
|
debug num => _1;
|
||||||
|
let mut _0: u32;
|
||||||
|
let mut _4: std::option::Option<u32>;
|
||||||
|
scope 1 (inlined char::methods::<impl char>::is_digit) {
|
||||||
|
let _2: std::option::Option<u32>;
|
||||||
|
scope 2 (inlined Option::<u32>::is_some) {
|
||||||
|
let mut _3: isize;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
scope 3 (inlined #[track_caller] Option::<u32>::unwrap) {
|
||||||
|
let mut _5: isize;
|
||||||
|
let mut _6: !;
|
||||||
|
scope 4 {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bb0: {
|
||||||
|
StorageLive(_2);
|
||||||
|
_2 = char::methods::<impl char>::to_digit(copy _1, const 8_u32) -> [return: bb1, unwind unreachable];
|
||||||
|
}
|
||||||
|
|
||||||
|
bb1: {
|
||||||
|
StorageLive(_3);
|
||||||
|
_3 = discriminant(_2);
|
||||||
|
StorageDead(_2);
|
||||||
|
switchInt(move _3) -> [1: bb2, otherwise: bb7];
|
||||||
|
}
|
||||||
|
|
||||||
|
bb2: {
|
||||||
|
StorageDead(_3);
|
||||||
|
StorageLive(_4);
|
||||||
|
_4 = char::methods::<impl char>::to_digit(move _1, const 8_u32) -> [return: bb3, unwind unreachable];
|
||||||
|
}
|
||||||
|
|
||||||
|
bb3: {
|
||||||
|
StorageLive(_5);
|
||||||
|
_5 = discriminant(_4);
|
||||||
|
switchInt(move _5) -> [0: bb4, 1: bb5, otherwise: bb6];
|
||||||
|
}
|
||||||
|
|
||||||
|
bb4: {
|
||||||
|
_6 = option::unwrap_failed() -> unwind unreachable;
|
||||||
|
}
|
||||||
|
|
||||||
|
bb5: {
|
||||||
|
_0 = move ((_4 as Some).0: u32);
|
||||||
|
StorageDead(_5);
|
||||||
|
StorageDead(_4);
|
||||||
|
goto -> bb8;
|
||||||
|
}
|
||||||
|
|
||||||
|
bb6: {
|
||||||
|
unreachable;
|
||||||
|
}
|
||||||
|
|
||||||
|
bb7: {
|
||||||
|
StorageDead(_3);
|
||||||
|
_0 = const 0_u32;
|
||||||
|
goto -> bb8;
|
||||||
|
}
|
||||||
|
|
||||||
|
bb8: {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,68 @@
|
||||||
|
// MIR for `num_to_digit` after PreCodegen
|
||||||
|
|
||||||
|
fn num_to_digit(_1: char) -> u32 {
|
||||||
|
debug num => _1;
|
||||||
|
let mut _0: u32;
|
||||||
|
let mut _4: std::option::Option<u32>;
|
||||||
|
scope 1 (inlined char::methods::<impl char>::is_digit) {
|
||||||
|
let _2: std::option::Option<u32>;
|
||||||
|
scope 2 (inlined Option::<u32>::is_some) {
|
||||||
|
let mut _3: isize;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
scope 3 (inlined #[track_caller] Option::<u32>::unwrap) {
|
||||||
|
let mut _5: isize;
|
||||||
|
let mut _6: !;
|
||||||
|
scope 4 {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bb0: {
|
||||||
|
StorageLive(_2);
|
||||||
|
_2 = char::methods::<impl char>::to_digit(copy _1, const 8_u32) -> [return: bb1, unwind continue];
|
||||||
|
}
|
||||||
|
|
||||||
|
bb1: {
|
||||||
|
StorageLive(_3);
|
||||||
|
_3 = discriminant(_2);
|
||||||
|
StorageDead(_2);
|
||||||
|
switchInt(move _3) -> [1: bb2, otherwise: bb7];
|
||||||
|
}
|
||||||
|
|
||||||
|
bb2: {
|
||||||
|
StorageDead(_3);
|
||||||
|
StorageLive(_4);
|
||||||
|
_4 = char::methods::<impl char>::to_digit(move _1, const 8_u32) -> [return: bb3, unwind continue];
|
||||||
|
}
|
||||||
|
|
||||||
|
bb3: {
|
||||||
|
StorageLive(_5);
|
||||||
|
_5 = discriminant(_4);
|
||||||
|
switchInt(move _5) -> [0: bb4, 1: bb5, otherwise: bb6];
|
||||||
|
}
|
||||||
|
|
||||||
|
bb4: {
|
||||||
|
_6 = option::unwrap_failed() -> unwind continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
bb5: {
|
||||||
|
_0 = move ((_4 as Some).0: u32);
|
||||||
|
StorageDead(_5);
|
||||||
|
StorageDead(_4);
|
||||||
|
goto -> bb8;
|
||||||
|
}
|
||||||
|
|
||||||
|
bb6: {
|
||||||
|
unreachable;
|
||||||
|
}
|
||||||
|
|
||||||
|
bb7: {
|
||||||
|
StorageDead(_3);
|
||||||
|
_0 = const 0_u32;
|
||||||
|
goto -> bb8;
|
||||||
|
}
|
||||||
|
|
||||||
|
bb8: {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,4 +1,6 @@
|
||||||
// EMIT_MIR_FOR_EACH_PANIC_STRATEGY
|
// EMIT_MIR_FOR_EACH_PANIC_STRATEGY
|
||||||
|
// EMIT_MIR_FOR_EACH_BIT_WIDTH
|
||||||
|
|
||||||
// This test is a mirror of codegen/issue-59352.rs.
|
// This test is a mirror of codegen/issue-59352.rs.
|
||||||
// The LLVM inliner doesn't inline `char::method::is_digit()` and so it doesn't recognize this case
|
// The LLVM inliner doesn't inline `char::method::is_digit()` and so it doesn't recognize this case
|
||||||
// as effectively `if x.is_some() { x.unwrap() } else { 0 }`.
|
// as effectively `if x.is_some() { x.unwrap() } else { 0 }`.
|
||||||
|
|
|
@ -29,6 +29,10 @@ fn mapped(_1: impl Iterator<Item = T>, _2: impl Fn(T) -> U) -> () {
|
||||||
let mut _12: U;
|
let mut _12: U;
|
||||||
scope 6 {
|
scope 6 {
|
||||||
debug x => _10;
|
debug x => _10;
|
||||||
|
scope 7 (inlined ops::function::impls::<impl FnOnce<(T,)> for &mut impl Fn(T) -> U>::call_once) {
|
||||||
|
debug self => _8;
|
||||||
|
debug args => _11;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -85,7 +89,7 @@ fn mapped(_1: impl Iterator<Item = T>, _2: impl Fn(T) -> U) -> () {
|
||||||
StorageLive(_12);
|
StorageLive(_12);
|
||||||
StorageLive(_11);
|
StorageLive(_11);
|
||||||
_11 = (copy _10,);
|
_11 = (copy _10,);
|
||||||
_12 = <&mut impl Fn(T) -> U as FnOnce<(T,)>>::call_once(move _8, move _11) -> [return: bb7, unwind: bb10];
|
_12 = <impl Fn(T) -> U as FnMut<(T,)>>::call_mut(move _8, move _11) -> [return: bb7, unwind: bb10];
|
||||||
}
|
}
|
||||||
|
|
||||||
bb7: {
|
bb7: {
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue