Skip to content

Commit 5de7345

Browse files
committed
deduplicate tail call terminator codegen into call terminator codegen
1 parent 07c07a5 commit 5de7345

File tree

1 file changed

+59
-103
lines changed
  • compiler/rustc_codegen_ssa/src/mir

1 file changed

+59
-103
lines changed

compiler/rustc_codegen_ssa/src/mir/block.rs

Lines changed: 59 additions & 103 deletions
Original file line numberDiff line numberDiff line change
@@ -160,6 +160,7 @@ impl<'a, 'tcx> TerminatorCodegenHelper<'tcx> {
160160
mut unwind: mir::UnwindAction,
161161
lifetime_ends_after_call: &[(Bx::Value, Size)],
162162
instance: Option<Instance<'tcx>>,
163+
tail: bool,
163164
mergeable_succ: bool,
164165
) -> MergingSucc {
165166
let tcx = bx.tcx();
@@ -252,8 +253,16 @@ impl<'a, 'tcx> TerminatorCodegenHelper<'tcx> {
252253
}
253254
MergingSucc::False
254255
} else {
255-
let llret =
256-
bx.call(fn_ty, fn_attrs, Some(fn_abi), fn_ptr, llargs, self.funclet(fx), instance);
256+
let llret = if !tail {
257+
bx.call(fn_ty, fn_attrs, Some(fn_abi), fn_ptr, llargs, self.funclet(fx), instance)
258+
} else {
259+
bx.call(fn_ty, fn_attrs, Some(fn_abi), fn_ptr, llargs, None, instance)
260+
};
261+
262+
if tail {
263+
bx.set_tail_call(llret);
264+
}
265+
257266
if fx.mir[self.bb].is_cleanup {
258267
bx.apply_attrs_to_cleanup_callsite(llret);
259268
}
@@ -264,6 +273,12 @@ impl<'a, 'tcx> TerminatorCodegenHelper<'tcx> {
264273
}
265274
fx.store_return(bx, ret_dest, &fn_abi.ret, llret);
266275
self.funclet_br(fx, bx, target, mergeable_succ)
276+
} else if tail {
277+
for &(tmp, size) in lifetime_ends_after_call {
278+
bx.lifetime_end(tmp, size);
279+
}
280+
bx.ret(llret);
281+
MergingSucc::False
267282
} else {
268283
bx.unreachable();
269284
MergingSucc::False
@@ -659,6 +674,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
659674
unwind,
660675
&[],
661676
Some(drop_instance),
677+
false,
662678
!maybe_null && mergeable_succ,
663679
)
664680
}
@@ -747,8 +763,19 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
747763
let (fn_abi, llfn, instance) = common::build_langcall(bx, span, lang_item);
748764

749765
// Codegen the actual panic invoke/call.
750-
let merging_succ =
751-
helper.do_call(self, bx, fn_abi, llfn, &args, None, unwind, &[], Some(instance), false);
766+
let merging_succ = helper.do_call(
767+
self,
768+
bx,
769+
fn_abi,
770+
llfn,
771+
&args,
772+
None,
773+
unwind,
774+
&[],
775+
Some(instance),
776+
false,
777+
false,
778+
);
752779
assert_eq!(merging_succ, MergingSucc::False);
753780
MergingSucc::False
754781
}
@@ -778,6 +805,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
778805
&[],
779806
Some(instance),
780807
false,
808+
false,
781809
);
782810
assert_eq!(merging_succ, MergingSucc::False);
783811
}
@@ -845,6 +873,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
845873
unwind,
846874
&[],
847875
Some(instance),
876+
false,
848877
mergeable_succ,
849878
))
850879
}
@@ -860,6 +889,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
860889
target: Option<mir::BasicBlock>,
861890
unwind: mir::UnwindAction,
862891
fn_span: Span,
892+
tail: bool,
863893
mergeable_succ: bool,
864894
) -> MergingSucc {
865895
let source_info = mir::SourceInfo { span: fn_span, ..terminator.source_info };
@@ -1003,8 +1033,12 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
10031033
// We still need to call `make_return_dest` even if there's no `target`, since
10041034
// `fn_abi.ret` could be `PassMode::Indirect`, even if it is uninhabited,
10051035
// and `make_return_dest` adds the return-place indirect pointer to `llargs`.
1006-
let return_dest = self.make_return_dest(bx, destination, &fn_abi.ret, &mut llargs);
1007-
let destination = target.map(|target| (return_dest, target));
1036+
let destination = if !tail {
1037+
let return_dest = self.make_return_dest(bx, destination, &fn_abi.ret, &mut llargs);
1038+
target.map(|target| (return_dest, target))
1039+
} else {
1040+
None
1041+
};
10081042

10091043
// Split the rust-call tupled arguments off.
10101044
let (first_args, untuple) = if sig.abi() == ExternAbi::RustCall
@@ -1147,106 +1181,11 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
11471181
unwind,
11481182
&lifetime_ends_after_call,
11491183
instance,
1184+
tail,
11501185
mergeable_succ,
11511186
)
11521187
}
11531188

