]> git.lizzy.rs Git - rust.git/blob - src/base.rs
16394fd50cf0859bc5edaeb49a42a5373dce9494
[rust.git] / src / base.rs
1 use rustc_middle::ty::adjustment::PointerCast;
2 use rustc_index::vec::IndexVec;
3
4 use crate::prelude::*;
5
6 pub(crate) fn trans_fn<'clif, 'tcx, B: Backend + 'static>(
7     cx: &mut crate::CodegenCx<'clif, 'tcx, B>,
8     instance: Instance<'tcx>,
9     linkage: Linkage,
10 ) {
11     let tcx = cx.tcx;
12
13     let mir = *tcx.instance_mir(instance.def);
14
15     // Declare function
16     let (name, sig) = get_function_name_and_sig(tcx, cx.module.isa().triple(), instance, false);
17     let func_id = cx.module.declare_function(&name, linkage, &sig).unwrap();
18     let mut debug_context = cx
19         .debug_context
20         .as_mut()
21         .map(|debug_context| FunctionDebugContext::new(debug_context, instance, func_id, &name));
22
23     // Make FunctionBuilder
24     let context = &mut cx.cached_context;
25     context.clear();
26     context.func.name = ExternalName::user(0, func_id.as_u32());
27     context.func.signature = sig;
28     context.func.collect_debug_info();
29     let mut func_ctx = FunctionBuilderContext::new();
30     let mut bcx = FunctionBuilder::new(&mut context.func, &mut func_ctx);
31
32     // Predefine block's
33     let start_block = bcx.create_block();
34     let block_map: IndexVec<BasicBlock, Block> = (0..mir.basic_blocks().len()).map(|_| bcx.create_block()).collect();
35
36     // Make FunctionCx
37     let pointer_type = cx.module.target_config().pointer_type();
38     let clif_comments = crate::pretty_clif::CommentWriter::new(tcx, instance);
39
40     let mut fx = FunctionCx {
41         tcx,
42         module: cx.module,
43         pointer_type,
44
45         instance,
46         mir,
47
48         bcx,
49         block_map,
50         local_map: FxHashMap::with_capacity_and_hasher(mir.local_decls.len(), Default::default()),
51         caller_location: None, // set by `codegen_fn_prelude`
52         cold_blocks: EntitySet::new(),
53
54         clif_comments,
55         constants_cx: &mut cx.constants_cx,
56         vtables: &mut cx.vtables,
57         source_info_set: indexmap::IndexSet::new(),
58     };
59
60     let arg_uninhabited = fx.mir.args_iter().any(|arg| fx.layout_of(fx.monomorphize(&fx.mir.local_decls[arg].ty)).abi.is_uninhabited());
61     let is_call_once_for_box = name.starts_with("_ZN83_$LT$alloc..boxed..Box$LT$F$GT$$u20$as$u20$core..ops..function..FnOnce$LT$A$GT$$GT$9call_once");
62
63     if arg_uninhabited {
64         fx.bcx.append_block_params_for_function_params(fx.block_map[START_BLOCK]);
65         fx.bcx.switch_to_block(fx.block_map[START_BLOCK]);
66         crate::trap::trap_unreachable(&mut fx, "function has uninhabited argument");
67     } else if is_call_once_for_box {
68         // HACK implement `<Box<F> as FnOnce>::call_once` without `alloca`.
69         tcx.sess.time("codegen prelude", || crate::abi::codegen_fn_prelude(&mut fx, start_block, false));
70         fx.bcx.switch_to_block(fx.block_map[START_BLOCK]);
71         let bb_data = &fx.mir.basic_blocks()[START_BLOCK];
72         let destination = match &bb_data.terminator().kind {
73             TerminatorKind::Call {
74                 func,
75                 args,
76                 destination,
77                 cleanup: _,
78                 from_hir_call: _,
79             } => {
80                 assert_eq!(args.len(), 2);
81
82                 let closure_arg = Local::new(1);
83                 let closure_local = args[0].place().unwrap().as_local().unwrap();
84                 assert_eq!(fx.mir.local_decls[closure_local].ty, fx.mir.local_decls[closure_arg].ty.builtin_deref(true).unwrap().ty);
85                 let closure_deref = fx.local_map[&closure_arg].place_deref(&mut fx);
86                 fx.local_map.insert(closure_local, closure_deref);
87
88                 let args_arg = Local::new(2);
89                 let args_local = args[1].place().unwrap().as_local().unwrap();
90                 assert_eq!(fx.mir.local_decls[args_local].ty, fx.mir.local_decls[args_arg].ty);
91                 fx.local_map.insert(args_local, fx.local_map[&args_arg]);
92
93                 fx.tcx.sess.time("codegen call", || crate::abi::codegen_terminator_call(
94                     &mut fx,
95                     bb_data.terminator().source_info.span,
96                     func,
97                     args,
98                     *destination,
99                 ));
100                 destination.map(|(_ret_place, ret_block)| ret_block)
101             }
102             _ => unreachable!(),
103         };
104
105         let destination = if let Some(destination) = destination {
106             fx.bcx.switch_to_block(fx.block_map[destination]);
107             let bb_data = &fx.mir.basic_blocks()[destination];
108             match &bb_data.terminator().kind {
109                 TerminatorKind::Call {
110                     func,
111                     args,
112                     destination,
113                     cleanup: _,
114                     from_hir_call: _,
115                 } => {
116                     match destination {
117                         Some((ret_place, _ret_block)) => {
118                             fx.local_map.insert(ret_place.as_local().unwrap(), CPlace::no_place(fx.layout_of(fx.tcx.mk_unit())));
119                         }
120                         None => {}
121                     }
122
123                     assert_eq!(args.len(), 1);
124                     fx.tcx.sess.time("codegen call", || crate::abi::codegen_terminator_call(
125                         &mut fx,
126                         bb_data.terminator().source_info.span,
127                         func,
128                         args,
129                         *destination,
130                     ));
131                     destination.map(|(_ret_place, ret_block)| ret_block)
132                 }
133                 _ => unreachable!(),
134             }
135         } else {
136             None
137         };
138
139         if let Some(destination) = destination {
140             fx.bcx.switch_to_block(fx.block_map[destination]);
141             let bb_data = &fx.mir.basic_blocks()[destination];
142             match &bb_data.terminator().kind {
143                 TerminatorKind::Return => crate::abi::codegen_return(&mut fx),
144                 _ => unreachable!(),
145             }
146         }
147     } else {
148         tcx.sess.time("codegen clif ir", || {
149             tcx.sess.time("codegen prelude", || crate::abi::codegen_fn_prelude(&mut fx, start_block, true));
150             codegen_fn_content(&mut fx);
151         });
152     }
153
154     // Recover all necessary data from fx, before accessing func will prevent future access to it.
155     let instance = fx.instance;
156     let mut clif_comments = fx.clif_comments;
157     let source_info_set = fx.source_info_set;
158     let local_map = fx.local_map;
159     let cold_blocks = fx.cold_blocks;
160
161     #[cfg(debug_assertions)]
162     crate::pretty_clif::write_clif_file(cx.tcx, "unopt", instance, &context.func, &clif_comments, None);
163
164     // Verify function
165     verify_func(tcx, &clif_comments, &context.func);
166
167     // Perform rust specific optimizations
168     tcx.sess.time("optimize clif ir", || {
169         crate::optimize::optimize_function(tcx, instance, context, &cold_blocks, &mut clif_comments);
170     });
171
172     // If the return block is not reachable, then the SSA builder may have inserted a `iconst.i128`
173     // instruction, which doesn't have an encoding.
174     context.compute_cfg();
175     context.compute_domtree();
176     context.eliminate_unreachable_code(cx.module.isa()).unwrap();
177
178     // Define function
179     let module = &mut cx.module;
180     tcx.sess.time(
181         "define function",
182         || module.define_function(
183             func_id,
184             context,
185             &mut cranelift_codegen::binemit::NullTrapSink {},
186         ).unwrap(),
187     );
188
189     // Write optimized function to file for debugging
190     #[cfg(debug_assertions)]
191     {
192         let value_ranges = context
193             .build_value_labels_ranges(cx.module.isa())
194             .expect("value location ranges");
195
196         crate::pretty_clif::write_clif_file(
197             cx.tcx,
198             "opt",
199             instance,
200             &context.func,
201             &clif_comments,
202             Some(&value_ranges),
203         );
204     }
205
206     // Define debuginfo for function
207     let isa = cx.module.isa();
208     tcx.sess.time("generate debug info", || {
209         debug_context
210             .as_mut()
211             .map(|x| x.define(context, isa, &source_info_set, local_map));
212     });
213
214     // Clear context to make it usable for the next function
215     context.clear();
216 }
217
218 pub(crate) fn verify_func(tcx: TyCtxt<'_>, writer: &crate::pretty_clif::CommentWriter, func: &Function) {
219     tcx.sess.time("verify clif ir", || {
220         let flags = settings::Flags::new(settings::builder());
221         match ::cranelift_codegen::verify_function(&func, &flags) {
222             Ok(_) => {}
223             Err(err) => {
224                 tcx.sess.err(&format!("{:?}", err));
225                 let pretty_error = ::cranelift_codegen::print_errors::pretty_verifier_error(
226                     &func,
227                     None,
228                     Some(Box::new(writer)),
229                     err,
230                 );
231                 tcx.sess
232                     .fatal(&format!("cranelift verify error:\n{}", pretty_error));
233             }
234         }
235     });
236 }
237
238 fn codegen_fn_content(fx: &mut FunctionCx<'_, '_, impl Backend>) {
239     for (bb, bb_data) in fx.mir.basic_blocks().iter_enumerated() {
240         let block = fx.get_block(bb);
241         fx.bcx.switch_to_block(block);
242
243         if bb_data.is_cleanup {
244             // Unwinding after panicking is not supported
245             continue;
246
247             // FIXME once unwinding is supported uncomment next lines
248             // // Unwinding is unlikely to happen, so mark cleanup block's as cold.
249             // fx.cold_blocks.insert(block);
250         }
251
252         fx.bcx.ins().nop();
253         for stmt in &bb_data.statements {
254             fx.set_debug_loc(stmt.source_info);
255             trans_stmt(fx, block, stmt);
256         }
257
258         #[cfg(debug_assertions)]
259         {
260             let mut terminator_head = "\n".to_string();
261             bb_data
262                 .terminator()
263                 .kind
264                 .fmt_head(&mut terminator_head)
265                 .unwrap();
266             let inst = fx.bcx.func.layout.last_inst(block).unwrap();
267             fx.add_comment(inst, terminator_head);
268         }
269
270         fx.set_debug_loc(bb_data.terminator().source_info);
271
272         match &bb_data.terminator().kind {
273             TerminatorKind::Goto { target } => {
274                 if let TerminatorKind::Return = fx.mir[*target].terminator().kind {
275                     let mut can_immediately_return = true;
276                     for stmt in &fx.mir[*target].statements {
277                         if let StatementKind::StorageDead(_) = stmt.kind {
278                         } else {
279                             // FIXME Can sometimes happen, see rust-lang/rust#70531
280                             can_immediately_return = false;
281                             break;
282                         }
283                     }
284
285                     if can_immediately_return {
286                         crate::abi::codegen_return(fx);
287                         continue;
288                     }
289                 }
290
291                 let block = fx.get_block(*target);
292                 fx.bcx.ins().jump(block, &[]);
293             }
294             TerminatorKind::Return => {
295                 crate::abi::codegen_return(fx);
296             }
297             TerminatorKind::Assert {
298                 cond,
299                 expected,
300                 msg,
301                 target,
302                 cleanup: _,
303             } => {
304                 if !fx.tcx.sess.overflow_checks() {
305                     if let mir::AssertKind::OverflowNeg = *msg {
306                         let target = fx.get_block(*target);
307                         fx.bcx.ins().jump(target, &[]);
308                         continue;
309                     }
310                 }
311                 let cond = trans_operand(fx, cond).load_scalar(fx);
312
313                 let target = fx.get_block(*target);
314                 let failure = fx.bcx.create_block();
315                 fx.cold_blocks.insert(failure);
316
317                 if *expected {
318                     fx.bcx.ins().brz(cond, failure, &[]);
319                 } else {
320                     fx.bcx.ins().brnz(cond, failure, &[]);
321                 };
322                 fx.bcx.ins().jump(target, &[]);
323
324                 fx.bcx.switch_to_block(failure);
325                 trap_panic(
326                     fx,
327                     format!(
328                         "[panic] Assert {:?} at {:?} failed.",
329                         msg,
330                         bb_data.terminator().source_info.span
331                     ),
332                 );
333             }
334
335             TerminatorKind::SwitchInt {
336                 discr,
337                 switch_ty: _,
338                 values,
339                 targets,
340             } => {
341                 let discr = trans_operand(fx, discr).load_scalar(fx);
342                 let mut switch = ::cranelift_frontend::Switch::new();
343                 for (i, value) in values.iter().enumerate() {
344                     let block = fx.get_block(targets[i]);
345                     switch.set_entry(*value as u64, block);
346                 }
347                 let otherwise_block = fx.get_block(targets[targets.len() - 1]);
348                 switch.emit(&mut fx.bcx, discr, otherwise_block);
349             }
350             TerminatorKind::Call {
351                 func,
352                 args,
353                 destination,
354                 cleanup: _,
355                 from_hir_call: _,
356             } => {
357                 fx.tcx.sess.time("codegen call", || crate::abi::codegen_terminator_call(
358                     fx,
359                     bb_data.terminator().source_info.span,
360                     func,
361                     args,
362                     *destination,
363                 ));
364             }
365             TerminatorKind::Resume | TerminatorKind::Abort => {
366                 trap_unreachable(fx, "[corruption] Unwinding bb reached.");
367             }
368             TerminatorKind::Unreachable => {
369                 trap_unreachable(fx, "[corruption] Hit unreachable code.");
370             }
371             TerminatorKind::Yield { .. }
372             | TerminatorKind::FalseEdges { .. }
373             | TerminatorKind::FalseUnwind { .. }
374             | TerminatorKind::DropAndReplace { .. }
375             | TerminatorKind::GeneratorDrop => {
376                 bug!("shouldn't exist at trans {:?}", bb_data.terminator());
377             }
378             TerminatorKind::Drop {
379                 location,
380                 target,
381                 unwind: _,
382             } => {
383                 let drop_place = trans_place(fx, *location);
384                 crate::abi::codegen_drop(fx, bb_data.terminator().source_info.span, drop_place);
385
386                 let target_block = fx.get_block(*target);
387                 fx.bcx.ins().jump(target_block, &[]);
388             }
389         };
390     }
391
392     fx.bcx.seal_all_blocks();
393     fx.bcx.finalize();
394 }
395
396 fn trans_stmt<'tcx>(
397     fx: &mut FunctionCx<'_, 'tcx, impl Backend>,
398     #[allow(unused_variables)]
399     cur_block: Block,
400     stmt: &Statement<'tcx>,
401 ) {
402     let _print_guard = PrintOnPanic(|| format!("stmt {:?}", stmt));
403
404     fx.set_debug_loc(stmt.source_info);
405
406     #[cfg(false_debug_assertions)]
407     match &stmt.kind {
408         StatementKind::StorageLive(..) | StatementKind::StorageDead(..) => {} // Those are not very useful
409         _ => {
410             let inst = fx.bcx.func.layout.last_inst(cur_block).unwrap();
411             fx.add_comment(inst, format!("{:?}", stmt));
412         }
413     }
414
415     match &stmt.kind {
416         StatementKind::SetDiscriminant {
417             place,
418             variant_index,
419         } => {
420             let place = trans_place(fx, **place);
421             crate::discriminant::codegen_set_discriminant(fx, place, *variant_index);
422         }
423         StatementKind::Assign(to_place_and_rval) => {
424             let lval = trans_place(fx, to_place_and_rval.0);
425             let dest_layout = lval.layout();
426             match &to_place_and_rval.1 {
427                 Rvalue::Use(operand) => {
428                     let val = trans_operand(fx, operand);
429                     lval.write_cvalue(fx, val);
430                 }
431                 Rvalue::Ref(_, _, place) | Rvalue::AddressOf(_, place) => {
432                     let place = trans_place(fx, *place);
433                     place.write_place_ref(fx, lval);
434                 }
435                 Rvalue::BinaryOp(bin_op, lhs, rhs) => {
436                     let lhs = trans_operand(fx, lhs);
437                     let rhs = trans_operand(fx, rhs);
438
439                     let res = crate::num::codegen_binop(fx, *bin_op, lhs, rhs);
440                     lval.write_cvalue(fx, res);
441                 }
442                 Rvalue::CheckedBinaryOp(bin_op, lhs, rhs) => {
443                     let lhs = trans_operand(fx, lhs);
444                     let rhs = trans_operand(fx, rhs);
445
446                     let res = if !fx.tcx.sess.overflow_checks() {
447                         let val =
448                             crate::num::trans_int_binop(fx, *bin_op, lhs, rhs).load_scalar(fx);
449                         let is_overflow = fx.bcx.ins().iconst(types::I8, 0);
450                         CValue::by_val_pair(val, is_overflow, lval.layout())
451                     } else {
452                         crate::num::trans_checked_int_binop(fx, *bin_op, lhs, rhs)
453                     };
454
455                     lval.write_cvalue(fx, res);
456                 }
457                 Rvalue::UnaryOp(un_op, operand) => {
458                     let operand = trans_operand(fx, operand);
459                     let layout = operand.layout();
460                     let val = operand.load_scalar(fx);
461                     let res = match un_op {
462                         UnOp::Not => {
463                             match layout.ty.kind {
464                                 ty::Bool => {
465                                     let res = fx.bcx.ins().icmp_imm(IntCC::Equal, val, 0);
466                                     CValue::by_val(fx.bcx.ins().bint(types::I8, res), layout)
467                                 }
468                                 ty::Uint(_) | ty::Int(_) => {
469                                     CValue::by_val(fx.bcx.ins().bnot(val), layout)
470                                 }
471                                 _ => unreachable!("un op Not for {:?}", layout.ty),
472                             }
473                         }
474                         UnOp::Neg => match layout.ty.kind {
475                             ty::Int(IntTy::I128) => {
476                                 // FIXME remove this case once ineg.i128 works
477                                 let zero = CValue::const_val(fx, layout, 0);
478                                 crate::num::trans_int_binop(fx, BinOp::Sub, zero, operand)
479                             }
480                             ty::Int(_) => {
481                                 CValue::by_val(fx.bcx.ins().ineg(val), layout)
482                             }
483                             ty::Float(_) => {
484                                 CValue::by_val(fx.bcx.ins().fneg(val), layout)
485                             }
486                             _ => unreachable!("un op Neg for {:?}", layout.ty),
487                         },
488                     };
489                     lval.write_cvalue(fx, res);
490                 }
491                 Rvalue::Cast(CastKind::Pointer(PointerCast::ReifyFnPointer), operand, to_ty) => {
492                     let from_ty = fx.monomorphize(&operand.ty(&fx.mir.local_decls, fx.tcx));
493                     let to_layout = fx.layout_of(fx.monomorphize(to_ty));
494                     match from_ty.kind {
495                         ty::FnDef(def_id, substs) => {
496                             let func_ref = fx.get_function_ref(
497                                 Instance::resolve_for_fn_ptr(fx.tcx, ParamEnv::reveal_all(), def_id, substs)
498                                     .unwrap(),
499                             );
500                             let func_addr = fx.bcx.ins().func_addr(fx.pointer_type, func_ref);
501                             lval.write_cvalue(fx, CValue::by_val(func_addr, to_layout));
502                         }
503                         _ => bug!("Trying to ReifyFnPointer on non FnDef {:?}", from_ty),
504                     }
505                 }
506                 Rvalue::Cast(CastKind::Pointer(PointerCast::UnsafeFnPointer), operand, to_ty)
507                 | Rvalue::Cast(CastKind::Pointer(PointerCast::MutToConstPointer), operand, to_ty)
508                 | Rvalue::Cast(CastKind::Pointer(PointerCast::ArrayToPointer), operand, to_ty) => {
509                     let to_layout = fx.layout_of(fx.monomorphize(to_ty));
510                     let operand = trans_operand(fx, operand);
511                     lval.write_cvalue(fx, operand.cast_pointer_to(to_layout));
512                 }
513                 Rvalue::Cast(CastKind::Misc, operand, to_ty) => {
514                     let operand = trans_operand(fx, operand);
515                     let from_ty = operand.layout().ty;
516                     let to_ty = fx.monomorphize(to_ty);
517
518                     fn is_fat_ptr<'tcx>(
519                         fx: &FunctionCx<'_, 'tcx, impl Backend>,
520                         ty: Ty<'tcx>,
521                     ) -> bool {
522                         ty.builtin_deref(true)
523                             .map(
524                                 |ty::TypeAndMut {
525                                      ty: pointee_ty,
526                                      mutbl: _,
527                                  }| has_ptr_meta(fx.tcx, pointee_ty),
528                             )
529                             .unwrap_or(false)
530                     }
531
532                     if is_fat_ptr(fx, from_ty) {
533                         if is_fat_ptr(fx, to_ty) {
534                             // fat-ptr -> fat-ptr
535                             lval.write_cvalue(fx, operand.cast_pointer_to(dest_layout));
536                         } else {
537                             // fat-ptr -> thin-ptr
538                             let (ptr, _extra) = operand.load_scalar_pair(fx);
539                             lval.write_cvalue(fx, CValue::by_val(ptr, dest_layout))
540                         }
541                     } else if let ty::Adt(adt_def, _substs) = from_ty.kind {
542                         // enum -> discriminant value
543                         assert!(adt_def.is_enum());
544                         match to_ty.kind {
545                             ty::Uint(_) | ty::Int(_) => {}
546                             _ => unreachable!("cast adt {} -> {}", from_ty, to_ty),
547                         }
548
549                         let discr = crate::discriminant::codegen_get_discriminant(
550                             fx,
551                             operand,
552                             fx.layout_of(to_ty),
553                         );
554                         lval.write_cvalue(fx, discr);
555                     } else {
556                         let to_clif_ty = fx.clif_type(to_ty).unwrap();
557                         let from = operand.load_scalar(fx);
558
559                         let res = clif_int_or_float_cast(
560                             fx,
561                             from,
562                             type_sign(from_ty),
563                             to_clif_ty,
564                             type_sign(to_ty),
565                         );
566                         lval.write_cvalue(fx, CValue::by_val(res, dest_layout));
567                     }
568                 }
569                 Rvalue::Cast(CastKind::Pointer(PointerCast::ClosureFnPointer(_)), operand, _to_ty) => {
570                     let operand = trans_operand(fx, operand);
571                     match operand.layout().ty.kind {
572                         ty::Closure(def_id, substs) => {
573                             let instance = Instance::resolve_closure(
574                                 fx.tcx,
575                                 def_id,
576                                 substs,
577                                 ty::ClosureKind::FnOnce,
578                             );
579                             let func_ref = fx.get_function_ref(instance);
580                             let func_addr = fx.bcx.ins().func_addr(fx.pointer_type, func_ref);
581                             lval.write_cvalue(fx, CValue::by_val(func_addr, lval.layout()));
582                         }
583                         _ => bug!("{} cannot be cast to a fn ptr", operand.layout().ty),
584                     }
585                 }
586                 Rvalue::Cast(CastKind::Pointer(PointerCast::Unsize), operand, _to_ty) => {
587                     let operand = trans_operand(fx, operand);
588                     operand.unsize_value(fx, lval);
589                 }
590                 Rvalue::Discriminant(place) => {
591                     let place = trans_place(fx, *place);
592                     let value = place.to_cvalue(fx);
593                     let discr =
594                         crate::discriminant::codegen_get_discriminant(fx, value, dest_layout);
595                     lval.write_cvalue(fx, discr);
596                 }
597                 Rvalue::Repeat(operand, times) => {
598                     let operand = trans_operand(fx, operand);
599                     let times = fx
600                         .monomorphize(times)
601                         .eval(fx.tcx, ParamEnv::reveal_all())
602                         .val
603                         .try_to_bits(fx.tcx.data_layout.pointer_size)
604                         .unwrap();
605                     for i in 0..times {
606                         let index = fx.bcx.ins().iconst(fx.pointer_type, i as i64);
607                         let to = lval.place_index(fx, index);
608                         to.write_cvalue(fx, operand);
609                     }
610                 }
611                 Rvalue::Len(place) => {
612                     let place = trans_place(fx, *place);
613                     let usize_layout = fx.layout_of(fx.tcx.types.usize);
614                     let len = codegen_array_len(fx, place);
615                     lval.write_cvalue(fx, CValue::by_val(len, usize_layout));
616                 }
617                 Rvalue::NullaryOp(NullOp::Box, content_ty) => {
618                     use rustc_hir::lang_items::ExchangeMallocFnLangItem;
619
620                     let usize_type = fx.clif_type(fx.tcx.types.usize).unwrap();
621                     let content_ty = fx.monomorphize(content_ty);
622                     let layout = fx.layout_of(content_ty);
623                     let llsize = fx.bcx.ins().iconst(usize_type, layout.size.bytes() as i64);
624                     let llalign = fx
625                         .bcx
626                         .ins()
627                         .iconst(usize_type, layout.align.abi.bytes() as i64);
628                     let box_layout = fx.layout_of(fx.tcx.mk_box(content_ty));
629
630                     // Allocate space:
631                     let def_id = match fx.tcx.lang_items().require(ExchangeMallocFnLangItem) {
632                         Ok(id) => id,
633                         Err(s) => {
634                             fx.tcx
635                                 .sess
636                                 .fatal(&format!("allocation of `{}` {}", box_layout.ty, s));
637                         }
638                     };
639                     let instance = ty::Instance::mono(fx.tcx, def_id);
640                     let func_ref = fx.get_function_ref(instance);
641                     let call = fx.bcx.ins().call(func_ref, &[llsize, llalign]);
642                     let ptr = fx.bcx.inst_results(call)[0];
643                     lval.write_cvalue(fx, CValue::by_val(ptr, box_layout));
644                 }
645                 Rvalue::NullaryOp(NullOp::SizeOf, ty) => {
646                     assert!(lval
647                         .layout()
648                         .ty
649                         .is_sized(fx.tcx.at(stmt.source_info.span), ParamEnv::reveal_all()));
650                     let ty_size = fx.layout_of(fx.monomorphize(ty)).size.bytes();
651                     let val = CValue::const_val(fx, fx.layout_of(fx.tcx.types.usize), ty_size.into());
652                     lval.write_cvalue(fx, val);
653                 }
654                 Rvalue::Aggregate(kind, operands) => match **kind {
655                     AggregateKind::Array(_ty) => {
656                         for (i, operand) in operands.into_iter().enumerate() {
657                             let operand = trans_operand(fx, operand);
658                             let index = fx.bcx.ins().iconst(fx.pointer_type, i as i64);
659                             let to = lval.place_index(fx, index);
660                             to.write_cvalue(fx, operand);
661                         }
662                     }
663                     _ => unreachable!("shouldn't exist at trans {:?}", to_place_and_rval.1),
664                 },
665             }
666         }
667         StatementKind::StorageLive(_)
668         | StatementKind::StorageDead(_)
669         | StatementKind::Nop
670         | StatementKind::FakeRead(..)
671         | StatementKind::Retag { .. }
672         | StatementKind::AscribeUserType(..) => {}
673
674         StatementKind::LlvmInlineAsm(asm) => {
675             use rustc_ast::ast::Name;
676             let LlvmInlineAsm {
677                 asm,
678                 outputs: _,
679                 inputs: _,
680             } = &**asm;
681             let rustc_hir::LlvmInlineAsmInner {
682                 asm: asm_code, // Name
683                 outputs,       // Vec<Name>
684                 inputs,        // Vec<Name>
685                 clobbers,      // Vec<Name>
686                 volatile,      // bool
687                 alignstack,    // bool
688                 dialect: _,    // rustc_ast::ast::AsmDialect
689                 asm_str_style: _,
690             } = asm;
691             match &*asm_code.as_str() {
692                 "" => {
693                     assert_eq!(inputs, &[Name::intern("r")]);
694                     assert!(outputs.is_empty(), "{:?}", outputs);
695
696                     // Black box
697                 }
698                 "cpuid" | "cpuid\n" => {
699                     assert_eq!(inputs, &[Name::intern("{eax}"), Name::intern("{ecx}")]);
700
701                     assert_eq!(outputs.len(), 4);
702                     for (i, c) in (&["={eax}", "={ebx}", "={ecx}", "={edx}"])
703                         .iter()
704                         .enumerate()
705                     {
706                         assert_eq!(&outputs[i].constraint.as_str(), c);
707                         assert!(!outputs[i].is_rw);
708                         assert!(!outputs[i].is_indirect);
709                     }
710
711                     assert_eq!(clobbers, &[Name::intern("rbx")]);
712
713                     assert!(!volatile);
714                     assert!(!alignstack);
715
716                     crate::trap::trap_unimplemented(
717                         fx,
718                         "__cpuid_count arch intrinsic is not supported",
719                     );
720                 }
721                 "xgetbv" => {
722                     assert_eq!(inputs, &[Name::intern("{ecx}")]);
723
724                     assert_eq!(outputs.len(), 2);
725                     for (i, c) in (&["={eax}", "={edx}"]).iter().enumerate() {
726                         assert_eq!(&outputs[i].constraint.as_str(), c);
727                         assert!(!outputs[i].is_rw);
728                         assert!(!outputs[i].is_indirect);
729                     }
730
731                     assert_eq!(clobbers, &[]);
732
733                     assert!(!volatile);
734                     assert!(!alignstack);
735
736                     crate::trap::trap_unimplemented(fx, "_xgetbv arch intrinsic is not supported");
737                 }
738                 _ => unimpl_fatal!(fx.tcx, stmt.source_info.span, "Inline assembly is not supported"),
739             }
740         }
741     }
742 }
743
744 fn codegen_array_len<'tcx>(
745     fx: &mut FunctionCx<'_, 'tcx, impl Backend>,
746     place: CPlace<'tcx>,
747 ) -> Value {
748     match place.layout().ty.kind {
749         ty::Array(_elem_ty, len) => {
750             let len = fx.monomorphize(&len)
751                 .eval(fx.tcx, ParamEnv::reveal_all())
752                 .eval_usize(fx.tcx, ParamEnv::reveal_all()) as i64;
753             fx.bcx.ins().iconst(fx.pointer_type, len)
754         }
755         ty::Slice(_elem_ty) => place
756             .to_ptr_maybe_unsized()
757             .1
758             .expect("Length metadata for slice place"),
759         _ => bug!("Rvalue::Len({:?})", place),
760     }
761 }
762
763 pub(crate) fn trans_place<'tcx>(
764     fx: &mut FunctionCx<'_, 'tcx, impl Backend>,
765     place: Place<'tcx>,
766 ) -> CPlace<'tcx> {
767     let mut cplace = fx.get_local_place(place.local);
768
769     for elem in place.projection {
770         match *elem {
771             PlaceElem::Deref => {
772                 cplace = cplace.place_deref(fx);
773             }
774             PlaceElem::Field(field, _ty) => {
775                 cplace = cplace.place_field(fx, field);
776             }
777             PlaceElem::Index(local) => {
778                 let index = fx.get_local_place(local).to_cvalue(fx).load_scalar(fx);
779                 cplace = cplace.place_index(fx, index);
780             }
781             PlaceElem::ConstantIndex {
782                 offset,
783                 min_length: _,
784                 from_end,
785             } => {
786                 let index = if !from_end {
787                     fx.bcx.ins().iconst(fx.pointer_type, offset as i64)
788                 } else {
789                     let len = codegen_array_len(fx, cplace);
790                     fx.bcx.ins().iadd_imm(len, -(offset as i64))
791                 };
792                 cplace = cplace.place_index(fx, index);
793             }
794             PlaceElem::Subslice { from, to, from_end } => {
795                 // These indices are generated by slice patterns.
796                 // slice[from:-to] in Python terms.
797
798                 match cplace.layout().ty.kind {
799                     ty::Array(elem_ty, _len) => {
800                         assert!(!from_end, "array subslices are never `from_end`");
801                         let elem_layout = fx.layout_of(elem_ty);
802                         let ptr = cplace.to_ptr();
803                         cplace = CPlace::for_ptr(
804                             ptr.offset_i64(fx, elem_layout.size.bytes() as i64 * from as i64),
805                             fx.layout_of(fx.tcx.mk_array(elem_ty, to as u64 - from as u64)),
806                         );
807                     }
808                     ty::Slice(elem_ty) => {
809                         assert!(from_end, "slice subslices should be `from_end`");
810                         let elem_layout = fx.layout_of(elem_ty);
811                         let (ptr, len) = cplace.to_ptr_maybe_unsized();
812                         let len = len.unwrap();
813                         cplace = CPlace::for_ptr_with_extra(
814                             ptr.offset_i64(fx, elem_layout.size.bytes() as i64 * from as i64),
815                             fx.bcx.ins().iadd_imm(len, -(from as i64 + to as i64)),
816                             cplace.layout(),
817                         );
818                     }
819                     _ => unreachable!(),
820                 }
821             }
822             PlaceElem::Downcast(_adt_def, variant) => {
823                 cplace = cplace.downcast_variant(fx, variant);
824             }
825         }
826     }
827
828     cplace
829 }
830
831 pub(crate) fn trans_operand<'tcx>(
832     fx: &mut FunctionCx<'_, 'tcx, impl Backend>,
833     operand: &Operand<'tcx>,
834 ) -> CValue<'tcx> {
835     match operand {
836         Operand::Move(place) | Operand::Copy(place) => {
837             let cplace = trans_place(fx, *place);
838             cplace.to_cvalue(fx)
839         }
840         Operand::Constant(const_) => crate::constant::trans_constant(fx, const_),
841     }
842 }