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