@@ -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 ( ) ;
@@ -221,6 +222,11 @@ impl<'a, 'tcx> TerminatorCodegenHelper<'tcx> {
221222 }
222223 } ;
223224
225+ if tail {
226+ bx. tail_call ( fn_ty, fn_attrs, fn_abi, fn_ptr, llargs, self . funclet ( fx) , instance) ;
227+ return MergingSucc :: False ;
228+ }
229+
224230 if let Some ( unwind_block) = unwind_block {
225231 let ret_llbb = if let Some ( ( _, target) ) = destination {
226232 fx. llbb ( target)
@@ -659,6 +665,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
659665 unwind,
660666 & [ ] ,
661667 Some ( drop_instance) ,
668+ false ,
662669 !maybe_null && mergeable_succ,
663670 )
664671 }
@@ -747,8 +754,19 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
747754 let ( fn_abi, llfn, instance) = common:: build_langcall ( bx, span, lang_item) ;
748755
749756 // 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 ) ;
757+ let merging_succ = helper. do_call (
758+ self ,
759+ bx,
760+ fn_abi,
761+ llfn,
762+ & args,
763+ None ,
764+ unwind,
765+ & [ ] ,
766+ Some ( instance) ,
767+ false ,
768+ false ,
769+ ) ;
752770 assert_eq ! ( merging_succ, MergingSucc :: False ) ;
753771 MergingSucc :: False
754772 }
@@ -778,6 +796,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
778796 & [ ] ,
779797 Some ( instance) ,
780798 false ,
799+ false ,
781800 ) ;
782801 assert_eq ! ( merging_succ, MergingSucc :: False ) ;
783802 }
@@ -845,6 +864,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
845864 unwind,
846865 & [ ] ,
847866 Some ( instance) ,
867+ false ,
848868 mergeable_succ,
849869 ) )
850870 }
@@ -860,6 +880,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
860880 target : Option < mir:: BasicBlock > ,
861881 unwind : mir:: UnwindAction ,
862882 fn_span : Span ,
883+ tail : bool ,
863884 mergeable_succ : bool ,
864885 ) -> MergingSucc {
865886 let source_info = mir:: SourceInfo { span : fn_span, ..terminator. source_info } ;
@@ -1003,8 +1024,12 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
10031024 // We still need to call `make_return_dest` even if there's no `target`, since
10041025 // `fn_abi.ret` could be `PassMode::Indirect`, even if it is uninhabited,
10051026 // 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) ) ;
1027+ let destination = if !tail {
1028+ let return_dest = self . make_return_dest ( bx, destination, & fn_abi. ret , & mut llargs) ;
1029+ target. map ( |target| ( return_dest, target) )
1030+ } else {
1031+ None
1032+ } ;
10081033
10091034 // Split the rust-call tupled arguments off.
10101035 let ( first_args, untuple) = if sig. abi ( ) == ExternAbi :: RustCall
@@ -1020,6 +1045,13 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
10201045 // to generate `lifetime_end` when the call returns.
10211046 let mut lifetime_ends_after_call: Vec < ( Bx :: Value , Size ) > = Vec :: new ( ) ;
10221047 ' make_args: for ( i, arg) in first_args. iter ( ) . enumerate ( ) {
1048+ if tail && matches ! ( fn_abi. args[ i] . mode, PassMode :: Indirect { .. } ) {
1049+ span_bug ! (
1050+ fn_span,
1051+ "arguments using PassMode::Indirect are currently not supported for tail calls"
1052+ ) ;
1053+ }
1054+
10231055 let mut op = self . codegen_operand ( bx, & arg. node ) ;
10241056
10251057 if let ( 0 , Some ( ty:: InstanceKind :: Virtual ( _, idx) ) ) = ( i, instance. map ( |i| i. def ) ) {
@@ -1147,6 +1179,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
11471179 unwind,
11481180 & lifetime_ends_after_call,
11491181 instance,
1182+ tail,
11501183 mergeable_succ,
11511184 )
11521185 }
@@ -1388,15 +1421,23 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
13881421 target,
13891422 unwind,
13901423 fn_span,
1424+ false ,
13911425 mergeable_succ ( ) ,
13921426 ) ,
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- }
1427+ mir:: TerminatorKind :: TailCall { ref func, ref args, fn_span } => self
1428+ . codegen_call_terminator (
1429+ helper,
1430+ bx,
1431+ terminator,
1432+ func,
1433+ args,
1434+ mir:: Place :: from ( mir:: RETURN_PLACE ) ,
1435+ None ,
1436+ mir:: UnwindAction :: Unreachable ,
1437+ fn_span,
1438+ true ,
1439+ mergeable_succ ( ) ,
1440+ ) ,
14001441 mir:: TerminatorKind :: CoroutineDrop | mir:: TerminatorKind :: Yield { .. } => {
14011442 bug ! ( "coroutine ops in codegen" )
14021443 }
0 commit comments