@@ -35,6 +35,14 @@ enum MergingSucc {
35
35
True ,
36
36
}
37
37
38
+ /// Indicates to the call terminator codegen whether a cal
39
+ /// is a normal call or an explicit tail call.
40
+ #[ derive( Debug , PartialEq ) ]
41
+ enum CallKind {
42
+ Normal ,
43
+ Tail ,
44
+ }
45
+
38
46
/// Used by `FunctionCx::codegen_terminator` for emitting common patterns
39
47
/// e.g., creating a basic block, calling a function, etc.
40
48
struct TerminatorCodegenHelper < ' tcx > {
@@ -160,6 +168,7 @@ impl<'a, 'tcx> TerminatorCodegenHelper<'tcx> {
160
168
mut unwind : mir:: UnwindAction ,
161
169
lifetime_ends_after_call : & [ ( Bx :: Value , Size ) ] ,
162
170
instance : Option < Instance < ' tcx > > ,
171
+ kind : CallKind ,
163
172
mergeable_succ : bool ,
164
173
) -> MergingSucc {
165
174
let tcx = bx. tcx ( ) ;
@@ -221,6 +230,11 @@ impl<'a, 'tcx> TerminatorCodegenHelper<'tcx> {
221
230
}
222
231
} ;
223
232
233
+ if kind == CallKind :: Tail {
234
+ bx. tail_call ( fn_ty, fn_attrs, fn_abi, fn_ptr, llargs, self . funclet ( fx) , instance) ;
235
+ return MergingSucc :: False ;
236
+ }
237
+
224
238
if let Some ( unwind_block) = unwind_block {
225
239
let ret_llbb = if let Some ( ( _, target) ) = destination {
226
240
fx. llbb ( target)
@@ -659,6 +673,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
659
673
unwind,
660
674
& [ ] ,
661
675
Some ( drop_instance) ,
676
+ CallKind :: Normal ,
662
677
!maybe_null && mergeable_succ,
663
678
)
664
679
}
@@ -747,8 +762,19 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
747
762
let ( fn_abi, llfn, instance) = common:: build_langcall ( bx, span, lang_item) ;
748
763
749
764
// 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 ) ;
765
+ let merging_succ = helper. do_call (
766
+ self ,
767
+ bx,
768
+ fn_abi,
769
+ llfn,
770
+ & args,
771
+ None ,
772
+ unwind,
773
+ & [ ] ,
774
+ Some ( instance) ,
775
+ CallKind :: Normal ,
776
+ false ,
777
+ ) ;
752
778
assert_eq ! ( merging_succ, MergingSucc :: False ) ;
753
779
MergingSucc :: False
754
780
}
@@ -777,6 +803,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
777
803
mir:: UnwindAction :: Unreachable ,
778
804
& [ ] ,
779
805
Some ( instance) ,
806
+ CallKind :: Normal ,
780
807
false ,
781
808
) ;
782
809
assert_eq ! ( merging_succ, MergingSucc :: False ) ;
@@ -845,6 +872,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
845
872
unwind,
846
873
& [ ] ,
847
874
Some ( instance) ,
875
+ CallKind :: Normal ,
848
876
mergeable_succ,
849
877
) )
850
878
}
@@ -860,6 +888,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
860
888
target : Option < mir:: BasicBlock > ,
861
889
unwind : mir:: UnwindAction ,
862
890
fn_span : Span ,
891
+ kind : CallKind ,
863
892
mergeable_succ : bool ,
864
893
) -> MergingSucc {
865
894
let source_info = mir:: SourceInfo { span : fn_span, ..terminator. source_info } ;
@@ -1003,8 +1032,13 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
1003
1032
// We still need to call `make_return_dest` even if there's no `target`, since
1004
1033
// `fn_abi.ret` could be `PassMode::Indirect`, even if it is uninhabited,
1005
1034
// 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) ) ;
1035
+ let destination = match kind {
1036
+ CallKind :: Normal => {
1037
+ let return_dest = self . make_return_dest ( bx, destination, & fn_abi. ret , & mut llargs) ;
1038
+ target. map ( |target| ( return_dest, target) )
1039
+ }
1040
+ CallKind :: Tail => None ,
1041
+ } ;
1008
1042
1009
1043
// Split the rust-call tupled arguments off.
1010
1044
let ( first_args, untuple) = if sig. abi ( ) == ExternAbi :: RustCall
@@ -1020,6 +1054,14 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
1020
1054
// to generate `lifetime_end` when the call returns.
1021
1055
let mut lifetime_ends_after_call: Vec < ( Bx :: Value , Size ) > = Vec :: new ( ) ;
1022
1056
' make_args: for ( i, arg) in first_args. iter ( ) . enumerate ( ) {
1057
+ if kind == CallKind :: Tail && matches ! ( fn_abi. args[ i] . mode, PassMode :: Indirect { .. } ) {
1058
+ // FIXME: https://github.com/rust-lang/rust/pull/144232#discussion_r2218543841
1059
+ span_bug ! (
1060
+ fn_span,
1061
+ "arguments using PassMode::Indirect are currently not supported for tail calls"
1062
+ ) ;
1063
+ }
1064
+
1023
1065
let mut op = self . codegen_operand ( bx, & arg. node ) ;
1024
1066
1025
1067
if let ( 0 , Some ( ty:: InstanceKind :: Virtual ( _, idx) ) ) = ( i, instance. map ( |i| i. def ) ) {
@@ -1147,6 +1189,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
1147
1189
unwind,
1148
1190
& lifetime_ends_after_call,
1149
1191
instance,
1192
+ kind,
1150
1193
mergeable_succ,
1151
1194
)
1152
1195
}
@@ -1388,15 +1431,23 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
1388
1431
target,
1389
1432
unwind,
1390
1433
fn_span,
1434
+ CallKind :: Normal ,
1391
1435
mergeable_succ ( ) ,
1392
1436
) ,
1393
- mir:: TerminatorKind :: TailCall { .. } => {
1394
- // FIXME(explicit_tail_calls): implement tail calls in ssa backend
1395
- span_bug ! (
1396
- terminator. source_info. span,
1397
- "`TailCall` terminator is not yet supported by `rustc_codegen_ssa`"
1398
- )
1399
- }
1437
+ mir:: TerminatorKind :: TailCall { ref func, ref args, fn_span } => self
1438
+ . codegen_call_terminator (
1439
+ helper,
1440
+ bx,
1441
+ terminator,
1442
+ func,
1443
+ args,
1444
+ mir:: Place :: from ( mir:: RETURN_PLACE ) ,
1445
+ None ,
1446
+ mir:: UnwindAction :: Unreachable ,
1447
+ fn_span,
1448
+ CallKind :: Tail ,
1449
+ mergeable_succ ( ) ,
1450
+ ) ,
1400
1451
mir:: TerminatorKind :: CoroutineDrop | mir:: TerminatorKind :: Yield { .. } => {
1401
1452
bug ! ( "coroutine ops in codegen" )
1402
1453
}
0 commit comments