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