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