@@ -239,6 +239,31 @@ impl<'a, 'tcx> TerminatorCodegenHelper<'tcx> {
239
239
}
240
240
}
241
241
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
+
242
267
/// Generates inline assembly with optional `destination` and `unwind`.
243
268
fn do_inlineasm < Bx : BuilderMethods < ' a , ' tcx > > (
244
269
& self ,
@@ -1077,6 +1102,242 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
1077
1102
)
1078
1103
}
1079
1104
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
+
1080
1341
fn codegen_asm_terminator (
1081
1342
& mut self ,
1082
1343
helper : TerminatorCodegenHelper < ' tcx > ,
@@ -1295,12 +1556,9 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
1295
1556
mergeable_succ ( ) ,
1296
1557
) ,
1297
1558
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
1304
1562
}
1305
1563
1306
1564
mir:: TerminatorKind :: GeneratorDrop | mir:: TerminatorKind :: Yield { .. } => {
0 commit comments