@@ -239,6 +239,31 @@ impl<'a, 'tcx> TerminatorCodegenHelper<'tcx> {
239239 }
240240 }
241241
242+ /// **Tail** call `fn_ptr` of `fn_abi` with the arguments `llargs`.
243+ fn do_tail_call < Bx : BuilderMethods < ' a , ' tcx > > (
244+ & self ,
245+ fx : & mut FunctionCx < ' a , ' tcx , Bx > ,
246+ bx : & mut Bx ,
247+ fn_abi : & ' tcx FnAbi < ' tcx , Ty < ' tcx > > ,
248+ fn_ptr : Bx :: Value ,
249+ llargs : & [ Bx :: Value ] ,
250+ copied_constant_arguments : & [ PlaceRef < ' tcx , <Bx as BackendTypes >:: Value > ] ,
251+ ) {
252+ let fn_ty = bx. fn_decl_backend_type ( & fn_abi) ;
253+
254+ let fn_attrs = if bx. tcx ( ) . def_kind ( fx. instance . def_id ( ) ) . has_codegen_attrs ( ) {
255+ Some ( bx. tcx ( ) . codegen_fn_attrs ( fx. instance . def_id ( ) ) )
256+ } else {
257+ None
258+ } ;
259+
260+ bx. tail_call ( fn_ty, fn_attrs, fn_abi, fn_ptr, & llargs, self . funclet ( fx) ) ;
261+
262+ for tmp in copied_constant_arguments {
263+ bx. lifetime_end ( tmp. llval , tmp. layout . size ) ;
264+ }
265+ }
266+
242267 /// Generates inline assembly with optional `destination` and `unwind`.
243268 fn do_inlineasm < Bx : BuilderMethods < ' a , ' tcx > > (
244269 & self ,
@@ -1077,6 +1102,242 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
10771102 )
10781103 }
10791104
1105+ fn codegen_tail_call_terminator (
1106+ & mut self ,
1107+ helper : TerminatorCodegenHelper < ' tcx > ,
1108+ bx : & mut Bx ,
1109+ terminator : & mir:: Terminator < ' tcx > ,
1110+ func : & mir:: Operand < ' tcx > ,
1111+ args : & [ mir:: Operand < ' tcx > ] ,
1112+ fn_span : Span ,
1113+ ) {
1114+ let source_info = terminator. source_info ;
1115+ let span = source_info. span ;
1116+
1117+ // Create the callee. This is a fn ptr or zero-sized and hence a kind of scalar.
1118+ let callee = self . codegen_operand ( bx, func) ;
1119+
1120+ let ( instance, mut llfn) = match * callee. layout . ty . kind ( ) {
1121+ ty:: FnDef ( def_id, substs) => (
1122+ Some (
1123+ ty:: Instance :: expect_resolve (
1124+ bx. tcx ( ) ,
1125+ ty:: ParamEnv :: reveal_all ( ) ,
1126+ def_id,
1127+ substs,
1128+ )
1129+ . polymorphize ( bx. tcx ( ) ) ,
1130+ ) ,
1131+ None ,
1132+ ) ,
1133+ ty:: FnPtr ( _) => ( None , Some ( callee. immediate ( ) ) ) ,
1134+ _ => bug ! ( "{} is not callable" , callee. layout. ty) ,
1135+ } ;
1136+ let def = instance. map ( |i| i. def ) ;
1137+
1138+ if let Some ( ty:: InstanceDef :: DropGlue ( ..) ) = def {
1139+ bug ! ( "tail-calling drop glue should not be possible" ) ;
1140+ }
1141+
1142+ // FIXME(eddyb) avoid computing this if possible, when `instance` is
1143+ // available - right now `sig` is only needed for getting the `abi`
1144+ // and figuring out how many extra args were passed to a C-variadic `fn`.
1145+ let sig = callee. layout . ty . fn_sig ( bx. tcx ( ) ) ;
1146+ let abi = sig. abi ( ) ;
1147+
1148+ if let Some ( ty:: InstanceDef :: Intrinsic ( def_id) ) = def {
1149+ span_bug ! (
1150+ fn_span,
1151+ "Attempting to tail-call `{}` intrinsic" ,
1152+ bx. tcx( ) . item_name( def_id)
1153+ ) ;
1154+ } ;
1155+
1156+ let extra_args = & args[ sig. inputs ( ) . skip_binder ( ) . len ( ) ..] ;
1157+ let extra_args = bx. tcx ( ) . mk_type_list_from_iter ( extra_args. iter ( ) . map ( |op_arg| {
1158+ let op_ty = op_arg. ty ( self . mir , bx. tcx ( ) ) ;
1159+ self . monomorphize ( op_ty)
1160+ } ) ) ;
1161+
1162+ let fn_abi = match instance {
1163+ Some ( instance) => bx. fn_abi_of_instance ( instance, extra_args) ,
1164+ None => bx. fn_abi_of_fn_ptr ( sig, extra_args) ,
1165+ } ;
1166+
1167+ // The arguments we'll be passing. Plus one to account for outptr, if used.
1168+ let arg_count = fn_abi. args . len ( ) + fn_abi. ret . is_indirect ( ) as usize ;
1169+ let mut llargs = Vec :: with_capacity ( arg_count) ;
1170+
1171+ if fn_abi. ret . is_indirect ( ) {
1172+ let LocalRef :: Place ( place) = self . locals [ mir:: RETURN_PLACE ]
1173+ else { bug ! ( ) } ;
1174+
1175+ llargs. push ( place. llval ) ;
1176+ }
1177+
1178+ // Split the rust-call tupled arguments off.
1179+ let ( first_args, untuple) = if abi == Abi :: RustCall && !args. is_empty ( ) {
1180+ let ( tup, args) = args. split_last ( ) . unwrap ( ) ;
1181+ ( args, Some ( tup) )
1182+ } else {
1183+ ( args, None )
1184+ } ;
1185+
1186+ // FIXME(explicit_tail_calls): refactor this into a separate function, deduplicate with `Call`
1187+ let mut copied_constant_arguments = vec ! [ ] ;
1188+ ' make_args: for ( i, arg) in first_args. iter ( ) . enumerate ( ) {
1189+ let mut op = self . codegen_operand ( bx, arg) ;
1190+
1191+ if let ( 0 , Some ( ty:: InstanceDef :: Virtual ( _, idx) ) ) = ( i, def) {
1192+ match op. val {
1193+ Pair ( data_ptr, meta) => {
1194+ // In the case of Rc<Self>, we need to explicitly pass a
1195+ // *mut RcBox<Self> with a Scalar (not ScalarPair) ABI. This is a hack
1196+ // that is understood elsewhere in the compiler as a method on
1197+ // `dyn Trait`.
1198+ // To get a `*mut RcBox<Self>`, we just keep unwrapping newtypes until
1199+ // we get a value of a built-in pointer type.
1200+ //
1201+ // This is also relevant for `Pin<&mut Self>`, where we need to peel the `Pin`.
1202+ ' descend_newtypes: while !op. layout . ty . is_unsafe_ptr ( )
1203+ && !op. layout . ty . is_ref ( )
1204+ {
1205+ for i in 0 ..op. layout . fields . count ( ) {
1206+ let field = op. extract_field ( bx, i) ;
1207+ if !field. layout . is_zst ( ) {
1208+ // we found the one non-zero-sized field that is allowed
1209+ // now find *its* non-zero-sized field, or stop if it's a
1210+ // pointer
1211+ op = field;
1212+ continue ' descend_newtypes;
1213+ }
1214+ }
1215+
1216+ span_bug ! ( span, "receiver has no non-zero-sized fields {:?}" , op) ;
1217+ }
1218+
1219+ // now that we have `*dyn Trait` or `&dyn Trait`, split it up into its
1220+ // data pointer and vtable. Look up the method in the vtable, and pass
1221+ // the data pointer as the first argument
1222+ llfn = Some ( meth:: VirtualIndex :: from_index ( idx) . get_fn (
1223+ bx,
1224+ meta,
1225+ op. layout . ty ,
1226+ & fn_abi,
1227+ ) ) ;
1228+ llargs. push ( data_ptr) ;
1229+ continue ' make_args;
1230+ }
1231+ Ref ( data_ptr, Some ( meta) , _) => {
1232+ // by-value dynamic dispatch
1233+ llfn = Some ( meth:: VirtualIndex :: from_index ( idx) . get_fn (
1234+ bx,
1235+ meta,
1236+ op. layout . ty ,
1237+ & fn_abi,
1238+ ) ) ;
1239+ llargs. push ( data_ptr) ;
1240+ continue ;
1241+ }
1242+ Immediate ( _) => {
1243+ // See comment above explaining why we peel these newtypes
1244+ ' descend_newtypes: while !op. layout . ty . is_unsafe_ptr ( )
1245+ && !op. layout . ty . is_ref ( )
1246+ {
1247+ for i in 0 ..op. layout . fields . count ( ) {
1248+ let field = op. extract_field ( bx, i) ;
1249+ if !field. layout . is_zst ( ) {
1250+ // we found the one non-zero-sized field that is allowed
1251+ // now find *its* non-zero-sized field, or stop if it's a
1252+ // pointer
1253+ op = field;
1254+ continue ' descend_newtypes;
1255+ }
1256+ }
1257+
1258+ span_bug ! ( span, "receiver has no non-zero-sized fields {:?}" , op) ;
1259+ }
1260+
1261+ // Make sure that we've actually unwrapped the rcvr down
1262+ // to a pointer or ref to `dyn* Trait`.
1263+ if !op. layout . ty . builtin_deref ( true ) . unwrap ( ) . ty . is_dyn_star ( ) {
1264+ span_bug ! ( span, "can't codegen a virtual call on {:#?}" , op) ;
1265+ }
1266+ let place = op. deref ( bx. cx ( ) ) ;
1267+ let data_ptr = place. project_field ( bx, 0 ) ;
1268+ let meta_ptr = place. project_field ( bx, 1 ) ;
1269+ let meta = bx. load_operand ( meta_ptr) ;
1270+ llfn = Some ( meth:: VirtualIndex :: from_index ( idx) . get_fn (
1271+ bx,
1272+ meta. immediate ( ) ,
1273+ op. layout . ty ,
1274+ & fn_abi,
1275+ ) ) ;
1276+ llargs. push ( data_ptr. llval ) ;
1277+ continue ;
1278+ }
1279+ _ => {
1280+ span_bug ! ( span, "can't codegen a virtual call on {:#?}" , op) ;
1281+ }
1282+ }
1283+ }
1284+
1285+ // The callee needs to own the argument memory if we pass it
1286+ // by-ref, so make a local copy of non-immediate constants.
1287+ match ( arg, op. val ) {
1288+ ( & mir:: Operand :: Copy ( _) , Ref ( _, None , _) )
1289+ | ( & mir:: Operand :: Constant ( _) , Ref ( _, None , _) ) => {
1290+ let tmp = PlaceRef :: alloca ( bx, op. layout ) ;
1291+ bx. lifetime_start ( tmp. llval , tmp. layout . size ) ;
1292+ op. val . store ( bx, tmp) ;
1293+ op. val = Ref ( tmp. llval , None , tmp. align ) ;
1294+ copied_constant_arguments. push ( tmp) ;
1295+ }
1296+ _ => { }
1297+ }
1298+
1299+ self . codegen_argument ( bx, op, & mut llargs, & fn_abi. args [ i] ) ;
1300+ }
1301+ let num_untupled = untuple. map ( |tup| {
1302+ self . codegen_arguments_untupled ( bx, tup, & mut llargs, & fn_abi. args [ first_args. len ( ) ..] )
1303+ } ) ;
1304+
1305+ let needs_location =
1306+ instance. map_or ( false , |i| i. def . requires_caller_location ( self . cx . tcx ( ) ) ) ;
1307+ if needs_location {
1308+ let mir_args = if let Some ( num_untupled) = num_untupled {
1309+ first_args. len ( ) + num_untupled
1310+ } else {
1311+ args. len ( )
1312+ } ;
1313+ assert_eq ! (
1314+ fn_abi. args. len( ) ,
1315+ mir_args + 1 ,
1316+ "#[track_caller] fn's must have 1 more argument in their ABI than in their MIR: {:?} {:?} {:?}" ,
1317+ instance,
1318+ fn_span,
1319+ fn_abi,
1320+ ) ;
1321+ let location =
1322+ self . get_caller_location ( bx, mir:: SourceInfo { span : fn_span, ..source_info } ) ;
1323+ debug ! (
1324+ "codegen_tail_call_terminator({:?}): location={:?} (fn_span {:?})" ,
1325+ terminator, location, fn_span
1326+ ) ;
1327+
1328+ let last_arg = fn_abi. args . last ( ) . unwrap ( ) ;
1329+ self . codegen_argument ( bx, location, & mut llargs, last_arg) ;
1330+ }
1331+
1332+ let fn_ptr = match ( instance, llfn) {
1333+ ( Some ( instance) , None ) => bx. get_fn_addr ( instance) ,
1334+ ( _, Some ( llfn) ) => llfn,
1335+ _ => span_bug ! ( span, "no instance or llfn for tail-call" ) ,
1336+ } ;
1337+
1338+ helper. do_tail_call ( self , bx, fn_abi, fn_ptr, & llargs, & copied_constant_arguments) ;
1339+ }
1340+
10801341 fn codegen_asm_terminator (
10811342 & mut self ,
10821343 helper : TerminatorCodegenHelper < ' tcx > ,
@@ -1295,12 +1556,9 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
12951556 mergeable_succ ( ) ,
12961557 ) ,
12971558
1298- mir:: TerminatorKind :: TailCall { .. } => {
1299- // FIXME(explicit_tail_calls): implement tail calls in ssa backend
1300- span_bug ! (
1301- terminator. source_info. span,
1302- "`TailCall` terminator is not yet supported by `rustc_codegen_ssa`"
1303- )
1559+ mir:: TerminatorKind :: TailCall { ref func, ref args, fn_span } => {
1560+ self . codegen_tail_call_terminator ( helper, bx, terminator, func, args, fn_span) ;
1561+ MergingSucc :: False
13041562 }
13051563
13061564 mir:: TerminatorKind :: GeneratorDrop | mir:: TerminatorKind :: Yield { .. } => {
0 commit comments