@@ -342,6 +342,86 @@ impl<'a, 'tcx> TerminatorCodegenHelper<'tcx> {
342
342
343
343
/// Codegen implementations for some terminator variants.
344
344
impl < ' a , ' tcx , Bx : BuilderMethods < ' a , ' tcx > > FunctionCx < ' a , ' tcx , Bx > {
345
+ fn codegen_tail_call_terminator (
346
+ & mut self ,
347
+ bx : & mut Bx ,
348
+ func : & mir:: Operand < ' tcx > ,
349
+ args : & [ Spanned < mir:: Operand < ' tcx > > ] ,
350
+ fn_span : Span ,
351
+ ) {
352
+ // We don't need source_info as we already have fn_span for diagnostics
353
+ let func = self . codegen_operand ( bx, func) ;
354
+ let fn_ty = func. layout . ty ;
355
+
356
+ // Create the callee. This is a fn ptr or zero-sized and hence a kind of scalar.
357
+ let ( fn_ptr, fn_abi, instance) = match * fn_ty. kind ( ) {
358
+ ty:: FnDef ( def_id, substs) => {
359
+ let instance = ty:: Instance :: expect_resolve (
360
+ bx. tcx ( ) ,
361
+ bx. typing_env ( ) ,
362
+ def_id,
363
+ substs,
364
+ fn_span,
365
+ ) ;
366
+ let fn_ptr = bx. get_fn_addr ( instance) ;
367
+ let fn_abi = bx. fn_abi_of_instance ( instance, ty:: List :: empty ( ) ) ;
368
+ ( fn_ptr, fn_abi, Some ( instance) )
369
+ }
370
+ ty:: FnPtr ( ..) => {
371
+ let sig = fn_ty. fn_sig ( bx. tcx ( ) ) ;
372
+ let extra_args = bx. tcx ( ) . mk_type_list ( & [ ] ) ;
373
+ let fn_ptr = func. immediate ( ) ;
374
+ let fn_abi = bx. fn_abi_of_fn_ptr ( sig, extra_args) ;
375
+ ( fn_ptr, fn_abi, None )
376
+ }
377
+ _ => bug ! ( "{} is not callable" , func. layout. ty) ,
378
+ } ;
379
+
380
+ let mut llargs = Vec :: with_capacity ( args. len ( ) ) ;
381
+
382
+ // Process arguments
383
+ for arg in args {
384
+ let op = self . codegen_operand ( bx, & arg. node ) ;
385
+ let arg_idx = llargs. len ( ) ;
386
+
387
+ if arg_idx < fn_abi. args . len ( ) {
388
+ self . codegen_argument ( bx, op, & mut llargs, & fn_abi. args [ arg_idx] ) ;
389
+ } else {
390
+ // This can happen in case of C-variadic functions
391
+ let is_immediate = match op. val {
392
+ Immediate ( _) => true ,
393
+ _ => false ,
394
+ } ;
395
+
396
+ if is_immediate {
397
+ llargs. push ( op. immediate ( ) ) ;
398
+ } else {
399
+ let temp = PlaceRef :: alloca ( bx, op. layout ) ;
400
+ op. val . store ( bx, temp) ;
401
+ llargs. push ( bx. load ( bx. backend_type ( op. layout ) , temp. val . llval , temp. val . align ) ) ;
402
+ }
403
+ }
404
+ }
405
+
406
+ // Call the function
407
+ let fn_ty = bx. fn_decl_backend_type ( fn_abi) ;
408
+ let fn_attrs = if let Some ( instance) = instance
409
+ && bx. tcx ( ) . def_kind ( instance. def_id ( ) ) . has_codegen_attrs ( )
410
+ {
411
+ Some ( bx. tcx ( ) . codegen_fn_attrs ( instance. def_id ( ) ) )
412
+ } else {
413
+ None
414
+ } ;
415
+
416
+ // Perform the actual function call
417
+ let llret = bx. call ( fn_ty, fn_attrs, Some ( fn_abi) , fn_ptr, & llargs, None , instance) ;
418
+
419
+ // Mark as tail call - this is the critical part
420
+ bx. set_tail_call ( llret) ;
421
+
422
+ // Return the result
423
+ bx. ret ( llret) ;
424
+ }
345
425
/// Generates code for a `Resume` terminator.
346
426
fn codegen_resume_terminator ( & mut self , helper : TerminatorCodegenHelper < ' tcx > , bx : & mut Bx ) {
347
427
if let Some ( funclet) = helper. funclet ( self ) {
@@ -1430,12 +1510,9 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
1430
1510
fn_span,
1431
1511
mergeable_succ ( ) ,
1432
1512
) ,
1433
- mir:: TerminatorKind :: TailCall { .. } => {
1434
- // FIXME(explicit_tail_calls): implement tail calls in ssa backend
1435
- span_bug ! (
1436
- terminator. source_info. span,
1437
- "`TailCall` terminator is not yet supported by `rustc_codegen_ssa`"
1438
- )
1513
+ mir:: TerminatorKind :: TailCall { ref func, ref args, fn_span } => {
1514
+ self . codegen_tail_call_terminator ( bx, func, args, fn_span) ;
1515
+ MergingSucc :: False
1439
1516
}
1440
1517
mir:: TerminatorKind :: CoroutineDrop | mir:: TerminatorKind :: Yield { .. } => {
1441
1518
bug ! ( "coroutine ops in codegen" )
0 commit comments