]> git.lizzy.rs Git - rust.git/blob - src/base.rs
Remove Instance param of DebugContext::define_function
[rust.git] / src / base.rs
1 //! Codegen of a single function
2
3 use rustc_ast::InlineAsmOptions;
4 use rustc_index::vec::IndexVec;
5 use rustc_middle::ty::adjustment::PointerCast;
6 use rustc_middle::ty::layout::FnAbiOf;
7 use rustc_middle::ty::print::with_no_trimmed_paths;
8 use rustc_middle::ty::SymbolName;
9
10 use indexmap::IndexSet;
11
12 use crate::constant::ConstantCx;
13 use crate::prelude::*;
14 use crate::pretty_clif::CommentWriter;
15
16 struct CodegenedFunction<'tcx> {
17     symbol_name: SymbolName<'tcx>,
18     func_id: FuncId,
19     func: Function,
20     clif_comments: CommentWriter,
21     function_span: Span,
22     source_info_set: IndexSet<SourceInfo>,
23 }
24
25 pub(crate) fn codegen_and_compile_fn<'tcx>(
26     tcx: TyCtxt<'tcx>,
27     cx: &mut crate::CodegenCx<'tcx>,
28     cached_context: &mut Context,
29     module: &mut dyn Module,
30     instance: Instance<'tcx>,
31 ) {
32     let _inst_guard =
33         crate::PrintOnPanic(|| format!("{:?} {}", instance, tcx.symbol_name(instance).name));
34
35     let cached_func = std::mem::replace(&mut cached_context.func, Function::new());
36     let codegened_func = codegen_fn(tcx, cx, cached_func, module, instance);
37
38     compile_fn(cx, cached_context, module, codegened_func);
39 }
40
41 fn codegen_fn<'tcx>(
42     tcx: TyCtxt<'tcx>,
43     cx: &mut crate::CodegenCx<'tcx>,
44     cached_func: Function,
45     module: &mut dyn Module,
46     instance: Instance<'tcx>,
47 ) -> CodegenedFunction<'tcx> {
48     debug_assert!(!instance.substs.needs_infer());
49
50     let mir = tcx.instance_mir(instance.def);
51     let _mir_guard = crate::PrintOnPanic(|| {
52         let mut buf = Vec::new();
53         with_no_trimmed_paths!({
54             rustc_middle::mir::pretty::write_mir_fn(tcx, mir, &mut |_, _| Ok(()), &mut buf)
55                 .unwrap();
56         });
57         String::from_utf8_lossy(&buf).into_owned()
58     });
59
60     // Declare function
61     let symbol_name = tcx.symbol_name(instance);
62     let sig = get_function_sig(tcx, module.isa().triple(), instance);
63     let func_id = module.declare_function(symbol_name.name, Linkage::Local, &sig).unwrap();
64
65     // Make the FunctionBuilder
66     let mut func_ctx = FunctionBuilderContext::new();
67     let mut func = cached_func;
68     func.clear();
69     func.name = ExternalName::user(0, func_id.as_u32());
70     func.signature = sig;
71     func.collect_debug_info();
72
73     let mut bcx = FunctionBuilder::new(&mut func, &mut func_ctx);
74
75     // Predefine blocks
76     let start_block = bcx.create_block();
77     let block_map: IndexVec<BasicBlock, Block> =
78         (0..mir.basic_blocks().len()).map(|_| bcx.create_block()).collect();
79
80     // Make FunctionCx
81     let target_config = module.target_config();
82     let pointer_type = target_config.pointer_type();
83     let clif_comments = crate::pretty_clif::CommentWriter::new(tcx, instance);
84
85     let mut fx = FunctionCx {
86         cx,
87         module,
88         tcx,
89         target_config,
90         pointer_type,
91         constants_cx: ConstantCx::new(),
92
93         instance,
94         symbol_name,
95         mir,
96         fn_abi: Some(RevealAllLayoutCx(tcx).fn_abi_of_instance(instance, ty::List::empty())),
97
98         bcx,
99         block_map,
100         local_map: IndexVec::with_capacity(mir.local_decls.len()),
101         caller_location: None, // set by `codegen_fn_prelude`
102
103         clif_comments,
104         source_info_set: indexmap::IndexSet::new(),
105         next_ssa_var: 0,
106     };
107
108     tcx.sess.time("codegen clif ir", || codegen_fn_body(&mut fx, start_block));
109
110     // Recover all necessary data from fx, before accessing func will prevent future access to it.
111     let clif_comments = fx.clif_comments;
112     let function_span = fx.mir.span;
113     let source_info_set = fx.source_info_set;
114
115     fx.constants_cx.finalize(fx.tcx, &mut *fx.module);
116
117     if cx.should_write_ir {
118         crate::pretty_clif::write_clif_file(
119             tcx.output_filenames(()),
120             symbol_name.name,
121             "unopt",
122             module.isa(),
123             &func,
124             &clif_comments,
125         );
126     }
127
128     // Verify function
129     verify_func(tcx, &clif_comments, &func);
130
131     CodegenedFunction { symbol_name, func_id, func, clif_comments, function_span, source_info_set }
132 }
133
134 fn compile_fn<'tcx>(
135     cx: &mut crate::CodegenCx<'tcx>,
136     cached_context: &mut Context,
137     module: &mut dyn Module,
138     codegened_func: CodegenedFunction<'tcx>,
139 ) {
140     let clif_comments = codegened_func.clif_comments;
141
142     // Store function in context
143     let context = cached_context;
144     context.clear();
145     context.func = codegened_func.func;
146
147     // If the return block is not reachable, then the SSA builder may have inserted an `iconst.i128`
148     // instruction, which doesn't have an encoding.
149     context.compute_cfg();
150     context.compute_domtree();
151     context.eliminate_unreachable_code(module.isa()).unwrap();
152     context.dce(module.isa()).unwrap();
153     // Some Cranelift optimizations expect the domtree to not yet be computed and as such don't
154     // invalidate it when it would change.
155     context.domtree.clear();
156
157     #[cfg(any())] // This is never true
158     let _clif_guard = {
159         use std::fmt::Write;
160
161         let func_clone = context.func.clone();
162         let clif_comments_clone = clif_comments.clone();
163         let mut clif = String::new();
164         for flag in module.isa().flags().iter() {
165             writeln!(clif, "set {}", flag).unwrap();
166         }
167         write!(clif, "target {}", module.isa().triple().architecture.to_string()).unwrap();
168         for isa_flag in module.isa().isa_flags().iter() {
169             write!(clif, " {}", isa_flag).unwrap();
170         }
171         writeln!(clif, "\n").unwrap();
172         crate::PrintOnPanic(move || {
173             let mut clif = clif.clone();
174             ::cranelift_codegen::write::decorate_function(
175                 &mut &clif_comments_clone,
176                 &mut clif,
177                 &func_clone,
178             )
179             .unwrap();
180             clif
181         })
182     };
183
184     // Define function
185     cx.profiler.verbose_generic_activity("define function").run(|| {
186         context.want_disasm = cx.should_write_ir;
187         module.define_function(codegened_func.func_id, context).unwrap();
188     });
189
190     if cx.should_write_ir {
191         // Write optimized function to file for debugging
192         crate::pretty_clif::write_clif_file(
193             &cx.output_filenames,
194             codegened_func.symbol_name.name,
195             "opt",
196             module.isa(),
197             &context.func,
198             &clif_comments,
199         );
200
201         if let Some(disasm) = &context.mach_compile_result.as_ref().unwrap().disasm {
202             crate::pretty_clif::write_ir_file(
203                 &cx.output_filenames,
204                 &format!("{}.vcode", codegened_func.symbol_name.name),
205                 |file| file.write_all(disasm.as_bytes()),
206             )
207         }
208     }
209
210     // Define debuginfo for function
211     let isa = module.isa();
212     let debug_context = &mut cx.debug_context;
213     let unwind_context = &mut cx.unwind_context;
214     cx.profiler.verbose_generic_activity("generate debug info").run(|| {
215         if let Some(debug_context) = debug_context {
216             debug_context.define_function(
217                 codegened_func.func_id,
218                 codegened_func.symbol_name.name,
219                 context,
220                 codegened_func.function_span,
221                 &codegened_func.source_info_set,
222             );
223         }
224         unwind_context.add_function(codegened_func.func_id, &context, isa);
225     });
226 }
227
228 pub(crate) fn verify_func(
229     tcx: TyCtxt<'_>,
230     writer: &crate::pretty_clif::CommentWriter,
231     func: &Function,
232 ) {
233     tcx.sess.time("verify clif ir", || {
234         let flags = cranelift_codegen::settings::Flags::new(cranelift_codegen::settings::builder());
235         match cranelift_codegen::verify_function(&func, &flags) {
236             Ok(_) => {}
237             Err(err) => {
238                 tcx.sess.err(&format!("{:?}", err));
239                 let pretty_error = cranelift_codegen::print_errors::pretty_verifier_error(
240                     &func,
241                     Some(Box::new(writer)),
242                     err,
243                 );
244                 tcx.sess.fatal(&format!("cranelift verify error:\n{}", pretty_error));
245             }
246         }
247     });
248 }
249
250 fn codegen_fn_body(fx: &mut FunctionCx<'_, '_, '_>, start_block: Block) {
251     if !crate::constant::check_constants(fx) {
252         fx.bcx.append_block_params_for_function_params(fx.block_map[START_BLOCK]);
253         fx.bcx.switch_to_block(fx.block_map[START_BLOCK]);
254         // compilation should have been aborted
255         fx.bcx.ins().trap(TrapCode::UnreachableCodeReached);
256         return;
257     }
258
259     let arg_uninhabited = fx
260         .mir
261         .args_iter()
262         .any(|arg| fx.layout_of(fx.monomorphize(fx.mir.local_decls[arg].ty)).abi.is_uninhabited());
263     if arg_uninhabited {
264         fx.bcx.append_block_params_for_function_params(fx.block_map[START_BLOCK]);
265         fx.bcx.switch_to_block(fx.block_map[START_BLOCK]);
266         fx.bcx.ins().trap(TrapCode::UnreachableCodeReached);
267         return;
268     }
269     fx.tcx.sess.time("codegen prelude", || crate::abi::codegen_fn_prelude(fx, start_block));
270
271     for (bb, bb_data) in fx.mir.basic_blocks().iter_enumerated() {
272         let block = fx.get_block(bb);
273         fx.bcx.switch_to_block(block);
274
275         if bb_data.is_cleanup {
276             // Unwinding after panicking is not supported
277             continue;
278
279             // FIXME Once unwinding is supported and Cranelift supports marking blocks as cold, do
280             // so for cleanup blocks.
281         }
282
283         fx.bcx.ins().nop();
284         for stmt in &bb_data.statements {
285             fx.set_debug_loc(stmt.source_info);
286             codegen_stmt(fx, block, stmt);
287         }
288
289         if fx.clif_comments.enabled() {
290             let mut terminator_head = "\n".to_string();
291             with_no_trimmed_paths!({
292                 bb_data.terminator().kind.fmt_head(&mut terminator_head).unwrap();
293             });
294             let inst = fx.bcx.func.layout.last_inst(block).unwrap();
295             fx.add_comment(inst, terminator_head);
296         }
297
298         let source_info = bb_data.terminator().source_info;
299         fx.set_debug_loc(source_info);
300
301         match &bb_data.terminator().kind {
302             TerminatorKind::Goto { target } => {
303                 if let TerminatorKind::Return = fx.mir[*target].terminator().kind {
304                     let mut can_immediately_return = true;
305                     for stmt in &fx.mir[*target].statements {
306                         if let StatementKind::StorageDead(_) = stmt.kind {
307                         } else {
308                             // FIXME Can sometimes happen, see rust-lang/rust#70531
309                             can_immediately_return = false;
310                             break;
311                         }
312                     }
313
314                     if can_immediately_return {
315                         crate::abi::codegen_return(fx);
316                         continue;
317                     }
318                 }
319
320                 let block = fx.get_block(*target);
321                 fx.bcx.ins().jump(block, &[]);
322             }
323             TerminatorKind::Return => {
324                 crate::abi::codegen_return(fx);
325             }
326             TerminatorKind::Assert { cond, expected, msg, target, cleanup: _ } => {
327                 if !fx.tcx.sess.overflow_checks() {
328                     if let mir::AssertKind::OverflowNeg(_) = *msg {
329                         let target = fx.get_block(*target);
330                         fx.bcx.ins().jump(target, &[]);
331                         continue;
332                     }
333                 }
334                 let cond = codegen_operand(fx, cond).load_scalar(fx);
335
336                 let target = fx.get_block(*target);
337                 let failure = fx.bcx.create_block();
338                 fx.bcx.set_cold_block(failure);
339
340                 if *expected {
341                     fx.bcx.ins().brz(cond, failure, &[]);
342                 } else {
343                     fx.bcx.ins().brnz(cond, failure, &[]);
344                 };
345                 fx.bcx.ins().jump(target, &[]);
346
347                 fx.bcx.switch_to_block(failure);
348                 fx.bcx.ins().nop();
349
350                 match msg {
351                     AssertKind::BoundsCheck { ref len, ref index } => {
352                         let len = codegen_operand(fx, len).load_scalar(fx);
353                         let index = codegen_operand(fx, index).load_scalar(fx);
354                         let location = fx.get_caller_location(source_info).load_scalar(fx);
355
356                         codegen_panic_inner(
357                             fx,
358                             rustc_hir::LangItem::PanicBoundsCheck,
359                             &[index, len, location],
360                             source_info.span,
361                         );
362                     }
363                     _ => {
364                         let msg_str = msg.description();
365                         codegen_panic(fx, msg_str, source_info);
366                     }
367                 }
368             }
369
370             TerminatorKind::SwitchInt { discr, switch_ty, targets } => {
371                 let discr = codegen_operand(fx, discr).load_scalar(fx);
372
373                 let use_bool_opt = switch_ty.kind() == fx.tcx.types.bool.kind()
374                     || (targets.iter().count() == 1 && targets.iter().next().unwrap().0 == 0);
375                 if use_bool_opt {
376                     assert_eq!(targets.iter().count(), 1);
377                     let (then_value, then_block) = targets.iter().next().unwrap();
378                     let then_block = fx.get_block(then_block);
379                     let else_block = fx.get_block(targets.otherwise());
380                     let test_zero = match then_value {
381                         0 => true,
382                         1 => false,
383                         _ => unreachable!("{:?}", targets),
384                     };
385
386                     let discr = crate::optimize::peephole::maybe_unwrap_bint(&mut fx.bcx, discr);
387                     let (discr, is_inverted) =
388                         crate::optimize::peephole::maybe_unwrap_bool_not(&mut fx.bcx, discr);
389                     let test_zero = if is_inverted { !test_zero } else { test_zero };
390                     let discr = crate::optimize::peephole::maybe_unwrap_bint(&mut fx.bcx, discr);
391                     if let Some(taken) = crate::optimize::peephole::maybe_known_branch_taken(
392                         &fx.bcx, discr, test_zero,
393                     ) {
394                         if taken {
395                             fx.bcx.ins().jump(then_block, &[]);
396                         } else {
397                             fx.bcx.ins().jump(else_block, &[]);
398                         }
399                     } else {
400                         if test_zero {
401                             fx.bcx.ins().brz(discr, then_block, &[]);
402                             fx.bcx.ins().jump(else_block, &[]);
403                         } else {
404                             fx.bcx.ins().brnz(discr, then_block, &[]);
405                             fx.bcx.ins().jump(else_block, &[]);
406                         }
407                     }
408                 } else {
409                     let mut switch = ::cranelift_frontend::Switch::new();
410                     for (value, block) in targets.iter() {
411                         let block = fx.get_block(block);
412                         switch.set_entry(value, block);
413                     }
414                     let otherwise_block = fx.get_block(targets.otherwise());
415                     switch.emit(&mut fx.bcx, discr, otherwise_block);
416                 }
417             }
418             TerminatorKind::Call {
419                 func,
420                 args,
421                 destination,
422                 target,
423                 fn_span,
424                 cleanup: _,
425                 from_hir_call: _,
426             } => {
427                 fx.tcx.sess.time("codegen call", || {
428                     crate::abi::codegen_terminator_call(
429                         fx,
430                         mir::SourceInfo { span: *fn_span, ..source_info },
431                         func,
432                         args,
433                         *destination,
434                         *target,
435                     )
436                 });
437             }
438             TerminatorKind::InlineAsm {
439                 template,
440                 operands,
441                 options,
442                 destination,
443                 line_spans: _,
444                 cleanup: _,
445             } => {
446                 if options.contains(InlineAsmOptions::MAY_UNWIND) {
447                     fx.tcx.sess.span_fatal(
448                         source_info.span,
449                         "cranelift doesn't support unwinding from inline assembly.",
450                     );
451                 }
452
453                 crate::inline_asm::codegen_inline_asm(
454                     fx,
455                     source_info.span,
456                     template,
457                     operands,
458                     *options,
459                     *destination,
460                 );
461             }
462             TerminatorKind::Resume | TerminatorKind::Abort => {
463                 // FIXME implement unwinding
464                 fx.bcx.ins().trap(TrapCode::UnreachableCodeReached);
465             }
466             TerminatorKind::Unreachable => {
467                 fx.bcx.ins().trap(TrapCode::UnreachableCodeReached);
468             }
469             TerminatorKind::Yield { .. }
470             | TerminatorKind::FalseEdge { .. }
471             | TerminatorKind::FalseUnwind { .. }
472             | TerminatorKind::DropAndReplace { .. }
473             | TerminatorKind::GeneratorDrop => {
474                 bug!("shouldn't exist at codegen {:?}", bb_data.terminator());
475             }
476             TerminatorKind::Drop { place, target, unwind: _ } => {
477                 let drop_place = codegen_place(fx, *place);
478                 crate::abi::codegen_drop(fx, source_info, drop_place);
479
480                 let target_block = fx.get_block(*target);
481                 fx.bcx.ins().jump(target_block, &[]);
482             }
483         };
484     }
485
486     fx.bcx.seal_all_blocks();
487     fx.bcx.finalize();
488 }
489
490 fn codegen_stmt<'tcx>(
491     fx: &mut FunctionCx<'_, '_, 'tcx>,
492     #[allow(unused_variables)] cur_block: Block,
493     stmt: &Statement<'tcx>,
494 ) {
495     let _print_guard = crate::PrintOnPanic(|| format!("stmt {:?}", stmt));
496
497     fx.set_debug_loc(stmt.source_info);
498
499     #[cfg(any())] // This is never true
500     match &stmt.kind {
501         StatementKind::StorageLive(..) | StatementKind::StorageDead(..) => {} // Those are not very useful
502         _ => {
503             if fx.clif_comments.enabled() {
504                 let inst = fx.bcx.func.layout.last_inst(cur_block).unwrap();
505                 fx.add_comment(inst, format!("{:?}", stmt));
506             }
507         }
508     }
509
510     match &stmt.kind {
511         StatementKind::SetDiscriminant { place, variant_index } => {
512             let place = codegen_place(fx, **place);
513             crate::discriminant::codegen_set_discriminant(fx, place, *variant_index);
514         }
515         StatementKind::Assign(to_place_and_rval) => {
516             let lval = codegen_place(fx, to_place_and_rval.0);
517             let dest_layout = lval.layout();
518             match to_place_and_rval.1 {
519                 Rvalue::Use(ref operand) => {
520                     let val = codegen_operand(fx, operand);
521                     lval.write_cvalue(fx, val);
522                 }
523                 Rvalue::CopyForDeref(place) => {
524                     let cplace = codegen_place(fx, place);
525                     let val = cplace.to_cvalue(fx);
526                     lval.write_cvalue(fx, val)
527                 }
528                 Rvalue::Ref(_, _, place) | Rvalue::AddressOf(_, place) => {
529                     let place = codegen_place(fx, place);
530                     let ref_ = place.place_ref(fx, lval.layout());
531                     lval.write_cvalue(fx, ref_);
532                 }
533                 Rvalue::ThreadLocalRef(def_id) => {
534                     let val = crate::constant::codegen_tls_ref(fx, def_id, lval.layout());
535                     lval.write_cvalue(fx, val);
536                 }
537                 Rvalue::BinaryOp(bin_op, ref lhs_rhs) => {
538                     let lhs = codegen_operand(fx, &lhs_rhs.0);
539                     let rhs = codegen_operand(fx, &lhs_rhs.1);
540
541                     let res = crate::num::codegen_binop(fx, bin_op, lhs, rhs);
542                     lval.write_cvalue(fx, res);
543                 }
544                 Rvalue::CheckedBinaryOp(bin_op, ref lhs_rhs) => {
545                     let lhs = codegen_operand(fx, &lhs_rhs.0);
546                     let rhs = codegen_operand(fx, &lhs_rhs.1);
547
548                     let res = if !fx.tcx.sess.overflow_checks() {
549                         let val =
550                             crate::num::codegen_int_binop(fx, bin_op, lhs, rhs).load_scalar(fx);
551                         let is_overflow = fx.bcx.ins().iconst(types::I8, 0);
552                         CValue::by_val_pair(val, is_overflow, lval.layout())
553                     } else {
554                         crate::num::codegen_checked_int_binop(fx, bin_op, lhs, rhs)
555                     };
556
557                     lval.write_cvalue(fx, res);
558                 }
559                 Rvalue::UnaryOp(un_op, ref operand) => {
560                     let operand = codegen_operand(fx, operand);
561                     let layout = operand.layout();
562                     let val = operand.load_scalar(fx);
563                     let res = match un_op {
564                         UnOp::Not => match layout.ty.kind() {
565                             ty::Bool => {
566                                 let res = fx.bcx.ins().icmp_imm(IntCC::Equal, val, 0);
567                                 CValue::by_val(fx.bcx.ins().bint(types::I8, res), layout)
568                             }
569                             ty::Uint(_) | ty::Int(_) => {
570                                 CValue::by_val(fx.bcx.ins().bnot(val), layout)
571                             }
572                             _ => unreachable!("un op Not for {:?}", layout.ty),
573                         },
574                         UnOp::Neg => match layout.ty.kind() {
575                             ty::Int(IntTy::I128) => {
576                                 // FIXME remove this case once ineg.i128 works
577                                 let zero =
578                                     CValue::const_val(fx, layout, ty::ScalarInt::null(layout.size));
579                                 crate::num::codegen_int_binop(fx, BinOp::Sub, zero, operand)
580                             }
581                             ty::Int(_) => CValue::by_val(fx.bcx.ins().ineg(val), layout),
582                             ty::Float(_) => CValue::by_val(fx.bcx.ins().fneg(val), layout),
583                             _ => unreachable!("un op Neg for {:?}", layout.ty),
584                         },
585                     };
586                     lval.write_cvalue(fx, res);
587                 }
588                 Rvalue::Cast(
589                     CastKind::Pointer(PointerCast::ReifyFnPointer),
590                     ref operand,
591                     to_ty,
592                 ) => {
593                     let from_ty = fx.monomorphize(operand.ty(&fx.mir.local_decls, fx.tcx));
594                     let to_layout = fx.layout_of(fx.monomorphize(to_ty));
595                     match *from_ty.kind() {
596                         ty::FnDef(def_id, substs) => {
597                             let func_ref = fx.get_function_ref(
598                                 Instance::resolve_for_fn_ptr(
599                                     fx.tcx,
600                                     ParamEnv::reveal_all(),
601                                     def_id,
602                                     substs,
603                                 )
604                                 .unwrap()
605                                 .polymorphize(fx.tcx),
606                             );
607                             let func_addr = fx.bcx.ins().func_addr(fx.pointer_type, func_ref);
608                             lval.write_cvalue(fx, CValue::by_val(func_addr, to_layout));
609                         }
610                         _ => bug!("Trying to ReifyFnPointer on non FnDef {:?}", from_ty),
611                     }
612                 }
613                 Rvalue::Cast(
614                     CastKind::Pointer(PointerCast::UnsafeFnPointer),
615                     ref operand,
616                     to_ty,
617                 )
618                 | Rvalue::Cast(
619                     CastKind::Pointer(PointerCast::MutToConstPointer),
620                     ref operand,
621                     to_ty,
622                 )
623                 | Rvalue::Cast(
624                     CastKind::Pointer(PointerCast::ArrayToPointer),
625                     ref operand,
626                     to_ty,
627                 ) => {
628                     let to_layout = fx.layout_of(fx.monomorphize(to_ty));
629                     let operand = codegen_operand(fx, operand);
630                     lval.write_cvalue(fx, operand.cast_pointer_to(to_layout));
631                 }
632                 Rvalue::Cast(
633                     CastKind::Misc
634                     | CastKind::PointerExposeAddress
635                     | CastKind::PointerFromExposedAddress,
636                     ref operand,
637                     to_ty,
638                 ) => {
639                     let operand = codegen_operand(fx, operand);
640                     let from_ty = operand.layout().ty;
641                     let to_ty = fx.monomorphize(to_ty);
642
643                     fn is_fat_ptr<'tcx>(fx: &FunctionCx<'_, '_, 'tcx>, ty: Ty<'tcx>) -> bool {
644                         ty.builtin_deref(true)
645                             .map(|ty::TypeAndMut { ty: pointee_ty, mutbl: _ }| {
646                                 has_ptr_meta(fx.tcx, pointee_ty)
647                             })
648                             .unwrap_or(false)
649                     }
650
651                     if is_fat_ptr(fx, from_ty) {
652                         if is_fat_ptr(fx, to_ty) {
653                             // fat-ptr -> fat-ptr
654                             lval.write_cvalue(fx, operand.cast_pointer_to(dest_layout));
655                         } else {
656                             // fat-ptr -> thin-ptr
657                             let (ptr, _extra) = operand.load_scalar_pair(fx);
658                             lval.write_cvalue(fx, CValue::by_val(ptr, dest_layout))
659                         }
660                     } else {
661                         let to_clif_ty = fx.clif_type(to_ty).unwrap();
662                         let from = operand.load_scalar(fx);
663
664                         let res = clif_int_or_float_cast(
665                             fx,
666                             from,
667                             type_sign(from_ty),
668                             to_clif_ty,
669                             type_sign(to_ty),
670                         );
671                         lval.write_cvalue(fx, CValue::by_val(res, dest_layout));
672                     }
673                 }
674                 Rvalue::Cast(
675                     CastKind::Pointer(PointerCast::ClosureFnPointer(_)),
676                     ref operand,
677                     _to_ty,
678                 ) => {
679                     let operand = codegen_operand(fx, operand);
680                     match *operand.layout().ty.kind() {
681                         ty::Closure(def_id, substs) => {
682                             let instance = Instance::resolve_closure(
683                                 fx.tcx,
684                                 def_id,
685                                 substs,
686                                 ty::ClosureKind::FnOnce,
687                             )
688                             .expect("failed to normalize and resolve closure during codegen")
689                             .polymorphize(fx.tcx);
690                             let func_ref = fx.get_function_ref(instance);
691                             let func_addr = fx.bcx.ins().func_addr(fx.pointer_type, func_ref);
692                             lval.write_cvalue(fx, CValue::by_val(func_addr, lval.layout()));
693                         }
694                         _ => bug!("{} cannot be cast to a fn ptr", operand.layout().ty),
695                     }
696                 }
697                 Rvalue::Cast(CastKind::Pointer(PointerCast::Unsize), ref operand, _to_ty) => {
698                     let operand = codegen_operand(fx, operand);
699                     operand.unsize_value(fx, lval);
700                 }
701                 Rvalue::Discriminant(place) => {
702                     let place = codegen_place(fx, place);
703                     let value = place.to_cvalue(fx);
704                     crate::discriminant::codegen_get_discriminant(fx, lval, value, dest_layout);
705                 }
706                 Rvalue::Repeat(ref operand, times) => {
707                     let operand = codegen_operand(fx, operand);
708                     let times = fx
709                         .monomorphize(times)
710                         .eval(fx.tcx, ParamEnv::reveal_all())
711                         .kind()
712                         .try_to_bits(fx.tcx.data_layout.pointer_size)
713                         .unwrap();
714                     if operand.layout().size.bytes() == 0 {
715                         // Do nothing for ZST's
716                     } else if fx.clif_type(operand.layout().ty) == Some(types::I8) {
717                         let times = fx.bcx.ins().iconst(fx.pointer_type, times as i64);
718                         // FIXME use emit_small_memset where possible
719                         let addr = lval.to_ptr().get_addr(fx);
720                         let val = operand.load_scalar(fx);
721                         fx.bcx.call_memset(fx.target_config, addr, val, times);
722                     } else {
723                         let loop_block = fx.bcx.create_block();
724                         let loop_block2 = fx.bcx.create_block();
725                         let done_block = fx.bcx.create_block();
726                         let index = fx.bcx.append_block_param(loop_block, fx.pointer_type);
727                         let zero = fx.bcx.ins().iconst(fx.pointer_type, 0);
728                         fx.bcx.ins().jump(loop_block, &[zero]);
729
730                         fx.bcx.switch_to_block(loop_block);
731                         let done = fx.bcx.ins().icmp_imm(IntCC::Equal, index, times as i64);
732                         fx.bcx.ins().brnz(done, done_block, &[]);
733                         fx.bcx.ins().jump(loop_block2, &[]);
734
735                         fx.bcx.switch_to_block(loop_block2);
736                         let to = lval.place_index(fx, index);
737                         to.write_cvalue(fx, operand);
738                         let index = fx.bcx.ins().iadd_imm(index, 1);
739                         fx.bcx.ins().jump(loop_block, &[index]);
740
741                         fx.bcx.switch_to_block(done_block);
742                         fx.bcx.ins().nop();
743                     }
744                 }
745                 Rvalue::Len(place) => {
746                     let place = codegen_place(fx, place);
747                     let usize_layout = fx.layout_of(fx.tcx.types.usize);
748                     let len = codegen_array_len(fx, place);
749                     lval.write_cvalue(fx, CValue::by_val(len, usize_layout));
750                 }
751                 Rvalue::ShallowInitBox(ref operand, content_ty) => {
752                     let content_ty = fx.monomorphize(content_ty);
753                     let box_layout = fx.layout_of(fx.tcx.mk_box(content_ty));
754                     let operand = codegen_operand(fx, operand);
755                     let operand = operand.load_scalar(fx);
756                     lval.write_cvalue(fx, CValue::by_val(operand, box_layout));
757                 }
758                 Rvalue::NullaryOp(null_op, ty) => {
759                     assert!(
760                         lval.layout()
761                             .ty
762                             .is_sized(fx.tcx.at(stmt.source_info.span), ParamEnv::reveal_all())
763                     );
764                     let layout = fx.layout_of(fx.monomorphize(ty));
765                     let val = match null_op {
766                         NullOp::SizeOf => layout.size.bytes(),
767                         NullOp::AlignOf => layout.align.abi.bytes(),
768                     };
769                     let val = CValue::const_val(fx, fx.layout_of(fx.tcx.types.usize), val.into());
770                     lval.write_cvalue(fx, val);
771                 }
772                 Rvalue::Aggregate(ref kind, ref operands) => match kind.as_ref() {
773                     AggregateKind::Array(_ty) => {
774                         for (i, operand) in operands.iter().enumerate() {
775                             let operand = codegen_operand(fx, operand);
776                             let index = fx.bcx.ins().iconst(fx.pointer_type, i as i64);
777                             let to = lval.place_index(fx, index);
778                             to.write_cvalue(fx, operand);
779                         }
780                     }
781                     _ => unreachable!("shouldn't exist at codegen {:?}", to_place_and_rval.1),
782                 },
783             }
784         }
785         StatementKind::StorageLive(_)
786         | StatementKind::StorageDead(_)
787         | StatementKind::Deinit(_)
788         | StatementKind::Nop
789         | StatementKind::FakeRead(..)
790         | StatementKind::Retag { .. }
791         | StatementKind::AscribeUserType(..) => {}
792
793         StatementKind::Coverage { .. } => fx.tcx.sess.fatal("-Zcoverage is unimplemented"),
794         StatementKind::CopyNonOverlapping(inner) => {
795             let dst = codegen_operand(fx, &inner.dst);
796             let pointee = dst
797                 .layout()
798                 .pointee_info_at(fx, rustc_target::abi::Size::ZERO)
799                 .expect("Expected pointer");
800             let dst = dst.load_scalar(fx);
801             let src = codegen_operand(fx, &inner.src).load_scalar(fx);
802             let count = codegen_operand(fx, &inner.count).load_scalar(fx);
803             let elem_size: u64 = pointee.size.bytes();
804             let bytes =
805                 if elem_size != 1 { fx.bcx.ins().imul_imm(count, elem_size as i64) } else { count };
806             fx.bcx.call_memcpy(fx.target_config, dst, src, bytes);
807         }
808     }
809 }
810
811 fn codegen_array_len<'tcx>(fx: &mut FunctionCx<'_, '_, 'tcx>, place: CPlace<'tcx>) -> Value {
812     match *place.layout().ty.kind() {
813         ty::Array(_elem_ty, len) => {
814             let len = fx.monomorphize(len).eval_usize(fx.tcx, ParamEnv::reveal_all()) as i64;
815             fx.bcx.ins().iconst(fx.pointer_type, len)
816         }
817         ty::Slice(_elem_ty) => {
818             place.to_ptr_maybe_unsized().1.expect("Length metadata for slice place")
819         }
820         _ => bug!("Rvalue::Len({:?})", place),
821     }
822 }
823
824 pub(crate) fn codegen_place<'tcx>(
825     fx: &mut FunctionCx<'_, '_, 'tcx>,
826     place: Place<'tcx>,
827 ) -> CPlace<'tcx> {
828     let mut cplace = fx.get_local_place(place.local);
829
830     for elem in place.projection {
831         match elem {
832             PlaceElem::Deref => {
833                 cplace = cplace.place_deref(fx);
834             }
835             PlaceElem::Field(field, _ty) => {
836                 cplace = cplace.place_field(fx, field);
837             }
838             PlaceElem::Index(local) => {
839                 let index = fx.get_local_place(local).to_cvalue(fx).load_scalar(fx);
840                 cplace = cplace.place_index(fx, index);
841             }
842             PlaceElem::ConstantIndex { offset, min_length: _, from_end } => {
843                 let offset: u64 = offset;
844                 let index = if !from_end {
845                     fx.bcx.ins().iconst(fx.pointer_type, offset as i64)
846                 } else {
847                     let len = codegen_array_len(fx, cplace);
848                     fx.bcx.ins().iadd_imm(len, -(offset as i64))
849                 };
850                 cplace = cplace.place_index(fx, index);
851             }
852             PlaceElem::Subslice { from, to, from_end } => {
853                 // These indices are generated by slice patterns.
854                 // slice[from:-to] in Python terms.
855
856                 let from: u64 = from;
857                 let to: u64 = to;
858
859                 match cplace.layout().ty.kind() {
860                     ty::Array(elem_ty, _len) => {
861                         assert!(!from_end, "array subslices are never `from_end`");
862                         let elem_layout = fx.layout_of(*elem_ty);
863                         let ptr = cplace.to_ptr();
864                         cplace = CPlace::for_ptr(
865                             ptr.offset_i64(fx, elem_layout.size.bytes() as i64 * (from as i64)),
866                             fx.layout_of(fx.tcx.mk_array(*elem_ty, to - from)),
867                         );
868                     }
869                     ty::Slice(elem_ty) => {
870                         assert!(from_end, "slice subslices should be `from_end`");
871                         let elem_layout = fx.layout_of(*elem_ty);
872                         let (ptr, len) = cplace.to_ptr_maybe_unsized();
873                         let len = len.unwrap();
874                         cplace = CPlace::for_ptr_with_extra(
875                             ptr.offset_i64(fx, elem_layout.size.bytes() as i64 * (from as i64)),
876                             fx.bcx.ins().iadd_imm(len, -(from as i64 + to as i64)),
877                             cplace.layout(),
878                         );
879                     }
880                     _ => unreachable!(),
881                 }
882             }
883             PlaceElem::Downcast(_adt_def, variant) => {
884                 cplace = cplace.downcast_variant(fx, variant);
885             }
886         }
887     }
888
889     cplace
890 }
891
892 pub(crate) fn codegen_operand<'tcx>(
893     fx: &mut FunctionCx<'_, '_, 'tcx>,
894     operand: &Operand<'tcx>,
895 ) -> CValue<'tcx> {
896     match operand {
897         Operand::Move(place) | Operand::Copy(place) => {
898             let cplace = codegen_place(fx, *place);
899             cplace.to_cvalue(fx)
900         }
901         Operand::Constant(const_) => crate::constant::codegen_constant(fx, const_),
902     }
903 }
904
905 pub(crate) fn codegen_panic<'tcx>(
906     fx: &mut FunctionCx<'_, '_, 'tcx>,
907     msg_str: &str,
908     source_info: mir::SourceInfo,
909 ) {
910     let location = fx.get_caller_location(source_info).load_scalar(fx);
911
912     let msg_ptr = fx.anonymous_str(msg_str);
913     let msg_len = fx.bcx.ins().iconst(fx.pointer_type, i64::try_from(msg_str.len()).unwrap());
914     let args = [msg_ptr, msg_len, location];
915
916     codegen_panic_inner(fx, rustc_hir::LangItem::Panic, &args, source_info.span);
917 }
918
919 pub(crate) fn codegen_panic_inner<'tcx>(
920     fx: &mut FunctionCx<'_, '_, 'tcx>,
921     lang_item: rustc_hir::LangItem,
922     args: &[Value],
923     span: Span,
924 ) {
925     let def_id =
926         fx.tcx.lang_items().require(lang_item).unwrap_or_else(|s| fx.tcx.sess.span_fatal(span, &s));
927
928     let instance = Instance::mono(fx.tcx, def_id).polymorphize(fx.tcx);
929     let symbol_name = fx.tcx.symbol_name(instance).name;
930
931     fx.lib_call(
932         &*symbol_name,
933         vec![
934             AbiParam::new(fx.pointer_type),
935             AbiParam::new(fx.pointer_type),
936             AbiParam::new(fx.pointer_type),
937         ],
938         vec![],
939         args,
940     );
941
942     fx.bcx.ins().trap(TrapCode::UnreachableCodeReached);
943 }