]> git.lizzy.rs Git - rust.git/blob - src/base.rs
Rustup to rustc 1.30.0-nightly (2f1547c0a 2018-09-11)
[rust.git] / src / base.rs
1 use crate::prelude::*;
2
3 struct PrintOnPanic<F: Fn() -> String>(F);
4 impl<F: Fn() -> String> Drop for PrintOnPanic<F> {
5     fn drop(&mut self) {
6         if ::std::thread::panicking() {
7             println!("{}", (self.0)());
8         }
9     }
10 }
11
12 pub fn trans_mono_item<'a, 'tcx: 'a>(
13     tcx: TyCtxt<'a, 'tcx, 'tcx>,
14     module: &mut Module<impl Backend>,
15     caches: &mut Caches<'tcx>,
16     ccx: &mut crate::constant::ConstantCx,
17     mono_item: MonoItem<'tcx>,
18 ) {
19     match mono_item {
20         MonoItem::Fn(inst) => {
21             let _inst_guard = PrintOnPanic(|| format!("{:?}", inst));
22             let _mir_guard = PrintOnPanic(|| {
23                 match inst.def {
24                     InstanceDef::Item(_)
25                     | InstanceDef::DropGlue(_, _)
26                     | InstanceDef::Virtual(_, _)
27                         if inst.def_id().krate == LOCAL_CRATE =>
28                     {
29                         let mut mir = ::std::io::Cursor::new(Vec::new());
30                         ::rustc_mir::util::write_mir_pretty(tcx, Some(inst.def_id()), &mut mir)
31                             .unwrap();
32                         String::from_utf8(mir.into_inner()).unwrap()
33                     }
34                     InstanceDef::Item(_)
35                     | InstanceDef::DropGlue(_, _)
36                     | InstanceDef::Virtual(_, _)
37                     | InstanceDef::FnPtrShim(_, _)
38                     | InstanceDef::ClosureOnceShim { .. }
39                     | InstanceDef::CloneShim(_, _) => {
40                         // FIXME fix write_mir_pretty for these instances
41                         format!("{:#?}", tcx.instance_mir(inst.def))
42                     }
43                     InstanceDef::Intrinsic(_) => bug!("tried to codegen intrinsic"),
44                 }
45             });
46
47             trans_fn(tcx, module, ccx, caches, inst);
48         }
49         MonoItem::Static(def_id) => {
50             crate::constant::codegen_static(ccx, def_id);
51         }
52         MonoItem::GlobalAsm(node_id) => tcx
53             .sess
54             .fatal(&format!("Unimplemented global asm mono item {:?}", node_id)),
55     }
56 }
57
58 fn trans_fn<'a, 'tcx: 'a>(
59     tcx: TyCtxt<'a, 'tcx, 'tcx>,
60     module: &mut Module<impl Backend>,
61     constants: &mut crate::constant::ConstantCx,
62     caches: &mut Caches<'tcx>,
63     instance: Instance<'tcx>,
64 ) {
65     // Step 1. Get mir
66     let mir = tcx.instance_mir(instance.def);
67
68     // Step 2. Declare function
69     let (name, sig) = get_function_name_and_sig(tcx, instance);
70     let func_id = module
71         .declare_function(&name, Linkage::Export, &sig)
72         .unwrap();
73
74     // Step 3. Make FunctionBuilder
75     let mut func = Function::with_name_signature(ExternalName::user(0, 0), sig);
76     let mut func_ctx = FunctionBuilderContext::new();
77     let mut bcx: FunctionBuilder = FunctionBuilder::new(&mut func, &mut func_ctx);
78
79     // Step 4. Predefine ebb's
80     let start_ebb = bcx.create_ebb();
81     let mut ebb_map: HashMap<BasicBlock, Ebb> = HashMap::new();
82     for (bb, _bb_data) in mir.basic_blocks().iter_enumerated() {
83         ebb_map.insert(bb, bcx.create_ebb());
84     }
85
86     // Step 5. Make FunctionCx
87     let mut fx = FunctionCx {
88         tcx,
89         module,
90         instance,
91         mir,
92         bcx,
93         param_substs: {
94             assert!(!instance.substs.needs_infer());
95             instance.substs
96         },
97         ebb_map,
98         local_map: HashMap::new(),
99         comments: HashMap::new(),
100         constants,
101         caches,
102
103         top_nop: None,
104     };
105
106     // Step 6. Codegen function
107     crate::abi::codegen_fn_prelude(&mut fx, start_ebb);
108     codegen_fn_content(&mut fx);
109
110     // Step 7. Write function to file for debugging
111     let mut writer = crate::pretty_clif::CommentWriter(fx.comments);
112
113     let mut cton = String::new();
114     if cfg!(debug_assertions) {
115         ::cranelift::codegen::write::decorate_function(&mut writer, &mut cton, &func, None)
116             .unwrap();
117         let clif_file_name = "target/out/clif/".to_string() + &tcx.symbol_name(instance).as_str();
118         ::std::fs::write(clif_file_name, cton.as_bytes()).unwrap();
119     }
120
121     // Step 8. Verify function
122     verify_func(tcx, writer, &func);
123
124     // Step 9. Define function
125     // TODO: cranelift doesn't yet support some of the things needed
126     if should_codegen(tcx.sess) {
127         caches.context.func = func;
128         module
129             .define_function(func_id, &mut caches.context)
130             .unwrap();
131         caches.context.clear();
132     }
133 }
134
135 fn verify_func(tcx: TyCtxt, writer: crate::pretty_clif::CommentWriter, func: &Function) {
136     let flags = settings::Flags::new(settings::builder());
137     match ::cranelift::codegen::verify_function(&func, &flags) {
138         Ok(_) => {}
139         Err(err) => {
140             tcx.sess.err(&format!("{:?}", err));
141             let pretty_error = ::cranelift::codegen::print_errors::pretty_verifier_error(
142                 &func,
143                 None,
144                 Some(Box::new(writer)),
145                 err,
146             );
147             tcx.sess
148                 .fatal(&format!("cretonne verify error:\n{}", pretty_error));
149         }
150     }
151 }
152
153 fn codegen_fn_content<'a, 'tcx: 'a>(fx: &mut FunctionCx<'a, 'tcx, impl Backend>) {
154     for (bb, bb_data) in fx.mir.basic_blocks().iter_enumerated() {
155         let ebb = fx.get_ebb(bb);
156         fx.bcx.switch_to_block(ebb);
157
158         fx.bcx.ins().nop();
159         for stmt in &bb_data.statements {
160             trans_stmt(fx, ebb, stmt);
161         }
162
163         let mut terminator_head = "\n".to_string();
164         bb_data
165             .terminator()
166             .kind
167             .fmt_head(&mut terminator_head)
168             .unwrap();
169         let inst = fx.bcx.func.layout.last_inst(ebb).unwrap();
170         fx.add_comment(inst, terminator_head);
171
172         match &bb_data.terminator().kind {
173             TerminatorKind::Goto { target } => {
174                 let ebb = fx.get_ebb(*target);
175                 fx.bcx.ins().jump(ebb, &[]);
176             }
177             TerminatorKind::Return => {
178                 crate::abi::codegen_return(fx);
179             }
180             TerminatorKind::Assert {
181                 cond,
182                 expected,
183                 msg: _,
184                 target,
185                 cleanup: _,
186             } => {
187                 let cond = trans_operand(fx, cond).load_value(fx);
188                 // TODO HACK brz/brnz for i8/i16 is not yet implemented
189                 let cond = fx.bcx.ins().uextend(types::I32, cond);
190                 let target = fx.get_ebb(*target);
191                 if *expected {
192                     fx.bcx.ins().brnz(cond, target, &[]);
193                 } else {
194                     fx.bcx.ins().brz(cond, target, &[]);
195                 };
196                 fx.bcx.ins().trap(TrapCode::User(!0));
197             }
198
199             TerminatorKind::SwitchInt {
200                 discr,
201                 switch_ty: _,
202                 values,
203                 targets,
204             } => {
205                 // TODO: prevent panics on large and negative disciminants
206                 if should_codegen(fx.tcx.sess) {
207                     let discr = trans_operand(fx, discr).load_value(fx);
208                     let mut jt_data = JumpTableData::new();
209                     for (i, value) in values.iter().enumerate() {
210                         let ebb = fx.get_ebb(targets[i]);
211                         jt_data.set_entry(*value as usize, ebb);
212                     }
213                     let jump_table = fx.bcx.create_jump_table(jt_data);
214                     fx.bcx.ins().br_table(discr, jump_table);
215                     let otherwise_ebb = fx.get_ebb(targets[targets.len() - 1]);
216                     fx.bcx.ins().jump(otherwise_ebb, &[]);
217                 } else {
218                     fx.bcx.ins().trap(TrapCode::User(0));
219                 }
220             }
221             TerminatorKind::Call {
222                 func,
223                 args,
224                 destination,
225                 cleanup: _,
226             } => {
227                 crate::abi::codegen_call(fx, func, args, destination);
228             }
229             TerminatorKind::Resume | TerminatorKind::Abort | TerminatorKind::Unreachable => {
230                 fx.bcx.ins().trap(TrapCode::User(!0));
231             }
232             TerminatorKind::Yield { .. }
233             | TerminatorKind::FalseEdges { .. }
234             | TerminatorKind::FalseUnwind { .. } => {
235                 bug!("shouldn't exist at trans {:?}", bb_data.terminator());
236             }
237             TerminatorKind::Drop { target, .. } | TerminatorKind::DropAndReplace { target, .. } => {
238                 // TODO call drop impl
239                 // unimplemented!("terminator {:?}", bb_data.terminator());
240                 let target_ebb = fx.get_ebb(*target);
241                 fx.bcx.ins().jump(target_ebb, &[]);
242             }
243             TerminatorKind::GeneratorDrop => {
244                 unimplemented!("terminator GeneratorDrop");
245             }
246         };
247     }
248
249     fx.bcx.seal_all_blocks();
250     fx.bcx.finalize();
251 }
252
253 fn trans_stmt<'a, 'tcx: 'a>(
254     fx: &mut FunctionCx<'a, 'tcx, impl Backend>,
255     cur_ebb: Ebb,
256     stmt: &Statement<'tcx>,
257 ) {
258     let _print_guard = PrintOnPanic(|| format!("stmt {:?}", stmt));
259
260     match &stmt.kind {
261         StatementKind::StorageLive(..) | StatementKind::StorageDead(..) => {} // Those are not very useful
262         _ => {
263             let inst = fx.bcx.func.layout.last_inst(cur_ebb).unwrap();
264             fx.add_comment(inst, format!("{:?}", stmt));
265         }
266     }
267
268     match &stmt.kind {
269         StatementKind::SetDiscriminant {
270             place,
271             variant_index,
272         } => {
273             let place = trans_place(fx, place);
274             let layout = place.layout();
275             if layout.for_variant(&*fx, *variant_index).abi == layout::Abi::Uninhabited {
276                 return;
277             }
278             match layout.variants {
279                 layout::Variants::Single { index } => {
280                     assert_eq!(index, *variant_index);
281                 }
282                 layout::Variants::Tagged { .. } => {
283                     let ptr = place.place_field(fx, mir::Field::new(0));
284                     let to = layout
285                         .ty
286                         .ty_adt_def()
287                         .unwrap()
288                         .discriminant_for_variant(fx.tcx, *variant_index)
289                         .val;
290                     let discr = CValue::const_val(fx, ptr.layout().ty, to as u64 as i64);
291                     ptr.write_cvalue(fx, discr);
292                 }
293                 layout::Variants::NicheFilling {
294                     dataful_variant,
295                     ref niche_variants,
296                     niche_start,
297                     ..
298                 } => {
299                     if *variant_index != dataful_variant {
300                         let niche = place.place_field(fx, mir::Field::new(0));
301                         //let niche_llty = niche.layout.immediate_llvm_type(bx.cx);
302                         let niche_value = ((variant_index - *niche_variants.start()) as u128)
303                             .wrapping_add(niche_start);
304                         // FIXME(eddyb) Check the actual primitive type here.
305                         let niche_llval = if niche_value == 0 {
306                             CValue::const_val(fx, niche.layout().ty, 0)
307                         } else {
308                             CValue::const_val(fx, niche.layout().ty, niche_value as u64 as i64)
309                         };
310                         niche.write_cvalue(fx, niche_llval);
311                     }
312                 }
313             }
314         }
315         StatementKind::Assign(to_place, rval) => {
316             let lval = trans_place(fx, to_place);
317             let dest_layout = lval.layout();
318             match rval {
319                 Rvalue::Use(operand) => {
320                     let val = trans_operand(fx, operand);
321                     lval.write_cvalue(fx, val);
322                 }
323                 Rvalue::Ref(_, _, place) => {
324                     let place = trans_place(fx, place);
325                     place.write_place_ref(fx, lval);
326                 }
327                 Rvalue::BinaryOp(bin_op, lhs, rhs) => {
328                     let ty = fx.monomorphize(&lhs.ty(&fx.mir.local_decls, fx.tcx));
329                     let lhs = trans_operand(fx, lhs);
330                     let rhs = trans_operand(fx, rhs);
331
332                     let res = match ty.sty {
333                         ty::Bool => trans_bool_binop(fx, *bin_op, lhs, rhs, lval.layout().ty),
334                         ty::Uint(_) => {
335                             trans_int_binop(fx, *bin_op, lhs, rhs, lval.layout().ty, false)
336                         }
337                         ty::Int(_) => {
338                             trans_int_binop(fx, *bin_op, lhs, rhs, lval.layout().ty, true)
339                         }
340                         ty::Float(_) => trans_float_binop(fx, *bin_op, lhs, rhs, lval.layout().ty),
341                         ty::Char => trans_char_binop(fx, *bin_op, lhs, rhs, lval.layout().ty),
342                         ty::RawPtr(..) => trans_ptr_binop(fx, *bin_op, lhs, rhs, lval.layout().ty),
343                         _ => unimplemented!("binop {:?} for {:?}", bin_op, ty),
344                     };
345                     lval.write_cvalue(fx, res);
346                 }
347                 Rvalue::CheckedBinaryOp(bin_op, lhs, rhs) => {
348                     let ty = fx.monomorphize(&lhs.ty(&fx.mir.local_decls, fx.tcx));
349                     let lhs = trans_operand(fx, lhs);
350                     let rhs = trans_operand(fx, rhs);
351
352                     let res = match ty.sty {
353                         ty::Uint(_) => {
354                             trans_checked_int_binop(fx, *bin_op, lhs, rhs, lval.layout().ty, false)
355                         }
356                         ty::Int(_) => {
357                             trans_checked_int_binop(fx, *bin_op, lhs, rhs, lval.layout().ty, true)
358                         }
359                         _ => unimplemented!("checked binop {:?} for {:?}", bin_op, ty),
360                     };
361                     lval.write_cvalue(fx, res);
362                 }
363                 Rvalue::UnaryOp(un_op, operand) => {
364                     let ty = fx.monomorphize(&operand.ty(&fx.mir.local_decls, fx.tcx));
365                     let layout = fx.layout_of(ty);
366                     let val = trans_operand(fx, operand).load_value(fx);
367                     let res = match un_op {
368                         UnOp::Not => fx.bcx.ins().bnot(val),
369                         UnOp::Neg => match ty.sty {
370                             ty::Int(_) => {
371                                 let clif_ty = fx.cton_type(ty).unwrap();
372                                 let zero = fx.bcx.ins().iconst(clif_ty, 0);
373                                 fx.bcx.ins().isub(zero, val)
374                             }
375                             ty::Float(_) => fx.bcx.ins().fneg(val),
376                             _ => unimplemented!("un op Neg for {:?}", ty),
377                         },
378                     };
379                     lval.write_cvalue(fx, CValue::ByVal(res, layout));
380                 }
381                 Rvalue::Cast(CastKind::ReifyFnPointer, operand, ty) => {
382                     let operand = trans_operand(fx, operand);
383                     let layout = fx.layout_of(ty);
384                     lval.write_cvalue(fx, operand.unchecked_cast_to(layout));
385                 }
386                 Rvalue::Cast(CastKind::UnsafeFnPointer, operand, ty) => {
387                     let operand = trans_operand(fx, operand);
388                     let layout = fx.layout_of(ty);
389                     lval.write_cvalue(fx, operand.unchecked_cast_to(layout));
390                 }
391                 Rvalue::Cast(CastKind::Misc, operand, to_ty) => {
392                     let operand = trans_operand(fx, operand);
393                     let from_ty = operand.layout().ty;
394                     match (&from_ty.sty, &to_ty.sty) {
395                         (ty::Ref(..), ty::Ref(..))
396                         | (ty::Ref(..), ty::RawPtr(..))
397                         | (ty::RawPtr(..), ty::Ref(..))
398                         | (ty::RawPtr(..), ty::RawPtr(..)) => {
399                             lval.write_cvalue(fx, operand.unchecked_cast_to(dest_layout));
400                         }
401                         (ty::RawPtr(..), ty::Uint(_)) | (ty::FnPtr(..), ty::Uint(_))
402                             if to_ty.sty == fx.tcx.types.usize.sty =>
403                         {
404                             lval.write_cvalue(fx, operand.unchecked_cast_to(dest_layout));
405                         }
406                         (ty::Uint(_), ty::RawPtr(..)) if from_ty.sty == fx.tcx.types.usize.sty => {
407                             lval.write_cvalue(fx, operand.unchecked_cast_to(dest_layout));
408                         }
409                         (ty::Char, ty::Uint(_))
410                         | (ty::Uint(_), ty::Char)
411                         | (ty::Uint(_), ty::Int(_))
412                         | (ty::Uint(_), ty::Uint(_)) => {
413                             let from = operand.load_value(fx);
414                             let res = crate::common::cton_intcast(
415                                 fx,
416                                 from,
417                                 fx.cton_type(to_ty).unwrap(),
418                                 false,
419                             );
420                             lval.write_cvalue(fx, CValue::ByVal(res, dest_layout));
421                         }
422                         (ty::Int(_), ty::Int(_)) | (ty::Int(_), ty::Uint(_)) => {
423                             let from = operand.load_value(fx);
424                             let res = crate::common::cton_intcast(
425                                 fx,
426                                 from,
427                                 fx.cton_type(to_ty).unwrap(),
428                                 true,
429                             );
430                             lval.write_cvalue(fx, CValue::ByVal(res, dest_layout));
431                         }
432                         (ty::Float(from_flt), ty::Float(to_flt)) => {
433                             let from = operand.load_value(fx);
434                             let res = match (from_flt, to_flt) {
435                                 (FloatTy::F32, FloatTy::F64) => {
436                                     fx.bcx.ins().fpromote(types::F64, from)
437                                 }
438                                 (FloatTy::F64, FloatTy::F32) => {
439                                     fx.bcx.ins().fdemote(types::F32, from)
440                                 }
441                                 _ => from,
442                             };
443                             lval.write_cvalue(fx, CValue::ByVal(res, dest_layout));
444                         }
445                         (ty::Int(_), ty::Float(_)) => {
446                             let from = operand.load_value(fx);
447                             let f_type = fx.cton_type(to_ty).unwrap();
448                             let res = fx.bcx.ins().fcvt_from_sint(f_type, from);
449                             lval.write_cvalue(fx, CValue::ByVal(res, dest_layout));
450                         }
451                         (ty::Uint(_), ty::Float(_)) => {
452                             let from = operand.load_value(fx);
453                             let f_type = fx.cton_type(to_ty).unwrap();
454                             let res = fx.bcx.ins().fcvt_from_uint(f_type, from);
455                             lval.write_cvalue(fx, CValue::ByVal(res, dest_layout));
456                         }
457                         (ty::Bool, ty::Uint(_)) | (ty::Bool, ty::Int(_)) => {
458                             let to_ty = fx.cton_type(to_ty).unwrap();
459                             let from = operand.load_value(fx);
460                             let res = if to_ty != types::I8 {
461                                 fx.bcx.ins().uextend(to_ty, from)
462                             } else {
463                                 from
464                             };
465                             lval.write_cvalue(fx, CValue::ByVal(res, dest_layout));
466                         }
467                         _ => unimpl!("rval misc {:?} {:?}", from_ty, to_ty),
468                     }
469                 }
470                 Rvalue::Cast(CastKind::ClosureFnPointer, operand, ty) => {
471                     unimplemented!("rval closure_fn_ptr {:?} {:?}", operand, ty)
472                 }
473                 Rvalue::Cast(CastKind::Unsize, operand, ty) => {
474                     let operand = trans_operand(fx, operand);
475                     operand.unsize_value(fx, lval);
476                 }
477                 Rvalue::Discriminant(place) => {
478                     let place = trans_place(fx, place).to_cvalue(fx);
479                     let discr = trans_get_discriminant(fx, place, dest_layout);
480                     lval.write_cvalue(fx, discr);
481                 }
482                 Rvalue::Repeat(operand, times) => {
483                     let operand = trans_operand(fx, operand);
484                     for i in 0..*times {
485                         let index = fx.bcx.ins().iconst(fx.module.pointer_type(), i as i64);
486                         let to = lval.place_index(fx, index);
487                         to.write_cvalue(fx, operand);
488                     }
489                 }
490                 Rvalue::Len(place) => {
491                     let place = trans_place(fx, place);
492                     let size = match place {
493                         CPlace::Addr(_, size, _) => size.unwrap(),
494                         CPlace::Var(_, _) => unreachable!(),
495                     };
496                     let usize_layout = fx.layout_of(fx.tcx.types.usize);
497                     lval.write_cvalue(fx, CValue::ByVal(size, usize_layout));
498                 }
499                 Rvalue::NullaryOp(NullOp::Box, content_ty) => {
500                     use rustc::middle::lang_items::ExchangeMallocFnLangItem;
501
502                     let usize_type = fx.cton_type(fx.tcx.types.usize).unwrap();
503                     let (size, align) = fx.layout_of(content_ty).size_and_align();
504                     let llsize = fx.bcx.ins().iconst(usize_type, size.bytes() as i64);
505                     let llalign = fx.bcx.ins().iconst(usize_type, align.abi() as i64);
506                     let box_layout = fx.layout_of(fx.tcx.mk_box(content_ty));
507
508                     // Allocate space:
509                     let def_id = match fx.tcx.lang_items().require(ExchangeMallocFnLangItem) {
510                         Ok(id) => id,
511                         Err(s) => {
512                             fx.tcx
513                                 .sess
514                                 .fatal(&format!("allocation of `{}` {}", box_layout.ty, s));
515                         }
516                     };
517                     let instance = ty::Instance::mono(fx.tcx, def_id);
518                     let func_ref = fx.get_function_ref(instance);
519                     let call = fx.bcx.ins().call(func_ref, &[llsize, llalign]);
520                     let ptr = fx.bcx.inst_results(call)[0];
521                     lval.write_cvalue(fx, CValue::ByVal(ptr, box_layout));
522                 }
523                 Rvalue::NullaryOp(NullOp::SizeOf, ty) => {
524                     assert!(
525                         lval.layout()
526                             .ty
527                             .is_sized(fx.tcx.at(DUMMY_SP), ParamEnv::reveal_all())
528                     );
529                     let ty_size = fx.layout_of(ty).size.bytes();
530                     let val = CValue::const_val(fx, fx.tcx.types.usize, ty_size as i64);
531                     lval.write_cvalue(fx, val);
532                 }
533                 Rvalue::Aggregate(kind, operands) => match **kind {
534                     AggregateKind::Array(_ty) => {
535                         for (i, operand) in operands.into_iter().enumerate() {
536                             let operand = trans_operand(fx, operand);
537                             let index = fx.bcx.ins().iconst(fx.module.pointer_type(), i as i64);
538                             let to = lval.place_index(fx, index);
539                             to.write_cvalue(fx, operand);
540                         }
541                     }
542                     _ => unimpl!("shouldn't exist at trans {:?}", rval),
543                 },
544             }
545         }
546         StatementKind::StorageLive(_)
547         | StatementKind::StorageDead(_)
548         | StatementKind::Nop
549         | StatementKind::ReadForMatch(_)
550         | StatementKind::Validate(_, _)
551         | StatementKind::EndRegion(_)
552         | StatementKind::AscribeUserType(..) => {}
553
554         StatementKind::InlineAsm { .. } => unimpl!("Inline assembly is not supported"),
555     }
556 }
557
558 pub fn trans_get_discriminant<'a, 'tcx: 'a>(
559     fx: &mut FunctionCx<'a, 'tcx, impl Backend>,
560     value: CValue<'tcx>,
561     dest_layout: TyLayout<'tcx>,
562 ) -> CValue<'tcx> {
563     let layout = value.layout();
564
565     if layout.abi == layout::Abi::Uninhabited {
566         fx.bcx.ins().trap(TrapCode::User(!0));
567     }
568     match layout.variants {
569         layout::Variants::Single { index } => {
570             let discr_val = layout.ty.ty_adt_def().map_or(index as u128, |def| {
571                 def.discriminant_for_variant(fx.tcx, index).val
572             });
573             return CValue::const_val(fx, dest_layout.ty, discr_val as u64 as i64);
574         }
575         layout::Variants::Tagged { .. } | layout::Variants::NicheFilling { .. } => {}
576     }
577
578     let discr = value.value_field(fx, mir::Field::new(0));
579     let discr_ty = discr.layout().ty;
580     let lldiscr = discr.load_value(fx);
581     match layout.variants {
582         layout::Variants::Single { .. } => bug!(),
583         layout::Variants::Tagged { ref tag, .. } => {
584             let signed = match tag.value {
585                 layout::Int(_, signed) => signed,
586                 _ => false,
587             };
588             let val = cton_intcast(fx, lldiscr, fx.cton_type(dest_layout.ty).unwrap(), signed);
589             return CValue::ByVal(val, dest_layout);
590         }
591         layout::Variants::NicheFilling {
592             dataful_variant,
593             ref niche_variants,
594             niche_start,
595             ..
596         } => {
597             let niche_llty = fx.cton_type(discr_ty).unwrap();
598             let dest_cton_ty = fx.cton_type(dest_layout.ty).unwrap();
599             if niche_variants.start() == niche_variants.end() {
600                 let b = fx
601                     .bcx
602                     .ins()
603                     .icmp_imm(IntCC::Equal, lldiscr, niche_start as u64 as i64);
604                 let if_true = fx
605                     .bcx
606                     .ins()
607                     .iconst(dest_cton_ty, *niche_variants.start() as u64 as i64);
608                 let if_false = fx
609                     .bcx
610                     .ins()
611                     .iconst(dest_cton_ty, dataful_variant as u64 as i64);
612                 let val = fx.bcx.ins().select(b, if_true, if_false);
613                 return CValue::ByVal(val, dest_layout);
614             } else {
615                 // Rebase from niche values to discriminant values.
616                 let delta = niche_start.wrapping_sub(*niche_variants.start() as u128);
617                 let delta = fx.bcx.ins().iconst(niche_llty, delta as u64 as i64);
618                 let lldiscr = fx.bcx.ins().isub(lldiscr, delta);
619                 let b = fx.bcx.ins().icmp_imm(
620                     IntCC::UnsignedLessThanOrEqual,
621                     lldiscr,
622                     *niche_variants.end() as u64 as i64,
623                 );
624                 let if_true =
625                     cton_intcast(fx, lldiscr, fx.cton_type(dest_layout.ty).unwrap(), false);
626                 let if_false = fx
627                     .bcx
628                     .ins()
629                     .iconst(dest_cton_ty, dataful_variant as u64 as i64);
630                 let val = fx.bcx.ins().select(b, if_true, if_false);
631                 return CValue::ByVal(val, dest_layout);
632             }
633         }
634     }
635 }
636
637 macro_rules! binop_match {
638     (@single $fx:expr, $bug_fmt:expr, $var:expr, $signed:expr, $lhs:expr, $rhs:expr, $ret_ty:expr, bug) => {
639         bug!("binop {} on {} lhs: {:?} rhs: {:?}", stringify!($var), $bug_fmt, $lhs, $rhs)
640     };
641     (@single $fx:expr, $bug_fmt:expr, $var:expr, $signed:expr, $lhs:expr, $rhs:expr, $ret_ty:expr, icmp($cc:ident)) => {{
642         assert_eq!($fx.tcx.types.bool, $ret_ty);
643         let ret_layout = $fx.layout_of($ret_ty);
644
645         // TODO HACK no encoding for icmp.i8
646         use crate::common::cton_intcast;
647         let (lhs, rhs) = (
648             cton_intcast($fx, $lhs, types::I64, $signed),
649             cton_intcast($fx, $rhs, types::I64, $signed),
650         );
651         let b = $fx.bcx.ins().icmp(IntCC::$cc, lhs, rhs);
652
653         CValue::ByVal($fx.bcx.ins().bint(types::I8, b), ret_layout)
654     }};
655     (@single $fx:expr, $bug_fmt:expr, $var:expr, $signed:expr, $lhs:expr, $rhs:expr, $ret_ty:expr, fcmp($cc:ident)) => {{
656         assert_eq!($fx.tcx.types.bool, $ret_ty);
657         let ret_layout = $fx.layout_of($ret_ty);
658         let b = $fx.bcx.ins().fcmp(FloatCC::$cc, $lhs, $rhs);
659         CValue::ByVal($fx.bcx.ins().bint(types::I8, b), ret_layout)
660     }};
661     (@single $fx:expr, $bug_fmt:expr, $var:expr, $signed:expr, $lhs:expr, $rhs:expr, $ret_ty:expr, custom(|| $body:expr)) => {{
662         $body
663     }};
664     (@single $fx:expr, $bug_fmt:expr, $var:expr, $signed:expr, $lhs:expr, $rhs:expr, $ret_ty:expr, $name:ident) => {{
665         let ret_layout = $fx.layout_of($ret_ty);
666         CValue::ByVal($fx.bcx.ins().$name($lhs, $rhs), ret_layout)
667     }};
668     (
669         $fx:expr, $bin_op:expr, $signed:expr, $lhs:expr, $rhs:expr, $ret_ty:expr, $bug_fmt:expr;
670         $(
671             $var:ident ($sign:pat) $name:tt $( ( $($next:tt)* ) )? ;
672         )*
673     ) => {{
674         let lhs = $lhs.load_value($fx);
675         let rhs = $rhs.load_value($fx);
676         match ($bin_op, $signed) {
677             $(
678                 (BinOp::$var, $sign) => binop_match!(@single $fx, $bug_fmt, $var, $signed, lhs, rhs, $ret_ty, $name $( ( $($next)* ) )?),
679             )*
680         }
681     }}
682 }
683
684 fn trans_bool_binop<'a, 'tcx: 'a>(
685     fx: &mut FunctionCx<'a, 'tcx, impl Backend>,
686     bin_op: BinOp,
687     lhs: CValue<'tcx>,
688     rhs: CValue<'tcx>,
689     ty: Ty<'tcx>,
690 ) -> CValue<'tcx> {
691     let res = binop_match! {
692         fx, bin_op, false, lhs, rhs, ty, "bool";
693         Add (_) bug;
694         Sub (_) bug;
695         Mul (_) bug;
696         Div (_) bug;
697         Rem (_) bug;
698         BitXor (_) bxor;
699         BitAnd (_) band;
700         BitOr (_) bor;
701         Shl (_) bug;
702         Shr (_) bug;
703
704         Eq (_) icmp(Equal);
705         Lt (_) icmp(UnsignedLessThan);
706         Le (_) icmp(UnsignedLessThanOrEqual);
707         Ne (_) icmp(NotEqual);
708         Ge (_) icmp(UnsignedGreaterThanOrEqual);
709         Gt (_) icmp(UnsignedGreaterThan);
710
711         Offset (_) bug;
712     };
713
714     res
715 }
716
717 pub fn trans_int_binop<'a, 'tcx: 'a>(
718     fx: &mut FunctionCx<'a, 'tcx, impl Backend>,
719     bin_op: BinOp,
720     lhs: CValue<'tcx>,
721     rhs: CValue<'tcx>,
722     out_ty: Ty<'tcx>,
723     signed: bool,
724 ) -> CValue<'tcx> {
725     if bin_op != BinOp::Shl && bin_op != BinOp::Shr {
726         assert_eq!(
727             lhs.layout().ty,
728             rhs.layout().ty,
729             "int binop requires lhs and rhs of same type"
730         );
731     }
732     binop_match! {
733         fx, bin_op, signed, lhs, rhs, out_ty, "int/uint";
734         Add (_) iadd;
735         Sub (_) isub;
736         Mul (_) imul;
737         Div (false) udiv;
738         Div (true) sdiv;
739         Rem (false) urem;
740         Rem (true) srem;
741         BitXor (_) bxor;
742         BitAnd (_) band;
743         BitOr (_) bor;
744         Shl (_) ishl;
745         Shr (false) ushr;
746         Shr (true) sshr;
747
748         Eq (_) icmp(Equal);
749         Lt (false) icmp(UnsignedLessThan);
750         Lt (true) icmp(SignedLessThan);
751         Le (false) icmp(UnsignedLessThanOrEqual);
752         Le (true) icmp(SignedLessThanOrEqual);
753         Ne (_) icmp(NotEqual);
754         Ge (false) icmp(UnsignedGreaterThanOrEqual);
755         Ge (true) icmp(SignedGreaterThanOrEqual);
756         Gt (false) icmp(UnsignedGreaterThan);
757         Gt (true) icmp(SignedGreaterThan);
758
759         Offset (_) bug;
760     }
761 }
762
763 pub fn trans_checked_int_binop<'a, 'tcx: 'a>(
764     fx: &mut FunctionCx<'a, 'tcx, impl Backend>,
765     bin_op: BinOp,
766     in_lhs: CValue<'tcx>,
767     in_rhs: CValue<'tcx>,
768     out_ty: Ty<'tcx>,
769     signed: bool,
770 ) -> CValue<'tcx> {
771     if bin_op != BinOp::Shl && bin_op != BinOp::Shr {
772         assert_eq!(
773             in_lhs.layout().ty,
774             in_rhs.layout().ty,
775             "checked int binop requires lhs and rhs of same type"
776         );
777     }
778     let res_ty = match out_ty.sty {
779         ty::Tuple(tys) => tys[0],
780         _ => bug!(
781             "Checked int binop requires tuple as output, but got {:?}",
782             out_ty
783         ),
784     };
785
786     let lhs = in_lhs.load_value(fx);
787     let rhs = in_rhs.load_value(fx);
788     let res = match bin_op {
789         BinOp::Add => fx.bcx.ins().iadd(lhs, rhs),
790         BinOp::Sub => fx.bcx.ins().isub(lhs, rhs),
791         BinOp::Mul => fx.bcx.ins().imul(lhs, rhs),
792         BinOp::Shl => fx.bcx.ins().ishl(lhs, rhs),
793         BinOp::Shr => if !signed {
794             fx.bcx.ins().ushr(lhs, rhs)
795         } else {
796             fx.bcx.ins().sshr(lhs, rhs)
797         },
798         _ => bug!(
799             "binop {:?} on checked int/uint lhs: {:?} rhs: {:?}",
800             bin_op,
801             in_lhs,
802             in_rhs
803         ),
804     };
805
806     // TODO: check for overflow
807     let has_overflow = fx.bcx.ins().iconst(types::I8, 0);
808
809     let out_place = CPlace::temp(fx, out_ty);
810     let out_layout = out_place.layout();
811     out_place.write_cvalue(fx, CValue::ByValPair(res, has_overflow, out_layout));
812
813     out_place.to_cvalue(fx)
814 }
815
816 fn trans_float_binop<'a, 'tcx: 'a>(
817     fx: &mut FunctionCx<'a, 'tcx, impl Backend>,
818     bin_op: BinOp,
819     lhs: CValue<'tcx>,
820     rhs: CValue<'tcx>,
821     ty: Ty<'tcx>,
822 ) -> CValue<'tcx> {
823     let res = binop_match! {
824         fx, bin_op, false, lhs, rhs, ty, "float";
825         Add (_) fadd;
826         Sub (_) fsub;
827         Mul (_) fmul;
828         Div (_) fdiv;
829         Rem (_) custom(|| {
830             assert_eq!(lhs.layout().ty, ty);
831             assert_eq!(rhs.layout().ty, ty);
832             match ty.sty {
833                 ty::Float(FloatTy::F32) => fx.easy_call("fmodf", &[lhs, rhs], ty),
834                 ty::Float(FloatTy::F64) => fx.easy_call("fmod", &[lhs, rhs], ty),
835                 _ => bug!(),
836             }
837         });
838         BitXor (_) bxor;
839         BitAnd (_) band;
840         BitOr (_) bor;
841         Shl (_) bug;
842         Shr (_) bug;
843
844         Eq (_) fcmp(Equal);
845         Lt (_) fcmp(LessThan);
846         Le (_) fcmp(LessThanOrEqual);
847         Ne (_) fcmp(NotEqual);
848         Ge (_) fcmp(GreaterThanOrEqual);
849         Gt (_) fcmp(GreaterThan);
850
851         Offset (_) bug;
852     };
853
854     res
855 }
856
857 fn trans_char_binop<'a, 'tcx: 'a>(
858     fx: &mut FunctionCx<'a, 'tcx, impl Backend>,
859     bin_op: BinOp,
860     lhs: CValue<'tcx>,
861     rhs: CValue<'tcx>,
862     ty: Ty<'tcx>,
863 ) -> CValue<'tcx> {
864     let res = binop_match! {
865         fx, bin_op, false, lhs, rhs, ty, "char";
866         Add (_) bug;
867         Sub (_) bug;
868         Mul (_) bug;
869         Div (_) bug;
870         Rem (_) bug;
871         BitXor (_) bug;
872         BitAnd (_) bug;
873         BitOr (_) bug;
874         Shl (_) bug;
875         Shr (_) bug;
876
877         Eq (_) icmp(Equal);
878         Lt (_) icmp(UnsignedLessThan);
879         Le (_) icmp(UnsignedLessThanOrEqual);
880         Ne (_) icmp(NotEqual);
881         Ge (_) icmp(UnsignedGreaterThanOrEqual);
882         Gt (_) icmp(UnsignedGreaterThan);
883
884         Offset (_) bug;
885     };
886
887     res
888 }
889
890 fn trans_ptr_binop<'a, 'tcx: 'a>(
891     fx: &mut FunctionCx<'a, 'tcx, impl Backend>,
892     bin_op: BinOp,
893     lhs: CValue<'tcx>,
894     rhs: CValue<'tcx>,
895     ty: Ty<'tcx>,
896 ) -> CValue<'tcx> {
897     match lhs.layout().ty.sty {
898         ty::RawPtr(TypeAndMut { ty, mutbl: _ }) => {
899             if !ty.is_sized(fx.tcx.at(DUMMY_SP), ParamEnv::reveal_all()) {
900                 unimpl!("Unsized values are not yet implemented");
901             }
902         }
903         _ => bug!("trans_ptr_binop on non ptr"),
904     }
905     binop_match! {
906         fx, bin_op, false, lhs, rhs, ty, "ptr";
907         Add (_) bug;
908         Sub (_) bug;
909         Mul (_) bug;
910         Div (_) bug;
911         Rem (_) bug;
912         BitXor (_) bug;
913         BitAnd (_) bug;
914         BitOr (_) bug;
915         Shl (_) bug;
916         Shr (_) bug;
917
918         Eq (_) icmp(Equal);
919         Lt (_) icmp(UnsignedLessThan);
920         Le (_) icmp(UnsignedLessThanOrEqual);
921         Ne (_) icmp(NotEqual);
922         Ge (_) icmp(UnsignedGreaterThanOrEqual);
923         Gt (_) icmp(UnsignedGreaterThan);
924
925         Offset (_) iadd;
926     }
927 }
928
929 pub fn trans_place<'a, 'tcx: 'a>(
930     fx: &mut FunctionCx<'a, 'tcx, impl Backend>,
931     place: &Place<'tcx>,
932 ) -> CPlace<'tcx> {
933     match place {
934         Place::Local(local) => fx.get_local_place(*local),
935         Place::Promoted(promoted) => crate::constant::trans_promoted(fx, promoted.0),
936         Place::Static(static_) => crate::constant::codegen_static_ref(fx, static_),
937         Place::Projection(projection) => {
938             let base = trans_place(fx, &projection.base);
939             match projection.elem {
940                 ProjectionElem::Deref => base.place_deref(fx),
941                 ProjectionElem::Field(field, _ty) => base.place_field(fx, field),
942                 ProjectionElem::Index(local) => {
943                     let index = fx.get_local_place(local).to_cvalue(fx).load_value(fx);
944                     base.place_index(fx, index)
945                 }
946                 ProjectionElem::ConstantIndex {
947                     offset,
948                     min_length: _,
949                     from_end: false,
950                 } => unimplemented!(
951                     "projection const index {:?} offset {:?} not from end",
952                     projection.base,
953                     offset
954                 ),
955                 ProjectionElem::ConstantIndex {
956                     offset,
957                     min_length: _,
958                     from_end: true,
959                 } => unimplemented!(
960                     "projection const index {:?} offset {:?} from end",
961                     projection.base,
962                     offset
963                 ),
964                 ProjectionElem::Subslice { from, to } => unimplemented!(
965                     "projection subslice {:?} from {} to {}",
966                     projection.base,
967                     from,
968                     to
969                 ),
970                 ProjectionElem::Downcast(_adt_def, variant) => base.downcast_variant(fx, variant),
971             }
972         }
973     }
974 }
975
976 pub fn trans_operand<'a, 'tcx>(
977     fx: &mut FunctionCx<'a, 'tcx, impl Backend>,
978     operand: &Operand<'tcx>,
979 ) -> CValue<'tcx> {
980     match operand {
981         Operand::Move(place) | Operand::Copy(place) => {
982             let cplace = trans_place(fx, place);
983             cplace.to_cvalue(fx)
984         }
985         Operand::Constant(const_) => crate::constant::trans_constant(fx, const_),
986     }
987 }