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