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