1154-
fn codegen_tail_call_terminator(
1155-
&mut self,
1156-
bx: &mut Bx,
1157-
func: &mir::Operand<'tcx>,
1158-
args: &[Spanned<mir::Operand<'tcx>>],
1159-
fn_span: Span,
1160-
mergeable_succ: bool,
1161-
) -> MergingSucc {
1162-
// We don't need source_info as we already have fn_span for diagnostics
1163-
let func = self.codegen_operand(bx, func);
1164-
let fn_ty = func.layout.ty;
1165-
1166-
// Create the callee. This is a fn ptr or zero-sized and hence a kind of scalar.
1167-
let (fn_ptr, fn_abi, instance) = match *fn_ty.kind() {
1168-
ty::FnDef(def_id, substs) => {
1169-
let instance = ty::Instance::expect_resolve(
1170-
bx.tcx(),
1171-
bx.typing_env(),
1172-
def_id,
1173-
substs,
1174-
fn_span,
1175-
);
1176-
let fn_ptr = bx.get_fn_addr(instance);
1177-
let fn_abi = bx.fn_abi_of_instance(instance, ty::List::empty());
1178-
(fn_ptr, fn_abi, Some(instance))
1179-
}
1180-
ty::FnPtr(..) => {
1181-
let sig = fn_ty.fn_sig(bx.tcx());
1182-
let extra_args = bx.tcx().mk_type_list(&[]);
1183-
let fn_ptr = func.immediate();
1184-
let fn_abi = bx.fn_abi_of_fn_ptr(sig, extra_args);
1185-
(fn_ptr, fn_abi, None)
1186-
}
1187-
_ => bug!("{} is not callable", func.layout.ty),
1188-
};
1189-
1190-
let mut llargs = Vec::with_capacity(args.len());
1191-
let mut lifetime_ends_after_call = Vec::new();
1192-
1193-
// Process arguments
1194-
for arg in args {
1195-
let op = self.codegen_operand(bx, &arg.node);
1196-
let arg_idx = llargs.len();
1197-
1198-
if arg_idx < fn_abi.args.len() {
1199-
self.codegen_argument(
1200-
bx,
1201-
op,
1202-
&mut llargs,
1203-
&fn_abi.args[arg_idx],
1204-
&mut lifetime_ends_after_call,
1205-
);
1206-
} else {
1207-
// This can happen in case of C-variadic functions
1208-
let is_immediate = match op.val {
1209-
Immediate(_) => true,
1210-
_ => false,
1211-
};
1212-
1213-
if is_immediate {
1214-
llargs.push(op.immediate());
1215-
} else {
1216-
let temp = PlaceRef::alloca(bx, op.layout);
1217-
op.val.store(bx, temp);
1218-
llargs.push(bx.load(
1219-
bx.backend_type(op.layout),
1220-
temp.val.llval,
1221-
temp.val.align,
1222-
));
1223-
}
1224-
}
1225-
}
1226-
1227-
// Call the function
1228-
let fn_ty = bx.fn_decl_backend_type(fn_abi);
1229-
let fn_attrs = if let Some(instance) = instance
1230-
&& bx.tcx().def_kind(instance.def_id()).has_codegen_attrs()
1231-
{
1232-
Some(bx.tcx().codegen_fn_attrs(instance.def_id()))
1233-
} else {
1234-
None
1235-
};
1236-
1237-
// Perform the actual function call
1238-
let llret = bx.call(fn_ty, fn_attrs, Some(fn_abi), fn_ptr, &llargs, None, instance);
1239-
1240-
// Mark as tail call - this is the critical part
1241-
bx.set_tail_call(llret);
1242-
1243-
// Return the result - musttail requires ret immediately after the call
1244-
bx.ret(llret);
1245-
1246-
assert_eq!(mergeable_succ, false);
1247-
MergingSucc::False
1248-
}
1249-
12501189
fn codegen_asm_terminator(
12511190
&mut self,
12521191
helper: TerminatorCodegenHelper<'tcx>,
@@ -1484,10 +1423,27 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
14841423
target,
14851424
unwind,
14861425
fn_span,
1426+
false,
14871427
mergeable_succ(),
14881428
),
14891429
mir::TerminatorKind::TailCall { ref func, ref args, fn_span } => {
1490-
self.codegen_tail_call_terminator(bx, func, args, fn_span, mergeable_succ())
1430+
let destination = mir::Place::from(mir::RETURN_PLACE);
1431+
let target = None;
1432+
let unwind = mir::UnwindAction::Unreachable;
1433+
1434+
self.codegen_call_terminator(
1435+
helper,
1436+
bx,
1437+
terminator,
1438+
func,
1439+
args,
1440+
destination,
1441+
target,
1442+
unwind,
1443+
fn_span,
1444+
true,
1445+
mergeable_succ(),
1446+
)
14911447
}
14921448
mir::TerminatorKind::CoroutineDrop | mir::TerminatorKind::Yield { .. } => {
14931449
bug!("coroutine ops in codegen")

0 commit comments

Comments
 (0)