@@ -36,7 +36,6 @@ use rustc_target::spec::{HasTargetSpec, HasX86AbiOpt, Target, X86Abi};
3636use crate :: abi:: FnAbiGccExt ;
3737use crate :: common:: { SignType , TypeReflection , type_is_pointer} ;
3838use crate :: context:: CodegenCx ;
39- use crate :: errors;
4039use crate :: intrinsic:: llvm;
4140use crate :: type_of:: LayoutGccExt ;
4241
@@ -312,14 +311,48 @@ impl<'a, 'gcc, 'tcx> Builder<'a, 'gcc, 'tcx> {
312311 self . block . get_function ( )
313312 }
314313
314+ /// Shared implementation of `call` and `tail_call`. For tail call it is important that this
315+ /// returns a bare call, and not the result assigned to a local, or the result of `add_eval`.
316+ fn build_call (
317+ & mut self ,
318+ typ : Type < ' gcc > ,
319+ fn_abi : Option < & FnAbi < ' tcx , Ty < ' tcx > > > ,
320+ func : RValue < ' gcc > ,
321+ args : & [ RValue < ' gcc > ] ,
322+ funclet : Option < & Funclet > ,
323+ must_tail : bool ,
324+ ) -> RValue < ' gcc > {
325+ // FIXME(antoyo): remove when having a proper API.
326+ let gcc_func = unsafe { std:: mem:: transmute :: < RValue < ' gcc > , Function < ' gcc > > ( func) } ;
327+ let call = if self . functions . borrow ( ) . values ( ) . any ( |value| * value == gcc_func) {
328+ // FIXME(antoyo): remove when the API supports a different type for functions.
329+ let func: Function < ' gcc > = self . cx . rvalue_as_function ( func) ;
330+ self . function_call ( func, args, funclet, must_tail)
331+ } else {
332+ // If it's a not function that was defined, it's a function pointer.
333+ self . function_ptr_call ( typ, fn_abi, func, args, funclet, must_tail)
334+ } ;
335+ if let Some ( _fn_abi) = fn_abi {
336+ // FIXME(bjorn3): Apply function attributes
337+ }
338+ call
339+ }
340+
315341 pub fn function_call (
316342 & mut self ,
317343 func : Function < ' gcc > ,
318344 args : & [ RValue < ' gcc > ] ,
319345 _funclet : Option < & Funclet > ,
346+ must_tail : bool ,
320347 ) -> RValue < ' gcc > {
321348 let args = self . check_call ( "call" , func, args) ;
322349
350+ let call = self . cx . context . new_call ( self . location , func, & args) ;
351+ if must_tail {
352+ // Return the bare tail call, don't assign or `add_eval` it yet.
353+ return call;
354+ }
355+
323356 // gccjit requires to use the result of functions, even when it's not used.
324357 // That's why we assign the result to a local or call add_eval().
325358 let return_type = func. get_return_type ( ) ;
@@ -331,15 +364,10 @@ impl<'a, 'gcc, 'tcx> Builder<'a, 'gcc, 'tcx> {
331364 return_type,
332365 format ! ( "returnValue{}" , self . next_value_counter( ) ) ,
333366 ) ;
334- self . block . add_assignment (
335- self . location ,
336- result,
337- self . cx . context . new_call ( self . location , func, & args) ,
338- ) ;
367+ self . block . add_assignment ( self . location , result, call) ;
339368 result. to_rvalue ( )
340369 } else {
341- self . block
342- . add_eval ( self . location , self . cx . context . new_call ( self . location , func, & args) ) ;
370+ self . block . add_eval ( self . location , call) ;
343371 // Return dummy value when not having return value.
344372 self . context . new_rvalue_zero ( self . isize_type )
345373 }
@@ -352,6 +380,7 @@ impl<'a, 'gcc, 'tcx> Builder<'a, 'gcc, 'tcx> {
352380 mut func_ptr : RValue < ' gcc > ,
353381 args : & [ RValue < ' gcc > ] ,
354382 _funclet : Option < & Funclet > ,
383+ must_tail : bool ,
355384 ) -> RValue < ' gcc > {
356385 let func_ptr_type = {
357386 let func_ptr_type = func_ptr. get_type ( ) ;
@@ -376,6 +405,12 @@ impl<'a, 'gcc, 'tcx> Builder<'a, 'gcc, 'tcx> {
376405 let args_adjusted = args. len ( ) != previous_arg_count;
377406 let args = self . check_ptr_call ( "call" , func_ptr, & args, & on_stack_param_indices) ;
378407
408+ if must_tail {
409+ // Return the bare tail call, don't assign or `add_eval` it yet.
410+ let call = self . cx . context . new_call_through_ptr ( self . location , func_ptr, & args) ;
411+ return call;
412+ }
413+
379414 // gccjit requires to use the result of functions, even when it's not used.
380415 // That's why we assign the result to a local or call add_eval().
381416 let return_type = gcc_func. get_return_type ( ) ;
@@ -1798,34 +1833,34 @@ impl<'a, 'gcc, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'gcc, 'tcx> {
17981833 funclet : Option < & Funclet > ,
17991834 _instance : Option < Instance < ' tcx > > ,
18001835 ) -> RValue < ' gcc > {
1801- // FIXME(antoyo): remove when having a proper API.
1802- let gcc_func = unsafe { std:: mem:: transmute :: < RValue < ' gcc > , Function < ' gcc > > ( func) } ;
1803- let call = if self . functions . borrow ( ) . values ( ) . any ( |value| * value == gcc_func) {
1804- // FIXME(antoyo): remove when the API supports a different type for functions.
1805- let func: Function < ' gcc > = self . cx . rvalue_as_function ( func) ;
1806- self . function_call ( func, args, funclet)
1807- } else {
1808- // If it's a not function that was defined, it's a function pointer.
1809- self . function_ptr_call ( typ, fn_abi, func, args, funclet)
1810- } ;
1811- if let Some ( _fn_abi) = fn_abi {
1812- // FIXME(bjorn3): Apply function attributes
1813- }
1814- call
1836+ self . build_call ( typ, fn_abi, func, args, funclet, false )
18151837 }
18161838
18171839 fn tail_call (
18181840 & mut self ,
1819- _llty : Self :: Type ,
1841+ llty : Self :: Type ,
18201842 _fn_attrs : Option < & CodegenFnAttrs > ,
1821- _fn_abi : & FnAbi < ' tcx , Ty < ' tcx > > ,
1822- _llfn : Self :: Value ,
1823- _args : & [ Self :: Value ] ,
1824- _funclet : Option < & Self :: Funclet > ,
1843+ fn_abi : & FnAbi < ' tcx , Ty < ' tcx > > ,
1844+ llfn : Self :: Value ,
1845+ args : & [ Self :: Value ] ,
1846+ funclet : Option < & Self :: Funclet > ,
18251847 _instance : Option < Instance < ' tcx > > ,
18261848 ) {
1827- // FIXME: implement support for explicit tail calls like rustc_codegen_llvm.
1828- self . tcx . dcx ( ) . emit_fatal ( errors:: ExplicitTailCallsUnsupported ) ;
1849+ // `emit_call` returns a bare call for here, it has not been assigned or passed to add_eval.
1850+ let call = self . build_call ( llty, Some ( fn_abi) , llfn, args, funclet, true ) ;
1851+ call. set_require_tail_call ( true ) ;
1852+
1853+ let return_type = self . current_func ( ) . get_return_type ( ) ;
1854+ let void_type = self . context . new_type :: < ( ) > ( ) ;
1855+
1856+ if return_type == void_type {
1857+ // For a void return the call is emitted as its own statement, immediately
1858+ // followed by a void return, so the tail call sits in tail position.
1859+ self . llbb ( ) . add_eval ( self . location , call) ;
1860+ self . ret_void ( ) ;
1861+ } else {
1862+ self . ret ( call)
1863+ }
18291864 }
18301865
18311866 fn zext ( & mut self , value : RValue < ' gcc > , dest_typ : Type < ' gcc > ) -> RValue < ' gcc > {
0 commit comments