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