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