]> git.lizzy.rs Git - rust.git/blob - src/base.rs
Extract driver.rs
[rust.git] / src / base.rs
1 use rustc::ty::adjustment::PointerCast;
2
3 use crate::prelude::*;
4
5 pub fn trans_fn<'a, 'clif, 'tcx: 'a, B: Backend + 'static>(
6     cx: &mut crate::CodegenCx<'a, 'clif, 'tcx, B>,
7     instance: Instance<'tcx>,
8     linkage: Linkage,
9 ) {
10     let tcx = cx.tcx;
11
12     // Step 1. Get mir
13     let mir = tcx.instance_mir(instance.def);
14
15     // Step 2. Check fn sig for u128 and i128 and replace those functions with a trap.
16     {
17         // FIXME implement u128 and i128 support
18
19         // Step 2a. Check sig for u128 and i128
20         let fn_sig = tcx.normalize_erasing_late_bound_regions(ParamEnv::reveal_all(), &instance.fn_sig(tcx));
21
22         struct UI128Visitor<'a, 'tcx: 'a>(TyCtxt<'a, 'tcx, 'tcx>, bool);
23
24         impl<'a, 'tcx: 'a> rustc::ty::fold::TypeVisitor<'tcx> for UI128Visitor<'a, 'tcx> {
25             fn visit_ty(&mut self, t: Ty<'tcx>) -> bool {
26                 if t.sty == self.0.types.u128.sty || t.sty == self.0.types.i128.sty {
27                     self.1 = true;
28                     return false; // stop visiting
29                 }
30
31                 t.super_visit_with(self)
32             }
33         }
34
35         let mut visitor = UI128Visitor(tcx, false);
36         fn_sig.visit_with(&mut visitor);
37
38         // Step 2b. If found replace function with a trap.
39         if visitor.1 {
40             tcx.sess.warn("u128 and i128 are not yet supported. \
41             Functions using these as args will be replaced with a trap.");
42
43             // Step 2b1. Declare function with fake signature
44             let sig = Signature {
45                 params: vec![AbiParam::new(types::INVALID)],
46                 returns: vec![],
47                 call_conv: CallConv::Fast,
48             };
49             let name = tcx.symbol_name(instance).as_str();
50             let func_id = cx.module.declare_function(&*name, linkage, &sig).unwrap();
51
52             // Step 2b2. Create trapping function
53             let mut func = Function::with_name_signature(ExternalName::user(0, 0), sig);
54             let mut func_ctx = FunctionBuilderContext::new();
55             let mut bcx = FunctionBuilder::new(&mut func, &mut func_ctx);
56             let start_ebb = bcx.create_ebb();
57             bcx.append_ebb_params_for_function_params(start_ebb);
58             bcx.switch_to_block(start_ebb);
59
60             let mut fx = FunctionCx {
61                 tcx,
62                 module: cx.module,
63                 pointer_type: pointer_ty(tcx),
64
65                 instance,
66                 mir,
67
68                 bcx,
69                 ebb_map: HashMap::new(),
70                 local_map: HashMap::new(),
71
72                 clif_comments: crate::pretty_clif::CommentWriter::new(tcx, instance),
73                 constants: &mut cx.ccx,
74                 caches: &mut cx.caches,
75                 source_info_set: indexmap::IndexSet::new(),
76             };
77
78             crate::trap::trap_unreachable(&mut fx, "[unimplemented] Called function with u128 or i128 as argument.");
79             fx.bcx.seal_all_blocks();
80             fx.bcx.finalize();
81
82             // Step 2b3. Define function
83             cx.caches.context.func = func;
84             cx.module
85                 .define_function(func_id, &mut cx.caches.context)
86                 .unwrap();
87             cx.caches.context.clear();
88             return;
89         }
90     }
91
92     // Step 3. Declare function
93     let (name, sig) = get_function_name_and_sig(tcx, instance, false);
94     let func_id = cx.module.declare_function(&name, linkage, &sig).unwrap();
95     let mut debug_context = cx
96         .debug_context
97         .as_mut()
98         .map(|debug_context| FunctionDebugContext::new(tcx, debug_context, mir, &name, &sig));
99
100     // Step 4. Make FunctionBuilder
101     let mut func = Function::with_name_signature(ExternalName::user(0, 0), sig);
102     let mut func_ctx = FunctionBuilderContext::new();
103     let mut bcx = FunctionBuilder::new(&mut func, &mut func_ctx);
104
105     // Step 5. Predefine ebb's
106     let start_ebb = bcx.create_ebb();
107     let mut ebb_map: HashMap<BasicBlock, Ebb> = HashMap::new();
108     for (bb, _bb_data) in mir.basic_blocks().iter_enumerated() {
109         ebb_map.insert(bb, bcx.create_ebb());
110     }
111
112     // Step 6. Make FunctionCx
113     let pointer_type = cx.module.target_config().pointer_type();
114     let clif_comments = crate::pretty_clif::CommentWriter::new(tcx, instance);
115
116     let mut fx = FunctionCx {
117         tcx,
118         module: cx.module,
119         pointer_type,
120
121         instance,
122         mir,
123
124         bcx,
125         ebb_map,
126         local_map: HashMap::new(),
127
128         clif_comments,
129         constants: &mut cx.ccx,
130         caches: &mut cx.caches,
131         source_info_set: indexmap::IndexSet::new(),
132     };
133
134     // Step 7. Codegen function
135     with_unimpl_span(fx.mir.span, || {
136         crate::abi::codegen_fn_prelude(&mut fx, start_ebb);
137         codegen_fn_content(&mut fx);
138     });
139     let source_info_set = fx.source_info_set.clone();
140
141     // Step 8. Write function to file for debugging
142     #[cfg(debug_assertions)]
143     fx.write_clif_file();
144
145     // Step 9. Verify function
146     verify_func(tcx, fx.clif_comments, &func);
147
148     // Step 10. Define function
149     cx.caches.context.func = func;
150     cx.module
151         .define_function(func_id, &mut cx.caches.context)
152         .unwrap();
153
154     // Step 11. Define debuginfo for function
155     let context = &cx.caches.context;
156     let isa = cx.module.isa();
157     debug_context
158         .as_mut()
159         .map(|x| x.define(tcx, context, isa, &source_info_set));
160
161     // Step 12. Clear context to make it usable for the next function
162     cx.caches.context.clear();
163 }
164
165 fn verify_func(tcx: TyCtxt, writer: crate::pretty_clif::CommentWriter, func: &Function) {
166     let flags = settings::Flags::new(settings::builder());
167     match ::cranelift::codegen::verify_function(&func, &flags) {
168         Ok(_) => {}
169         Err(err) => {
170             tcx.sess.err(&format!("{:?}", err));
171             let pretty_error = ::cranelift::codegen::print_errors::pretty_verifier_error(
172                 &func,
173                 None,
174                 Some(Box::new(&writer)),
175                 err,
176             );
177             tcx.sess
178                 .fatal(&format!("cranelift verify error:\n{}", pretty_error));
179         }
180     }
181 }
182
183 fn codegen_fn_content<'a, 'tcx: 'a>(fx: &mut FunctionCx<'a, 'tcx, impl Backend>) {
184     for (bb, bb_data) in fx.mir.basic_blocks().iter_enumerated() {
185         if bb_data.is_cleanup {
186             // Unwinding after panicking is not supported
187             continue;
188         }
189
190         let ebb = fx.get_ebb(bb);
191         fx.bcx.switch_to_block(ebb);
192
193         fx.bcx.ins().nop();
194         for stmt in &bb_data.statements {
195             fx.set_debug_loc(stmt.source_info);
196             trans_stmt(fx, ebb, stmt);
197         }
198
199         #[cfg(debug_assertions)]
200         {
201             let mut terminator_head = "\n".to_string();
202             bb_data
203                 .terminator()
204                 .kind
205                 .fmt_head(&mut terminator_head)
206                 .unwrap();
207             let inst = fx.bcx.func.layout.last_inst(ebb).unwrap();
208             fx.add_comment(inst, terminator_head);
209         }
210
211         fx.set_debug_loc(bb_data.terminator().source_info);
212
213         match &bb_data.terminator().kind {
214             TerminatorKind::Goto { target } => {
215                 let ebb = fx.get_ebb(*target);
216                 fx.bcx.ins().jump(ebb, &[]);
217             }
218             TerminatorKind::Return => {
219                 crate::abi::codegen_return(fx);
220             }
221             TerminatorKind::Assert {
222                 cond,
223                 expected,
224                 msg,
225                 target,
226                 cleanup: _,
227             } => {
228                 let cond = trans_operand(fx, cond).load_scalar(fx);
229                 // TODO HACK brz/brnz for i8/i16 is not yet implemented
230                 let cond = fx.bcx.ins().uextend(types::I32, cond);
231                 let target = fx.get_ebb(*target);
232                 if *expected {
233                     fx.bcx.ins().brnz(cond, target, &[]);
234                 } else {
235                     fx.bcx.ins().brz(cond, target, &[]);
236                 };
237                 trap_panic(fx, format!("[panic] Assert {:?} failed.", msg));
238             }
239
240             TerminatorKind::SwitchInt {
241                 discr,
242                 switch_ty: _,
243                 values,
244                 targets,
245             } => {
246                 let discr = trans_operand(fx, discr).load_scalar(fx);
247                 let mut switch = ::cranelift::frontend::Switch::new();
248                 for (i, value) in values.iter().enumerate() {
249                     let ebb = fx.get_ebb(targets[i]);
250                     switch.set_entry(*value as u64, ebb);
251                 }
252                 let otherwise_ebb = fx.get_ebb(targets[targets.len() - 1]);
253                 switch.emit(&mut fx.bcx, discr, otherwise_ebb);
254             }
255             TerminatorKind::Call {
256                 func,
257                 args,
258                 destination,
259                 cleanup: _,
260                 from_hir_call: _,
261             } => {
262                 crate::abi::codegen_terminator_call(fx, func, args, destination);
263             }
264             TerminatorKind::Resume | TerminatorKind::Abort => {
265                 trap_unreachable(fx, "[corruption] Unwinding bb reached.");
266             }
267             TerminatorKind::Unreachable => {
268                 trap_unreachable(fx, "[corruption] Hit unreachable code.");
269             }
270             TerminatorKind::Yield { .. }
271             | TerminatorKind::FalseEdges { .. }
272             | TerminatorKind::FalseUnwind { .. }
273             | TerminatorKind::DropAndReplace { .. }
274             | TerminatorKind::GeneratorDrop => {
275                 bug!("shouldn't exist at trans {:?}", bb_data.terminator());
276             }
277             TerminatorKind::Drop {
278                 location,
279                 target,
280                 unwind: _,
281             } => {
282                 let ty = location.ty(fx.mir, fx.tcx).ty;
283                 let ty = fx.monomorphize(&ty);
284                 let drop_fn = crate::rustc_mir::monomorphize::resolve_drop_in_place(fx.tcx, ty);
285
286                 if let ty::InstanceDef::DropGlue(_, None) = drop_fn.def {
287                     // we don't actually need to drop anything
288                 } else {
289                     let drop_place = trans_place(fx, location);
290                     let drop_fn_ty = drop_fn.ty(fx.tcx);
291                     match ty.sty {
292                         ty::Dynamic(..) => {
293                             crate::abi::codegen_drop(fx, drop_place, drop_fn_ty);
294                         }
295                         _ => {
296                             let arg_place = CPlace::new_stack_slot(
297                                 fx,
298                                 fx.tcx.mk_ref(
299                                     &ty::RegionKind::ReErased,
300                                     TypeAndMut {
301                                         ty,
302                                         mutbl: crate::rustc::hir::Mutability::MutMutable,
303                                     },
304                                 ),
305                             );
306                             drop_place.write_place_ref(fx, arg_place);
307                             let arg_value = arg_place.to_cvalue(fx);
308                             crate::abi::codegen_call_inner(
309                                 fx,
310                                 None,
311                                 drop_fn_ty,
312                                 vec![arg_value],
313                                 None,
314                             );
315                         }
316                     }
317                 }
318
319                 let target_ebb = fx.get_ebb(*target);
320                 fx.bcx.ins().jump(target_ebb, &[]);
321             }
322         };
323     }
324
325     fx.bcx.seal_all_blocks();
326     fx.bcx.finalize();
327 }
328
329 fn trans_stmt<'a, 'tcx: 'a>(
330     fx: &mut FunctionCx<'a, 'tcx, impl Backend>,
331     cur_ebb: Ebb,
332     stmt: &Statement<'tcx>,
333 ) {
334     let _print_guard = PrintOnPanic(|| format!("stmt {:?}", stmt));
335
336     fx.set_debug_loc(stmt.source_info);
337
338     #[cfg(debug_assertions)]
339     match &stmt.kind {
340         StatementKind::StorageLive(..) | StatementKind::StorageDead(..) => {} // Those are not very useful
341         _ => {
342             let inst = fx.bcx.func.layout.last_inst(cur_ebb).unwrap();
343             fx.add_comment(inst, format!("{:?}", stmt));
344         }
345     }
346
347     match &stmt.kind {
348         StatementKind::SetDiscriminant {
349             place,
350             variant_index,
351         } => {
352             let place = trans_place(fx, place);
353             let layout = place.layout();
354             if layout.for_variant(&*fx, *variant_index).abi == layout::Abi::Uninhabited {
355                 return;
356             }
357             match layout.variants {
358                 layout::Variants::Single { index } => {
359                     assert_eq!(index, *variant_index);
360                 }
361                 layout::Variants::Multiple {
362                     discr: _,
363                     discr_index,
364                     discr_kind: layout::DiscriminantKind::Tag,
365                     variants: _,
366                 } => {
367                     let ptr = place.place_field(fx, mir::Field::new(discr_index));
368                     let to = layout
369                         .ty
370                         .ty_adt_def()
371                         .unwrap()
372                         .discriminant_for_variant(fx.tcx, *variant_index)
373                         .val;
374                     let discr = CValue::const_val(fx, ptr.layout().ty, to as u64 as i64);
375                     ptr.write_cvalue(fx, discr);
376                 }
377                 layout::Variants::Multiple {
378                     discr: _,
379                     discr_index,
380                     discr_kind: layout::DiscriminantKind::Niche {
381                         dataful_variant,
382                         ref niche_variants,
383                         niche_start,
384                     },
385                     variants: _,
386                 } => {
387                     if *variant_index != dataful_variant {
388                         let niche = place.place_field(fx, mir::Field::new(discr_index));
389                         //let niche_llty = niche.layout.immediate_llvm_type(bx.cx);
390                         let niche_value =
391                             ((variant_index.as_u32() - niche_variants.start().as_u32()) as u128)
392                                 .wrapping_add(niche_start);
393                         // FIXME(eddyb) Check the actual primitive type here.
394                         let niche_llval = if niche_value == 0 {
395                             CValue::const_val(fx, niche.layout().ty, 0)
396                         } else {
397                             CValue::const_val(fx, niche.layout().ty, niche_value as u64 as i64)
398                         };
399                         niche.write_cvalue(fx, niche_llval);
400                     }
401                 }
402             }
403         }
404         StatementKind::Assign(to_place, rval) => {
405             let lval = trans_place(fx, to_place);
406             let dest_layout = lval.layout();
407             match &**rval {
408                 Rvalue::Use(operand) => {
409                     let val = trans_operand(fx, operand);
410                     lval.write_cvalue(fx, val);
411                 }
412                 Rvalue::Ref(_, _, place) => {
413                     let place = trans_place(fx, place);
414                     place.write_place_ref(fx, lval);
415                 }
416                 Rvalue::BinaryOp(bin_op, lhs, rhs) => {
417                     let ty = fx.monomorphize(&lhs.ty(fx.mir, fx.tcx));
418                     let lhs = trans_operand(fx, lhs);
419                     let rhs = trans_operand(fx, rhs);
420
421                     let res = match ty.sty {
422                         ty::Bool => trans_bool_binop(fx, *bin_op, lhs, rhs, lval.layout().ty),
423                         ty::Uint(_) => {
424                             trans_int_binop(fx, *bin_op, lhs, rhs, lval.layout().ty, false)
425                         }
426                         ty::Int(_) => {
427                             trans_int_binop(fx, *bin_op, lhs, rhs, lval.layout().ty, true)
428                         }
429                         ty::Float(_) => trans_float_binop(fx, *bin_op, lhs, rhs, lval.layout().ty),
430                         ty::Char => trans_char_binop(fx, *bin_op, lhs, rhs, lval.layout().ty),
431                         ty::RawPtr(..) => trans_ptr_binop(fx, *bin_op, lhs, rhs, lval.layout().ty),
432                         ty::FnPtr(..) => trans_ptr_binop(fx, *bin_op, lhs, rhs, lval.layout().ty),
433                         _ => unimplemented!("binop {:?} for {:?}", bin_op, ty),
434                     };
435                     lval.write_cvalue(fx, res);
436                 }
437                 Rvalue::CheckedBinaryOp(bin_op, lhs, rhs) => {
438                     let ty = fx.monomorphize(&lhs.ty(fx.mir, fx.tcx));
439                     let lhs = trans_operand(fx, lhs);
440                     let rhs = trans_operand(fx, rhs);
441
442                     let res = match ty.sty {
443                         ty::Uint(_) => {
444                             trans_checked_int_binop(fx, *bin_op, lhs, rhs, lval.layout().ty, false)
445                         }
446                         ty::Int(_) => {
447                             trans_checked_int_binop(fx, *bin_op, lhs, rhs, lval.layout().ty, true)
448                         }
449                         _ => unimplemented!("checked binop {:?} for {:?}", bin_op, ty),
450                     };
451                     lval.write_cvalue(fx, res);
452                 }
453                 Rvalue::UnaryOp(un_op, operand) => {
454                     let operand = trans_operand(fx, operand);
455                     let layout = operand.layout();
456                     let val = operand.load_scalar(fx);
457                     let res = match un_op {
458                         UnOp::Not => {
459                             match layout.ty.sty {
460                                 ty::Bool => {
461                                     let val = fx.bcx.ins().uextend(types::I32, val); // WORKAROUND for CraneStation/cranelift#466
462                                     let res = fx.bcx.ins().icmp_imm(IntCC::Equal, val, 0);
463                                     fx.bcx.ins().bint(types::I8, res)
464                                 }
465                                 ty::Uint(_) | ty::Int(_) => fx.bcx.ins().bnot(val),
466                                 _ => unimplemented!("un op Not for {:?}", layout.ty),
467                             }
468                         }
469                         UnOp::Neg => match layout.ty.sty {
470                             ty::Int(_) => {
471                                 let clif_ty = fx.clif_type(layout.ty).unwrap();
472                                 let zero = fx.bcx.ins().iconst(clif_ty, 0);
473                                 fx.bcx.ins().isub(zero, val)
474                             }
475                             ty::Float(_) => fx.bcx.ins().fneg(val),
476                             _ => unimplemented!("un op Neg for {:?}", layout.ty),
477                         },
478                     };
479                     lval.write_cvalue(fx, CValue::ByVal(res, layout));
480                 }
481                 Rvalue::Cast(CastKind::Pointer(PointerCast::ReifyFnPointer), operand, ty) => {
482                     let layout = fx.layout_of(ty);
483                     match fx
484                         .monomorphize(&operand.ty(&fx.mir.local_decls, fx.tcx))
485                         .sty
486                     {
487                         ty::FnDef(def_id, substs) => {
488                             let func_ref = fx.get_function_ref(
489                                 Instance::resolve(fx.tcx, ParamEnv::reveal_all(), def_id, substs)
490                                     .unwrap(),
491                             );
492                             let func_addr = fx.bcx.ins().func_addr(fx.pointer_type, func_ref);
493                             lval.write_cvalue(fx, CValue::ByVal(func_addr, layout));
494                         }
495                         _ => bug!("Trying to ReifyFnPointer on non FnDef {:?}", ty),
496                     }
497                 }
498                 Rvalue::Cast(CastKind::Pointer(PointerCast::UnsafeFnPointer), operand, ty)
499                 | Rvalue::Cast(CastKind::Pointer(PointerCast::MutToConstPointer), operand, ty) => {
500                     let operand = trans_operand(fx, operand);
501                     let layout = fx.layout_of(ty);
502                     lval.write_cvalue(fx, operand.unchecked_cast_to(layout));
503                 }
504                 Rvalue::Cast(CastKind::Misc, operand, to_ty) => {
505                     let operand = trans_operand(fx, operand);
506                     let from_ty = operand.layout().ty;
507
508                     fn is_fat_ptr<'a, 'tcx: 'a>(fx: &FunctionCx<'a, 'tcx, impl Backend>, ty: Ty<'tcx>) -> bool {
509                         ty
510                             .builtin_deref(true)
511                             .map(|ty::TypeAndMut {ty: pointee_ty, mutbl: _ }| fx.layout_of(pointee_ty).is_unsized())
512                             .unwrap_or(false)
513                     }
514
515                     if is_fat_ptr(fx, from_ty) {
516                         if is_fat_ptr(fx, to_ty) {
517                             // fat-ptr -> fat-ptr
518                             lval.write_cvalue(fx, operand.unchecked_cast_to(dest_layout));
519                         } else {
520                             // fat-ptr -> thin-ptr
521                             let (ptr, _extra) = operand.load_scalar_pair(fx);
522                             lval.write_cvalue(fx, CValue::ByVal(ptr, dest_layout))
523                         }
524                     } else if let ty::Adt(adt_def, _substs) = from_ty.sty {
525                         // enum -> discriminant value
526                         assert!(adt_def.is_enum());
527                         match to_ty.sty {
528                             ty::Uint(_) | ty::Int(_) => {},
529                             _ => unreachable!("cast adt {} -> {}", from_ty, to_ty),
530                         }
531
532                         // FIXME avoid forcing to stack
533                         let place =
534                             CPlace::Addr(operand.force_stack(fx), None, operand.layout());
535                         let discr = trans_get_discriminant(fx, place, fx.layout_of(to_ty));
536                         lval.write_cvalue(fx, discr);
537                     } else {
538                         let from_clif_ty = fx.clif_type(from_ty).unwrap();
539                         let to_clif_ty = fx.clif_type(to_ty).unwrap();
540                         let from = operand.load_scalar(fx);
541
542                         let signed = match from_ty.sty {
543                             ty::Ref(..) | ty::RawPtr(..) | ty::FnPtr(..) | ty::Char | ty::Uint(..) | ty::Bool => false,
544                             ty::Int(..) => true,
545                             ty::Float(..) => false, // `signed` is unused for floats
546                             _ => panic!("{}", from_ty),
547                         };
548
549                         let res = if from_clif_ty.is_int() && to_clif_ty.is_int() {
550                             // int-like -> int-like
551                             crate::common::clif_intcast(
552                                 fx,
553                                 from,
554                                 to_clif_ty,
555                                 signed,
556                             )
557                         } else if from_clif_ty.is_int() && to_clif_ty.is_float() {
558                             // int-like -> float
559                             // FIXME missing encoding for fcvt_from_sint.f32.i8
560                             let from = if from_clif_ty == types::I8 || from_clif_ty == types::I16 {
561                                 fx.bcx.ins().uextend(types::I32, from)
562                             } else {
563                                 from
564                             };
565                             if signed {
566                                 fx.bcx.ins().fcvt_from_sint(to_clif_ty, from)
567                             } else {
568                                 fx.bcx.ins().fcvt_from_uint(to_clif_ty, from)
569                             }
570                         } else if from_clif_ty.is_float() && to_clif_ty.is_int() {
571                             // float -> int-like
572                             let from = operand.load_scalar(fx);
573                             if signed {
574                                 fx.bcx.ins().fcvt_to_sint_sat(to_clif_ty, from)
575                             } else {
576                                 fx.bcx.ins().fcvt_to_uint_sat(to_clif_ty, from)
577                             }
578                         } else if from_clif_ty.is_float() && to_clif_ty.is_float() {
579                             // float -> float
580                             match (from_clif_ty, to_clif_ty) {
581                                 (types::F32, types::F64) => {
582                                     fx.bcx.ins().fpromote(types::F64, from)
583                                 }
584                                 (types::F64, types::F32) => {
585                                     fx.bcx.ins().fdemote(types::F32, from)
586                                 }
587                                 _ => from,
588                             }
589                         } else {
590                             unimpl!("rval misc {:?} {:?}", from_ty, to_ty)
591                         };
592                         lval.write_cvalue(fx, CValue::ByVal(res, dest_layout));
593                     }
594                 }
595                 Rvalue::Cast(CastKind::Pointer(PointerCast::ClosureFnPointer(_)), operand, _ty) => {
596                     let operand = trans_operand(fx, operand);
597                     match operand.layout().ty.sty {
598                         ty::Closure(def_id, substs) => {
599                             let instance = rustc_mir::monomorphize::resolve_closure(
600                                 fx.tcx,
601                                 def_id,
602                                 substs,
603                                 ty::ClosureKind::FnOnce,
604                             );
605                             let func_ref = fx.get_function_ref(instance);
606                             let func_addr = fx.bcx.ins().func_addr(fx.pointer_type, func_ref);
607                             lval.write_cvalue(fx, CValue::ByVal(func_addr, lval.layout()));
608                         }
609                         _ => {
610                             bug!("{} cannot be cast to a fn ptr", operand.layout().ty)
611                         }
612                     }
613                 }
614                 Rvalue::Cast(CastKind::Pointer(PointerCast::Unsize), operand, _ty) => {
615                     let operand = trans_operand(fx, operand);
616                     operand.unsize_value(fx, lval);
617                 }
618                 Rvalue::Discriminant(place) => {
619                     let place = trans_place(fx, place);
620                     let discr = trans_get_discriminant(fx, place, dest_layout);
621                     lval.write_cvalue(fx, discr);
622                 }
623                 Rvalue::Repeat(operand, times) => {
624                     let operand = trans_operand(fx, operand);
625                     for i in 0..*times {
626                         let index = fx.bcx.ins().iconst(fx.pointer_type, i as i64);
627                         let to = lval.place_index(fx, index);
628                         to.write_cvalue(fx, operand);
629                     }
630                 }
631                 Rvalue::Len(place) => {
632                     let place = trans_place(fx, place);
633                     let usize_layout = fx.layout_of(fx.tcx.types.usize);
634                     let len = codegen_array_len(fx, place);
635                     lval.write_cvalue(fx, CValue::ByVal(len, usize_layout));
636                 }
637                 Rvalue::NullaryOp(NullOp::Box, content_ty) => {
638                     use rustc::middle::lang_items::ExchangeMallocFnLangItem;
639
640                     let usize_type = fx.clif_type(fx.tcx.types.usize).unwrap();
641                     let layout = fx.layout_of(content_ty);
642                     let llsize = fx.bcx.ins().iconst(usize_type, layout.size.bytes() as i64);
643                     let llalign = fx
644                         .bcx
645                         .ins()
646                         .iconst(usize_type, layout.align.abi.bytes() as i64);
647                     let box_layout = fx.layout_of(fx.tcx.mk_box(content_ty));
648
649                     // Allocate space:
650                     let def_id = match fx.tcx.lang_items().require(ExchangeMallocFnLangItem) {
651                         Ok(id) => id,
652                         Err(s) => {
653                             fx.tcx
654                                 .sess
655                                 .fatal(&format!("allocation of `{}` {}", box_layout.ty, s));
656                         }
657                     };
658                     let instance = ty::Instance::mono(fx.tcx, def_id);
659                     let func_ref = fx.get_function_ref(instance);
660                     let call = fx.bcx.ins().call(func_ref, &[llsize, llalign]);
661                     let ptr = fx.bcx.inst_results(call)[0];
662                     lval.write_cvalue(fx, CValue::ByVal(ptr, box_layout));
663                 }
664                 Rvalue::NullaryOp(NullOp::SizeOf, ty) => {
665                     assert!(lval
666                         .layout()
667                         .ty
668                         .is_sized(fx.tcx.at(DUMMY_SP), ParamEnv::reveal_all()));
669                     let ty_size = fx.layout_of(ty).size.bytes();
670                     let val = CValue::const_val(fx, fx.tcx.types.usize, ty_size as i64);
671                     lval.write_cvalue(fx, val);
672                 }
673                 Rvalue::Aggregate(kind, operands) => match **kind {
674                     AggregateKind::Array(_ty) => {
675                         for (i, operand) in operands.into_iter().enumerate() {
676                             let operand = trans_operand(fx, operand);
677                             let index = fx.bcx.ins().iconst(fx.pointer_type, i as i64);
678                             let to = lval.place_index(fx, index);
679                             to.write_cvalue(fx, operand);
680                         }
681                     }
682                     _ => unimpl!("shouldn't exist at trans {:?}", rval),
683                 },
684             }
685         }
686         StatementKind::StorageLive(_)
687         | StatementKind::StorageDead(_)
688         | StatementKind::Nop
689         | StatementKind::FakeRead(..)
690         | StatementKind::Retag { .. }
691         | StatementKind::AscribeUserType(..) => {}
692
693         StatementKind::InlineAsm { .. } => unimpl!("Inline assembly is not supported"),
694     }
695 }
696
697 fn codegen_array_len<'a, 'tcx: 'a>(
698     fx: &mut FunctionCx<'a, 'tcx, impl Backend>,
699     place: CPlace<'tcx>,
700 ) -> Value {
701     match place.layout().ty.sty {
702         ty::Array(_elem_ty, len) => {
703             let len = crate::constant::force_eval_const(fx, len).unwrap_usize(fx.tcx) as i64;
704             fx.bcx.ins().iconst(fx.pointer_type, len)
705         }
706         ty::Slice(_elem_ty) => place
707             .to_addr_maybe_unsized(fx)
708             .1
709             .expect("Length metadata for slice place"),
710         _ => bug!("Rvalue::Len({:?})", place),
711     }
712 }
713
714 pub fn trans_get_discriminant<'a, 'tcx: 'a>(
715     fx: &mut FunctionCx<'a, 'tcx, impl Backend>,
716     place: CPlace<'tcx>,
717     dest_layout: TyLayout<'tcx>,
718 ) -> CValue<'tcx> {
719     let layout = place.layout();
720
721     if layout.abi == layout::Abi::Uninhabited {
722         return trap_unreachable_ret_value(fx, dest_layout, "[panic] Tried to get discriminant for uninhabited type.");
723     }
724
725     let (discr_scalar, discr_index, discr_kind) = match &layout.variants {
726         layout::Variants::Single { index } => {
727             let discr_val = layout
728                 .ty
729                 .ty_adt_def()
730                 .map_or(index.as_u32() as u128, |def| {
731                     def.discriminant_for_variant(fx.tcx, *index).val
732                 });
733             return CValue::const_val(fx, dest_layout.ty, discr_val as u64 as i64);
734         }
735         layout::Variants::Multiple { discr, discr_index, discr_kind, variants: _ } => {
736             (discr, *discr_index, discr_kind)
737         }
738     };
739
740     let discr = place.place_field(fx, mir::Field::new(discr_index)).to_cvalue(fx);
741     let discr_ty = discr.layout().ty;
742     let lldiscr = discr.load_scalar(fx);
743     match discr_kind {
744         layout::DiscriminantKind::Tag => {
745             let signed = match discr_scalar.value {
746                 layout::Int(_, signed) => signed,
747                 _ => false,
748             };
749             let val = clif_intcast(fx, lldiscr, fx.clif_type(dest_layout.ty).unwrap(), signed);
750             return CValue::ByVal(val, dest_layout);
751         }
752         layout::DiscriminantKind::Niche {
753             dataful_variant,
754             ref niche_variants,
755             niche_start,
756         } => {
757             let niche_llty = fx.clif_type(discr_ty).unwrap();
758             let dest_clif_ty = fx.clif_type(dest_layout.ty).unwrap();
759             if niche_variants.start() == niche_variants.end() {
760                 let b = fx
761                     .bcx
762                     .ins()
763                     .icmp_imm(IntCC::Equal, lldiscr, *niche_start as u64 as i64);
764                 let if_true = fx
765                     .bcx
766                     .ins()
767                     .iconst(dest_clif_ty, niche_variants.start().as_u32() as i64);
768                 let if_false = fx
769                     .bcx
770                     .ins()
771                     .iconst(dest_clif_ty, dataful_variant.as_u32() as i64);
772                 let val = fx.bcx.ins().select(b, if_true, if_false);
773                 return CValue::ByVal(val, dest_layout);
774             } else {
775                 // Rebase from niche values to discriminant values.
776                 let delta = niche_start.wrapping_sub(niche_variants.start().as_u32() as u128);
777                 let delta = fx.bcx.ins().iconst(niche_llty, delta as u64 as i64);
778                 let lldiscr = fx.bcx.ins().isub(lldiscr, delta);
779                 let b = fx.bcx.ins().icmp_imm(
780                     IntCC::UnsignedLessThanOrEqual,
781                     lldiscr,
782                     niche_variants.end().as_u32() as i64,
783                 );
784                 let if_true =
785                     clif_intcast(fx, lldiscr, fx.clif_type(dest_layout.ty).unwrap(), false);
786                 let if_false = fx
787                     .bcx
788                     .ins()
789                     .iconst(dest_clif_ty, dataful_variant.as_u32() as i64);
790                 let val = fx.bcx.ins().select(b, if_true, if_false);
791                 return CValue::ByVal(val, dest_layout);
792             }
793         }
794     }
795 }
796
797 macro_rules! binop_match {
798     (@single $fx:expr, $bug_fmt:expr, $var:expr, $signed:expr, $lhs:expr, $rhs:expr, $ret_ty:expr, bug) => {
799         bug!("binop {} on {} lhs: {:?} rhs: {:?}", stringify!($var), $bug_fmt, $lhs, $rhs)
800     };
801     (@single $fx:expr, $bug_fmt:expr, $var:expr, $signed:expr, $lhs:expr, $rhs:expr, $ret_ty:expr, icmp($cc:ident)) => {{
802         assert_eq!($fx.tcx.types.bool, $ret_ty);
803         let ret_layout = $fx.layout_of($ret_ty);
804
805         let b = $fx.bcx.ins().icmp(IntCC::$cc, $lhs, $rhs);
806         CValue::ByVal($fx.bcx.ins().bint(types::I8, b), ret_layout)
807     }};
808     (@single $fx:expr, $bug_fmt:expr, $var:expr, $signed:expr, $lhs:expr, $rhs:expr, $ret_ty:expr, fcmp($cc:ident)) => {{
809         assert_eq!($fx.tcx.types.bool, $ret_ty);
810         let ret_layout = $fx.layout_of($ret_ty);
811         let b = $fx.bcx.ins().fcmp(FloatCC::$cc, $lhs, $rhs);
812         CValue::ByVal($fx.bcx.ins().bint(types::I8, b), ret_layout)
813     }};
814     (@single $fx:expr, $bug_fmt:expr, $var:expr, $signed:expr, $lhs:expr, $rhs:expr, $ret_ty:expr, custom(|| $body:expr)) => {{
815         $body
816     }};
817     (@single $fx:expr, $bug_fmt:expr, $var:expr, $signed:expr, $lhs:expr, $rhs:expr, $ret_ty:expr, $name:ident) => {{
818         let ret_layout = $fx.layout_of($ret_ty);
819         CValue::ByVal($fx.bcx.ins().$name($lhs, $rhs), ret_layout)
820     }};
821     (
822         $fx:expr, $bin_op:expr, $signed:expr, $lhs:expr, $rhs:expr, $ret_ty:expr, $bug_fmt:expr;
823         $(
824             $var:ident ($sign:pat) $name:tt $( ( $($next:tt)* ) )? ;
825         )*
826     ) => {{
827         let lhs = $lhs.load_scalar($fx);
828         let rhs = $rhs.load_scalar($fx);
829         match ($bin_op, $signed) {
830             $(
831                 (BinOp::$var, $sign) => binop_match!(@single $fx, $bug_fmt, $var, $signed, lhs, rhs, $ret_ty, $name $( ( $($next)* ) )?),
832             )*
833         }
834     }}
835 }
836
837 fn trans_bool_binop<'a, 'tcx: 'a>(
838     fx: &mut FunctionCx<'a, 'tcx, impl Backend>,
839     bin_op: BinOp,
840     lhs: CValue<'tcx>,
841     rhs: CValue<'tcx>,
842     ty: Ty<'tcx>,
843 ) -> CValue<'tcx> {
844     let res = binop_match! {
845         fx, bin_op, false, lhs, rhs, ty, "bool";
846         Add (_) bug;
847         Sub (_) bug;
848         Mul (_) bug;
849         Div (_) bug;
850         Rem (_) bug;
851         BitXor (_) bxor;
852         BitAnd (_) band;
853         BitOr (_) bor;
854         Shl (_) bug;
855         Shr (_) bug;
856
857         Eq (_) icmp(Equal);
858         Lt (_) icmp(UnsignedLessThan);
859         Le (_) icmp(UnsignedLessThanOrEqual);
860         Ne (_) icmp(NotEqual);
861         Ge (_) icmp(UnsignedGreaterThanOrEqual);
862         Gt (_) icmp(UnsignedGreaterThan);
863
864         Offset (_) bug;
865     };
866
867     res
868 }
869
870 pub fn trans_int_binop<'a, 'tcx: 'a>(
871     fx: &mut FunctionCx<'a, 'tcx, impl Backend>,
872     bin_op: BinOp,
873     lhs: CValue<'tcx>,
874     rhs: CValue<'tcx>,
875     out_ty: Ty<'tcx>,
876     signed: bool,
877 ) -> CValue<'tcx> {
878     if bin_op != BinOp::Shl && bin_op != BinOp::Shr {
879         assert_eq!(
880             lhs.layout().ty,
881             rhs.layout().ty,
882             "int binop requires lhs and rhs of same type"
883         );
884     }
885     binop_match! {
886         fx, bin_op, signed, lhs, rhs, out_ty, "int/uint";
887         Add (_) iadd;
888         Sub (_) isub;
889         Mul (_) imul;
890         Div (false) udiv;
891         Div (true) sdiv;
892         Rem (false) urem;
893         Rem (true) srem;
894         BitXor (_) bxor;
895         BitAnd (_) band;
896         BitOr (_) bor;
897         Shl (_) ishl;
898         Shr (false) ushr;
899         Shr (true) sshr;
900
901         Eq (_) icmp(Equal);
902         Lt (false) icmp(UnsignedLessThan);
903         Lt (true) icmp(SignedLessThan);
904         Le (false) icmp(UnsignedLessThanOrEqual);
905         Le (true) icmp(SignedLessThanOrEqual);
906         Ne (_) icmp(NotEqual);
907         Ge (false) icmp(UnsignedGreaterThanOrEqual);
908         Ge (true) icmp(SignedGreaterThanOrEqual);
909         Gt (false) icmp(UnsignedGreaterThan);
910         Gt (true) icmp(SignedGreaterThan);
911
912         Offset (_) bug;
913     }
914 }
915
916 pub fn trans_checked_int_binop<'a, 'tcx: 'a>(
917     fx: &mut FunctionCx<'a, 'tcx, impl Backend>,
918     bin_op: BinOp,
919     in_lhs: CValue<'tcx>,
920     in_rhs: CValue<'tcx>,
921     out_ty: Ty<'tcx>,
922     signed: bool,
923 ) -> CValue<'tcx> {
924     if bin_op != BinOp::Shl && bin_op != BinOp::Shr {
925         assert_eq!(
926             in_lhs.layout().ty,
927             in_rhs.layout().ty,
928             "checked int binop requires lhs and rhs of same type"
929         );
930     }
931
932     let lhs = in_lhs.load_scalar(fx);
933     let rhs = in_rhs.load_scalar(fx);
934     let res = match bin_op {
935         BinOp::Add => fx.bcx.ins().iadd(lhs, rhs),
936         BinOp::Sub => fx.bcx.ins().isub(lhs, rhs),
937         BinOp::Mul => fx.bcx.ins().imul(lhs, rhs),
938         BinOp::Shl => fx.bcx.ins().ishl(lhs, rhs),
939         BinOp::Shr => {
940             if !signed {
941                 fx.bcx.ins().ushr(lhs, rhs)
942             } else {
943                 fx.bcx.ins().sshr(lhs, rhs)
944             }
945         }
946         _ => bug!(
947             "binop {:?} on checked int/uint lhs: {:?} rhs: {:?}",
948             bin_op,
949             in_lhs,
950             in_rhs
951         ),
952     };
953
954     // TODO: check for overflow
955     let has_overflow = fx.bcx.ins().iconst(types::I8, 0);
956
957     let out_place = CPlace::new_stack_slot(fx, out_ty);
958     let out_layout = out_place.layout();
959     out_place.write_cvalue(fx, CValue::ByValPair(res, has_overflow, out_layout));
960
961     out_place.to_cvalue(fx)
962 }
963
964 fn trans_float_binop<'a, 'tcx: 'a>(
965     fx: &mut FunctionCx<'a, 'tcx, impl Backend>,
966     bin_op: BinOp,
967     lhs: CValue<'tcx>,
968     rhs: CValue<'tcx>,
969     ty: Ty<'tcx>,
970 ) -> CValue<'tcx> {
971     let res = binop_match! {
972         fx, bin_op, false, lhs, rhs, ty, "float";
973         Add (_) fadd;
974         Sub (_) fsub;
975         Mul (_) fmul;
976         Div (_) fdiv;
977         Rem (_) custom(|| {
978             assert_eq!(lhs.layout().ty, ty);
979             assert_eq!(rhs.layout().ty, ty);
980             match ty.sty {
981                 ty::Float(FloatTy::F32) => fx.easy_call("fmodf", &[lhs, rhs], ty),
982                 ty::Float(FloatTy::F64) => fx.easy_call("fmod", &[lhs, rhs], ty),
983                 _ => bug!(),
984             }
985         });
986         BitXor (_) bxor;
987         BitAnd (_) band;
988         BitOr (_) bor;
989         Shl (_) bug;
990         Shr (_) bug;
991
992         Eq (_) fcmp(Equal);
993         Lt (_) fcmp(LessThan);
994         Le (_) fcmp(LessThanOrEqual);
995         Ne (_) fcmp(NotEqual);
996         Ge (_) fcmp(GreaterThanOrEqual);
997         Gt (_) fcmp(GreaterThan);
998
999         Offset (_) bug;
1000     };
1001
1002     res
1003 }
1004
1005 fn trans_char_binop<'a, 'tcx: 'a>(
1006     fx: &mut FunctionCx<'a, 'tcx, impl Backend>,
1007     bin_op: BinOp,
1008     lhs: CValue<'tcx>,
1009     rhs: CValue<'tcx>,
1010     ty: Ty<'tcx>,
1011 ) -> CValue<'tcx> {
1012     let res = binop_match! {
1013         fx, bin_op, false, lhs, rhs, ty, "char";
1014         Add (_) bug;
1015         Sub (_) bug;
1016         Mul (_) bug;
1017         Div (_) bug;
1018         Rem (_) bug;
1019         BitXor (_) bug;
1020         BitAnd (_) bug;
1021         BitOr (_) bug;
1022         Shl (_) bug;
1023         Shr (_) bug;
1024
1025         Eq (_) icmp(Equal);
1026         Lt (_) icmp(UnsignedLessThan);
1027         Le (_) icmp(UnsignedLessThanOrEqual);
1028         Ne (_) icmp(NotEqual);
1029         Ge (_) icmp(UnsignedGreaterThanOrEqual);
1030         Gt (_) icmp(UnsignedGreaterThan);
1031
1032         Offset (_) bug;
1033     };
1034
1035     res
1036 }
1037
1038 fn trans_ptr_binop<'a, 'tcx: 'a>(
1039     fx: &mut FunctionCx<'a, 'tcx, impl Backend>,
1040     bin_op: BinOp,
1041     lhs: CValue<'tcx>,
1042     rhs: CValue<'tcx>,
1043     ret_ty: Ty<'tcx>,
1044 ) -> CValue<'tcx> {
1045     let not_fat = match lhs.layout().ty.sty {
1046         ty::RawPtr(TypeAndMut { ty, mutbl: _ }) => {
1047             ty.is_sized(fx.tcx.at(DUMMY_SP), ParamEnv::reveal_all())
1048         }
1049         ty::FnPtr(..) => true,
1050         _ => bug!("trans_ptr_binop on non ptr"),
1051     };
1052     if not_fat {
1053         if let BinOp::Offset = bin_op {
1054             let (base, offset) = (lhs, rhs.load_scalar(fx));
1055             let pointee_ty = base.layout().ty.builtin_deref(true).unwrap().ty;
1056             let pointee_size = fx.layout_of(pointee_ty).size.bytes();
1057             let ptr_diff = fx.bcx.ins().imul_imm(offset, pointee_size as i64);
1058             let base_val = base.load_scalar(fx);
1059             let res = fx.bcx.ins().iadd(base_val, ptr_diff);
1060             return CValue::ByVal(res, base.layout());
1061         }
1062
1063         binop_match! {
1064             fx, bin_op, false, lhs, rhs, ret_ty, "ptr";
1065             Add (_) bug;
1066             Sub (_) bug;
1067             Mul (_) bug;
1068             Div (_) bug;
1069             Rem (_) bug;
1070             BitXor (_) bug;
1071             BitAnd (_) bug;
1072             BitOr (_) bug;
1073             Shl (_) bug;
1074             Shr (_) bug;
1075
1076             Eq (_) icmp(Equal);
1077             Lt (_) icmp(UnsignedLessThan);
1078             Le (_) icmp(UnsignedLessThanOrEqual);
1079             Ne (_) icmp(NotEqual);
1080             Ge (_) icmp(UnsignedGreaterThanOrEqual);
1081             Gt (_) icmp(UnsignedGreaterThan);
1082
1083             Offset (_) bug; // Handled above
1084         }
1085     } else {
1086         let (lhs_ptr, lhs_extra) = lhs.load_scalar_pair(fx);
1087         let (rhs_ptr, rhs_extra) = rhs.load_scalar_pair(fx);
1088         let res = match bin_op {
1089             BinOp::Eq => {
1090                 let ptr_eq = fx.bcx.ins().icmp(IntCC::Equal, lhs_ptr, rhs_ptr);
1091                 let extra_eq = fx.bcx.ins().icmp(IntCC::Equal, lhs_extra, rhs_extra);
1092                 fx.bcx.ins().band(ptr_eq, extra_eq)
1093             }
1094             BinOp::Ne => {
1095                 let ptr_ne = fx.bcx.ins().icmp(IntCC::NotEqual, lhs_ptr, rhs_ptr);
1096                 let extra_ne = fx.bcx.ins().icmp(IntCC::NotEqual, lhs_extra, rhs_extra);
1097                 fx.bcx.ins().bor(ptr_ne, extra_ne)
1098             }
1099             _ => unimplemented!(
1100                 "trans_ptr_binop({:?}, <fat ptr>, <fat ptr>) not implemented",
1101                 bin_op
1102             ),
1103         };
1104
1105         assert_eq!(fx.tcx.types.bool, ret_ty);
1106         let ret_layout = fx.layout_of(ret_ty);
1107         CValue::ByVal(fx.bcx.ins().bint(types::I8, res), ret_layout)
1108     }
1109 }
1110
1111 pub fn trans_place<'a, 'tcx: 'a>(
1112     fx: &mut FunctionCx<'a, 'tcx, impl Backend>,
1113     place: &Place<'tcx>,
1114 ) -> CPlace<'tcx> {
1115     match place {
1116         Place::Base(base) => match base {
1117             PlaceBase::Local(local) => fx.get_local_place(*local),
1118             PlaceBase::Static(static_) => match static_.kind {
1119                 StaticKind::Static(def_id) => {
1120                     crate::constant::codegen_static_ref(fx, def_id, static_.ty)
1121                 }
1122                 StaticKind::Promoted(promoted) => {
1123                     crate::constant::trans_promoted(fx, promoted, static_.ty)
1124                 }
1125             }
1126         }
1127         Place::Projection(projection) => {
1128             let base = trans_place(fx, &projection.base);
1129             match projection.elem {
1130                 ProjectionElem::Deref => base.place_deref(fx),
1131                 ProjectionElem::Field(field, _ty) => base.place_field(fx, field),
1132                 ProjectionElem::Index(local) => {
1133                     let index = fx.get_local_place(local).to_cvalue(fx).load_scalar(fx);
1134                     base.place_index(fx, index)
1135                 }
1136                 ProjectionElem::ConstantIndex {
1137                     offset,
1138                     min_length: _,
1139                     from_end,
1140                 } => {
1141                     let index = if !from_end {
1142                         fx.bcx.ins().iconst(fx.pointer_type, offset as i64)
1143                     } else {
1144                         let len = codegen_array_len(fx, base);
1145                         fx.bcx.ins().iadd_imm(len, -(offset as i64))
1146                     };
1147                     base.place_index(fx, index)
1148                 }
1149                 ProjectionElem::Subslice { from, to } => {
1150                     // These indices are generated by slice patterns.
1151                     // slice[from:-to] in Python terms.
1152
1153                     match base.layout().ty.sty {
1154                         ty::Array(elem_ty, len) => {
1155                             let elem_layout = fx.layout_of(elem_ty);
1156                             let ptr = base.to_addr(fx);
1157                             let len = crate::constant::force_eval_const(fx, len).unwrap_usize(fx.tcx);
1158                             CPlace::Addr(
1159                                 fx.bcx.ins().iadd_imm(ptr, elem_layout.size.bytes() as i64 * from as i64),
1160                                 None,
1161                                 fx.layout_of(fx.tcx.mk_array(elem_ty, len - from as u64 - to as u64)),
1162                             )
1163                         }
1164                         ty::Slice(elem_ty) => {
1165                             let elem_layout = fx.layout_of(elem_ty);
1166                             let (ptr, len) = base.to_addr_maybe_unsized(fx);
1167                             let len = len.unwrap();
1168                             CPlace::Addr(
1169                                 fx.bcx.ins().iadd_imm(ptr, elem_layout.size.bytes() as i64 * from as i64),
1170                                 Some(fx.bcx.ins().iadd_imm(len, -(from as i64 + to as i64))),
1171                                 base.layout(),
1172                             )
1173                         }
1174                         _ => unreachable!(),
1175                     }
1176                 }
1177                 ProjectionElem::Downcast(_adt_def, variant) => base.downcast_variant(fx, variant),
1178             }
1179         }
1180     }
1181 }
1182
1183 pub fn trans_operand<'a, 'tcx>(
1184     fx: &mut FunctionCx<'a, 'tcx, impl Backend>,
1185     operand: &Operand<'tcx>,
1186 ) -> CValue<'tcx> {
1187     match operand {
1188         Operand::Move(place) | Operand::Copy(place) => {
1189             let cplace = trans_place(fx, place);
1190             cplace.to_cvalue(fx)
1191         }
1192         Operand::Constant(const_) => crate::constant::trans_constant(fx, const_),
1193     }
1194 }