]> git.lizzy.rs Git - rust.git/blob - src/base.rs
Rvalue::Len
[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     tcx: TyCtxt<'a, 'tcx, 'tcx>,
14     module: &mut Module<impl Backend>,
15     caches: &mut Caches,
16     ccx: &mut crate::constant::ConstantCx,
17     mono_item: MonoItem<'tcx>,
18 ) {
19     match mono_item {
20         MonoItem::Fn(inst) => {
21             let _print_guard = PrintOnPanic(format!("{:?}", inst));
22             let mir = match inst.def {
23                 InstanceDef::Item(_) | InstanceDef::DropGlue(_, _) | InstanceDef::Virtual(_, _) => {
24                     let mut mir = ::std::io::Cursor::new(Vec::new());
25                     ::rustc_mir::util::write_mir_pretty(tcx, Some(inst.def_id()), &mut mir)
26                         .unwrap();
27                     mir.into_inner()
28                 }
29                 InstanceDef::FnPtrShim(_, _)
30                 | InstanceDef::ClosureOnceShim { .. }
31                 | InstanceDef::CloneShim(_, _) => {
32                     // FIXME fix write_mir_pretty for these instances
33                     format!("{:#?}", tcx.instance_mir(inst.def)).into_bytes()
34                 }
35                 InstanceDef::Intrinsic(_) => bug!("tried to codegen intrinsic"),
36             };
37             let mir_file_name =
38                 "target/out/mir/".to_string() + &format!("{:?}", inst.def_id()).replace('/', "@");
39             ::std::fs::write(mir_file_name, mir).unwrap();
40
41             trans_fn(tcx, module, ccx, caches, inst);
42         }
43         MonoItem::Static(def_id) => {
44             crate::constant::codegen_static(ccx, def_id);
45         }
46         MonoItem::GlobalAsm(node_id) => tcx
47             .sess
48             .fatal(&format!("Unimplemented global asm mono item {:?}", node_id)),
49     }
50 }
51
52 fn trans_fn<'a, 'tcx: 'a>(
53     tcx: TyCtxt<'a, 'tcx, 'tcx>,
54     module: &mut Module<impl Backend>,
55     constants: &mut crate::constant::ConstantCx,
56     caches: &mut Caches,
57     instance: Instance<'tcx>,
58 ) {
59     // Step 1. Get mir
60     let mir = tcx.instance_mir(instance.def);
61
62     // Step 2. Declare function
63     let (name, sig) = get_function_name_and_sig(tcx, instance);
64     let func_id = module
65         .declare_function(&name, Linkage::Export, &sig)
66         .unwrap();
67
68     // Step 3. Make FunctionBuilder
69     let mut func = Function::with_name_signature(ExternalName::user(0, 0), sig);
70     let mut func_ctx = FunctionBuilderContext::new();
71     let mut bcx: FunctionBuilder = FunctionBuilder::new(&mut func, &mut func_ctx);
72
73     // Step 4. Predefine ebb's
74     let start_ebb = bcx.create_ebb();
75     let mut ebb_map: HashMap<BasicBlock, Ebb> = HashMap::new();
76     for (bb, _bb_data) in mir.basic_blocks().iter_enumerated() {
77         ebb_map.insert(bb, bcx.create_ebb());
78     }
79
80     // Step 5. Make FunctionCx
81     let mut fx = FunctionCx {
82         tcx,
83         module,
84         instance,
85         mir,
86         bcx,
87         param_substs: {
88             assert!(!instance.substs.needs_infer());
89             instance.substs
90         },
91         ebb_map,
92         local_map: HashMap::new(),
93         comments: HashMap::new(),
94         constants,
95         caches,
96
97         top_nop: None,
98     };
99
100     // Step 6. Codegen function
101     crate::abi::codegen_fn_prelude(&mut fx, start_ebb);
102     codegen_fn_content(&mut fx);
103     fx.bcx.seal_all_blocks();
104     fx.bcx.finalize();
105
106     // Step 7. Print function to terminal for debugging
107     let mut writer = crate::pretty_clif::CommentWriter(fx.comments);
108     let mut cton = String::new();
109     ::cranelift::codegen::write::decorate_function(&mut writer, &mut cton, &func, None).unwrap();
110     let clif_file_name = "target/out/clif/".to_string() + &tcx.symbol_name(instance).as_str();
111     ::std::fs::write(clif_file_name, cton.as_bytes()).unwrap();
112
113     // Step 8. Verify function
114     verify_func(tcx, writer, &func);
115
116     // Step 9. Define function
117     // TODO: cranelift doesn't yet support some of the things needed
118     if should_codegen(tcx.sess) {
119         caches.context.func = func;
120         module
121             .define_function(func_id, &mut caches.context)
122             .unwrap();
123         caches.context.clear();
124     }
125 }
126
127 fn verify_func(tcx: TyCtxt, writer: crate::pretty_clif::CommentWriter, func: &Function) {
128     let flags = settings::Flags::new(settings::builder());
129     match ::cranelift::codegen::verify_function(&func, &flags) {
130         Ok(_) => {}
131         Err(err) => {
132             tcx.sess.err(&format!("{:?}", err));
133             let pretty_error = ::cranelift::codegen::print_errors::pretty_verifier_error(
134                 &func,
135                 None,
136                 Some(Box::new(writer)),
137                 err,
138             );
139             tcx.sess
140                 .fatal(&format!("cretonne verify error:\n{}", pretty_error));
141         }
142     }
143 }
144
145 fn codegen_fn_content<'a, 'tcx: 'a>(fx: &mut FunctionCx<'a, 'tcx, impl Backend>) {
146     for (bb, bb_data) in fx.mir.basic_blocks().iter_enumerated() {
147         let ebb = fx.get_ebb(bb);
148         fx.bcx.switch_to_block(ebb);
149
150         fx.bcx.ins().nop();
151         for stmt in &bb_data.statements {
152             trans_stmt(fx, ebb, stmt);
153         }
154
155         let mut terminator_head = "\n".to_string();
156         bb_data
157             .terminator()
158             .kind
159             .fmt_head(&mut terminator_head)
160             .unwrap();
161         let inst = fx.bcx.func.layout.last_inst(ebb).unwrap();
162         fx.add_comment(inst, terminator_head);
163
164         match &bb_data.terminator().kind {
165             TerminatorKind::Goto { target } => {
166                 let ebb = fx.get_ebb(*target);
167                 fx.bcx.ins().jump(ebb, &[]);
168             }
169             TerminatorKind::Return => {
170                 crate::abi::codegen_return(fx);
171             }
172             TerminatorKind::Assert {
173                 cond,
174                 expected,
175                 msg: _,
176                 target,
177                 cleanup: _,
178             } => {
179                 let cond = trans_operand(fx, cond).load_value(fx);
180                 // TODO HACK brz/brnz for i8/i16 is not yet implemented
181                 let cond = fx.bcx.ins().uextend(types::I32, cond);
182                 let target = fx.get_ebb(*target);
183                 if *expected {
184                     fx.bcx.ins().brnz(cond, target, &[]);
185                 } else {
186                     fx.bcx.ins().brz(cond, target, &[]);
187                 };
188                 fx.bcx.ins().trap(TrapCode::User(!0));
189             }
190
191             TerminatorKind::SwitchInt {
192                 discr,
193                 switch_ty: _,
194                 values,
195                 targets,
196             } => {
197                 // TODO: prevent panics on large and negative disciminants
198                 if should_codegen(fx.tcx.sess) {
199                     let discr = trans_operand(fx, discr).load_value(fx);
200                     let mut jt_data = JumpTableData::new();
201                     for (i, value) in values.iter().enumerate() {
202                         let ebb = fx.get_ebb(targets[i]);
203                         jt_data.set_entry(*value as usize, ebb);
204                     }
205                     let jump_table = fx.bcx.create_jump_table(jt_data);
206                     fx.bcx.ins().br_table(discr, jump_table);
207                     let otherwise_ebb = fx.get_ebb(targets[targets.len() - 1]);
208                     fx.bcx.ins().jump(otherwise_ebb, &[]);
209                 } else {
210                     fx.bcx.ins().trap(TrapCode::User(0));
211                 }
212             }
213             TerminatorKind::Call {
214                 func,
215                 args,
216                 destination,
217                 cleanup: _,
218             } => {
219                 crate::abi::codegen_call(fx, func, args, destination);
220             }
221             TerminatorKind::Resume | TerminatorKind::Abort | TerminatorKind::Unreachable => {
222                 fx.bcx.ins().trap(TrapCode::User(!0));
223             }
224             TerminatorKind::Yield { .. }
225             | TerminatorKind::FalseEdges { .. }
226             | TerminatorKind::FalseUnwind { .. } => {
227                 bug!("shouldn't exist at trans {:?}", bb_data.terminator());
228             }
229             TerminatorKind::Drop { target, .. } | TerminatorKind::DropAndReplace { target, .. } => {
230                 // TODO call drop impl
231                 // unimplemented!("terminator {:?}", bb_data.terminator());
232                 let target_ebb = fx.get_ebb(*target);
233                 fx.bcx.ins().jump(target_ebb, &[]);
234             }
235             TerminatorKind::GeneratorDrop => {
236                 unimplemented!("terminator GeneratorDrop");
237             }
238         };
239     }
240
241     fx.bcx.seal_all_blocks();
242     fx.bcx.finalize();
243 }
244
245 fn trans_stmt<'a, 'tcx: 'a>(
246     fx: &mut FunctionCx<'a, 'tcx, impl Backend>,
247     cur_ebb: Ebb,
248     stmt: &Statement<'tcx>,
249 ) {
250     let _print_guard = PrintOnPanic(format!("stmt {:?}", stmt));
251
252     let inst = fx.bcx.func.layout.last_inst(cur_ebb).unwrap();
253     fx.add_comment(inst, format!("{:?}", stmt));
254
255     match &stmt.kind {
256         StatementKind::SetDiscriminant {
257             place,
258             variant_index,
259         } => {
260             let place = trans_place(fx, place);
261             let layout = place.layout();
262             if layout.for_variant(&*fx, *variant_index).abi == layout::Abi::Uninhabited {
263                 return;
264             }
265             match layout.variants {
266                 layout::Variants::Single { index } => {
267                     assert_eq!(index, *variant_index);
268                 }
269                 layout::Variants::Tagged { .. } => {
270                     let ptr = place.place_field(fx, mir::Field::new(0));
271                     let to = layout
272                         .ty
273                         .ty_adt_def()
274                         .unwrap()
275                         .discriminant_for_variant(fx.tcx, *variant_index)
276                         .val;
277                     let discr = CValue::const_val(fx, ptr.layout().ty, to as u64 as i64);
278                     ptr.write_cvalue(fx, discr);
279                 }
280                 layout::Variants::NicheFilling {
281                     dataful_variant,
282                     ref niche_variants,
283                     niche_start,
284                     ..
285                 } => {
286                     if *variant_index != dataful_variant {
287                         let niche = place.place_field(fx, mir::Field::new(0));
288                         //let niche_llty = niche.layout.immediate_llvm_type(bx.cx);
289                         let niche_value = ((variant_index - *niche_variants.start()) as u128)
290                             .wrapping_add(niche_start);
291                         // FIXME(eddyb) Check the actual primitive type here.
292                         let niche_llval = if niche_value == 0 {
293                             CValue::const_val(fx, niche.layout().ty, 0)
294                         } else {
295                             CValue::const_val(fx, niche.layout().ty, niche_value as u64 as i64)
296                         };
297                         niche.write_cvalue(fx, niche_llval);
298                     }
299                 }
300             }
301         }
302         StatementKind::Assign(to_place, rval) => {
303             let lval = trans_place(fx, to_place);
304             let dest_layout = lval.layout();
305             match rval {
306                 Rvalue::Use(operand) => {
307                     let val = trans_operand(fx, operand);
308                     lval.write_cvalue(fx, val);
309                 }
310                 Rvalue::Ref(_, _, place) => {
311                     let place = trans_place(fx, place);
312                     place.write_place_ref(fx, lval);
313                 }
314                 Rvalue::BinaryOp(bin_op, lhs, rhs) => {
315                     let ty = fx.monomorphize(&lhs.ty(&fx.mir.local_decls, fx.tcx));
316                     let lhs = trans_operand(fx, lhs);
317                     let rhs = trans_operand(fx, rhs);
318
319                     let res = match ty.sty {
320                         ty::Bool => trans_bool_binop(fx, *bin_op, lhs, rhs, lval.layout().ty),
321                         ty::Uint(_) => {
322                             trans_int_binop(fx, *bin_op, lhs, rhs, lval.layout().ty, false)
323                         }
324                         ty::Int(_) => {
325                             trans_int_binop(fx, *bin_op, lhs, rhs, lval.layout().ty, true)
326                         }
327                         ty::Float(_) => trans_float_binop(fx, *bin_op, lhs, rhs, lval.layout().ty),
328                         ty::Char => trans_char_binop(fx, *bin_op, lhs, rhs, lval.layout().ty),
329                         ty::RawPtr(..) => trans_ptr_binop(fx, *bin_op, lhs, rhs, lval.layout().ty),
330                         _ => unimplemented!("binop {:?} for {:?}", bin_op, ty),
331                     };
332                     lval.write_cvalue(fx, res);
333                 }
334                 Rvalue::CheckedBinaryOp(bin_op, lhs, rhs) => {
335                     let ty = fx.monomorphize(&lhs.ty(&fx.mir.local_decls, fx.tcx));
336                     let lhs = trans_operand(fx, lhs);
337                     let rhs = trans_operand(fx, rhs);
338
339                     let res = match ty.sty {
340                         ty::Uint(_) => {
341                             trans_checked_int_binop(fx, *bin_op, lhs, rhs, lval.layout().ty, false)
342                         }
343                         ty::Int(_) => {
344                             trans_checked_int_binop(fx, *bin_op, lhs, rhs, lval.layout().ty, true)
345                         }
346                         _ => unimplemented!("checked binop {:?} for {:?}", bin_op, ty),
347                     };
348                     lval.write_cvalue(fx, res);
349                 }
350                 Rvalue::UnaryOp(un_op, operand) => {
351                     let ty = fx.monomorphize(&operand.ty(&fx.mir.local_decls, fx.tcx));
352                     let layout = fx.layout_of(ty);
353                     let val = trans_operand(fx, operand).load_value(fx);
354                     let res = match un_op {
355                         UnOp::Not => fx.bcx.ins().bnot(val),
356                         UnOp::Neg => match ty.sty {
357                             ty::Int(_) => {
358                                 let clif_ty = fx.cton_type(ty).unwrap();
359                                 let zero = fx.bcx.ins().iconst(clif_ty, 0);
360                                 fx.bcx.ins().isub(zero, val)
361                             }
362                             ty::Float(_) => fx.bcx.ins().fneg(val),
363                             _ => unimplemented!("un op Neg for {:?}", ty),
364                         },
365                     };
366                     lval.write_cvalue(fx, CValue::ByVal(res, layout));
367                 }
368                 Rvalue::Cast(CastKind::ReifyFnPointer, operand, ty) => {
369                     let operand = trans_operand(fx, operand);
370                     let layout = fx.layout_of(ty);
371                     lval.write_cvalue(fx, operand.unchecked_cast_to(layout));
372                 }
373                 Rvalue::Cast(CastKind::UnsafeFnPointer, operand, ty) => {
374                     let operand = trans_operand(fx, operand);
375                     let layout = fx.layout_of(ty);
376                     lval.write_cvalue(fx, operand.unchecked_cast_to(layout));
377                 }
378                 Rvalue::Cast(CastKind::Misc, operand, to_ty) => {
379                     let operand = trans_operand(fx, operand);
380                     let from_ty = operand.layout().ty;
381                     match (&from_ty.sty, &to_ty.sty) {
382                         (ty::Ref(..), ty::Ref(..))
383                         | (ty::Ref(..), ty::RawPtr(..))
384                         | (ty::RawPtr(..), ty::Ref(..))
385                         | (ty::RawPtr(..), ty::RawPtr(..)) => {
386                             lval.write_cvalue(fx, operand.unchecked_cast_to(dest_layout));
387                         }
388                         (ty::RawPtr(..), ty::Uint(_)) | (ty::FnPtr(..), ty::Uint(_))
389                             if to_ty.sty == fx.tcx.types.usize.sty =>
390                         {
391                             lval.write_cvalue(fx, operand.unchecked_cast_to(dest_layout));
392                         }
393                         (ty::Uint(_), ty::RawPtr(..)) if from_ty.sty == fx.tcx.types.usize.sty => {
394                             lval.write_cvalue(fx, operand.unchecked_cast_to(dest_layout));
395                         }
396                         (ty::Char, ty::Uint(_))
397                         | (ty::Uint(_), ty::Char)
398                         | (ty::Uint(_), ty::Int(_))
399                         | (ty::Uint(_), ty::Uint(_)) => {
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                         (ty::Int(_), ty::Int(_)) | (ty::Int(_), ty::Uint(_)) => {
410                             let from = operand.load_value(fx);
411                             let res = crate::common::cton_intcast(
412                                 fx,
413                                 from,
414                                 fx.cton_type(to_ty).unwrap(),
415                                 true,
416                             );
417                             lval.write_cvalue(fx, CValue::ByVal(res, dest_layout));
418                         }
419                         (ty::Float(from_flt), ty::Float(to_flt)) => {
420                             let from = operand.load_value(fx);
421                             let res = match (from_flt, to_flt) {
422                                 (FloatTy::F32, FloatTy::F64) => {
423                                     fx.bcx.ins().fpromote(types::F64, from)
424                                 }
425                                 (FloatTy::F64, FloatTy::F32) => {
426                                     fx.bcx.ins().fdemote(types::F32, from)
427                                 }
428                                 _ => from,
429                             };
430                             lval.write_cvalue(fx, CValue::ByVal(res, dest_layout));
431                         }
432                         (ty::Int(_), ty::Float(_)) => {
433                             let from = operand.load_value(fx);
434                             let f_type = fx.cton_type(to_ty).unwrap();
435                             let res = fx.bcx.ins().fcvt_from_sint(f_type, from);
436                             lval.write_cvalue(fx, CValue::ByVal(res, dest_layout));
437                         }
438                         (ty::Uint(_), ty::Float(_)) => {
439                             let from = operand.load_value(fx);
440                             let f_type = fx.cton_type(to_ty).unwrap();
441                             let res = fx.bcx.ins().fcvt_from_uint(f_type, from);
442                             lval.write_cvalue(fx, CValue::ByVal(res, dest_layout));
443                         }
444                         (ty::Bool, ty::Uint(_)) | (ty::Bool, ty::Int(_)) => {
445                             let to_ty = fx.cton_type(to_ty).unwrap();
446                             let from = operand.load_value(fx);
447                             let res = if to_ty != types::I8 {
448                                 fx.bcx.ins().uextend(to_ty, from)
449                             } else {
450                                 from
451                             };
452                             lval.write_cvalue(fx, CValue::ByVal(res, dest_layout));
453                         }
454                         _ => unimpl!("rval misc {:?} {:?}", from_ty, to_ty),
455                     }
456                 }
457                 Rvalue::Cast(CastKind::ClosureFnPointer, operand, ty) => {
458                     unimplemented!("rval closure_fn_ptr {:?} {:?}", operand, ty)
459                 }
460                 Rvalue::Cast(CastKind::Unsize, operand, ty) => {
461                     let operand = trans_operand(fx, operand);
462                     operand.unsize_value(fx, lval);
463                 }
464                 Rvalue::Discriminant(place) => {
465                     let place = trans_place(fx, place).to_cvalue(fx);
466                     let discr = trans_get_discriminant(fx, place, dest_layout);
467                     lval.write_cvalue(fx, discr);
468                 }
469                 Rvalue::Repeat(operand, times) => {
470                     let operand = trans_operand(fx, operand);
471                     for i in 0..*times {
472                         let index = fx.bcx.ins().iconst(fx.module.pointer_type(), i as i64);
473                         let to = lval.place_index(fx, index);
474                         to.write_cvalue(fx, operand);
475                     }
476                 }
477                 Rvalue::Len(place) => {
478                     let place = trans_place(fx, place);
479                     let size = match place {
480                         CPlace::Addr(_, size, _) => size.unwrap(),
481                         CPlace::Var(_, _) => unreachable!(),
482                     };
483                     let usize_layout = fx.layout_of(fx.tcx.types.usize);
484                     lval.write_cvalue(fx, CValue::ByVal(size, usize_layout));
485                 }
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(fx.module.pointer_type(), 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     in_lhs: CValue<'tcx>,
731     in_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             in_lhs.layout().ty,
738             in_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         ty::Tuple(tys) => tys[0],
744         _ => bug!(
745             "Checked int binop requires tuple as output, but got {:?}",
746             out_ty
747         ),
748     };
749
750     let lhs = in_lhs.load_value(fx);
751     let rhs = in_rhs.load_value(fx);
752     let res = match bin_op {
753         BinOp::Add => fx.bcx.ins().iadd(lhs, rhs),
754         BinOp::Sub => fx.bcx.ins().isub(lhs, rhs),
755         BinOp::Mul => fx.bcx.ins().imul(lhs, rhs),
756         BinOp::Shl => fx.bcx.ins().ishl(lhs, rhs),
757         BinOp::Shr => if !signed {
758             fx.bcx.ins().ushr(lhs, rhs)
759         } else {
760             fx.bcx.ins().sshr(lhs, rhs)
761         },
762         _ => bug!(
763             "binop {:?} on checked int/uint lhs: {:?} rhs: {:?}",
764             bin_op,
765             in_lhs,
766             in_rhs
767         ),
768     };
769
770     // TODO: check for overflow
771     let has_overflow = fx.bcx.ins().iconst(types::I8, 0);
772
773     let out_place = CPlace::temp(fx, out_ty);
774     let out_layout = out_place.layout();
775     out_place.write_cvalue(fx, CValue::ByValPair(res, has_overflow, out_layout));
776
777     out_place.to_cvalue(fx)
778 }
779
780 fn trans_float_binop<'a, 'tcx: 'a>(
781     fx: &mut FunctionCx<'a, 'tcx, impl Backend>,
782     bin_op: BinOp,
783     lhs: CValue<'tcx>,
784     rhs: CValue<'tcx>,
785     ty: Ty<'tcx>,
786 ) -> CValue<'tcx> {
787     let res = binop_match! {
788         fx, bin_op, false, lhs, rhs, ty, "float";
789         Add (_) fadd;
790         Sub (_) fsub;
791         Mul (_) fmul;
792         Div (_) fdiv;
793         Rem (_) custom(|| {
794             assert_eq!(lhs.layout().ty, ty);
795             assert_eq!(rhs.layout().ty, ty);
796             match ty.sty {
797                 ty::Float(FloatTy::F32) => fx.easy_call("fmodf", &[lhs, rhs], ty),
798                 ty::Float(FloatTy::F64) => fx.easy_call("fmod", &[lhs, rhs], ty),
799                 _ => bug!(),
800             }
801         });
802         BitXor (_) bxor;
803         BitAnd (_) band;
804         BitOr (_) bor;
805         Shl (_) bug;
806         Shr (_) bug;
807
808         Eq (_) fcmp(Equal);
809         Lt (_) fcmp(LessThan);
810         Le (_) fcmp(LessThanOrEqual);
811         Ne (_) fcmp(NotEqual);
812         Ge (_) fcmp(GreaterThanOrEqual);
813         Gt (_) fcmp(GreaterThan);
814
815         Offset (_) bug;
816     };
817
818     res
819 }
820
821 fn trans_char_binop<'a, 'tcx: 'a>(
822     fx: &mut FunctionCx<'a, 'tcx, impl Backend>,
823     bin_op: BinOp,
824     lhs: CValue<'tcx>,
825     rhs: CValue<'tcx>,
826     ty: Ty<'tcx>,
827 ) -> CValue<'tcx> {
828     let res = binop_match! {
829         fx, bin_op, false, lhs, rhs, ty, "char";
830         Add (_) bug;
831         Sub (_) bug;
832         Mul (_) bug;
833         Div (_) bug;
834         Rem (_) bug;
835         BitXor (_) bug;
836         BitAnd (_) bug;
837         BitOr (_) bug;
838         Shl (_) bug;
839         Shr (_) bug;
840
841         Eq (_) icmp(Equal);
842         Lt (_) icmp(UnsignedLessThan);
843         Le (_) icmp(UnsignedLessThanOrEqual);
844         Ne (_) icmp(NotEqual);
845         Ge (_) icmp(UnsignedGreaterThanOrEqual);
846         Gt (_) icmp(UnsignedGreaterThan);
847
848         Offset (_) bug;
849     };
850
851     res
852 }
853
854 fn trans_ptr_binop<'a, 'tcx: 'a>(
855     fx: &mut FunctionCx<'a, 'tcx, impl Backend>,
856     bin_op: BinOp,
857     lhs: CValue<'tcx>,
858     rhs: CValue<'tcx>,
859     ty: Ty<'tcx>,
860 ) -> CValue<'tcx> {
861     match lhs.layout().ty.sty {
862         ty::RawPtr(TypeAndMut { ty, mutbl: _ }) => {
863             if !ty.is_sized(fx.tcx.at(DUMMY_SP), ParamEnv::reveal_all()) {
864                 unimpl!("Unsized values are not yet implemented");
865             }
866         }
867         _ => bug!("trans_ptr_binop on non ptr"),
868     }
869     binop_match! {
870         fx, bin_op, false, lhs, rhs, ty, "ptr";
871         Add (_) bug;
872         Sub (_) bug;
873         Mul (_) bug;
874         Div (_) bug;
875         Rem (_) bug;
876         BitXor (_) bug;
877         BitAnd (_) bug;
878         BitOr (_) bug;
879         Shl (_) bug;
880         Shr (_) bug;
881
882         Eq (_) icmp(Equal);
883         Lt (_) icmp(UnsignedLessThan);
884         Le (_) icmp(UnsignedLessThanOrEqual);
885         Ne (_) icmp(NotEqual);
886         Ge (_) icmp(UnsignedGreaterThanOrEqual);
887         Gt (_) icmp(UnsignedGreaterThan);
888
889         Offset (_) iadd;
890     }
891 }
892
893 pub fn trans_place<'a, 'tcx: 'a>(
894     fx: &mut FunctionCx<'a, 'tcx, impl Backend>,
895     place: &Place<'tcx>,
896 ) -> CPlace<'tcx> {
897     match place {
898         Place::Local(local) => fx.get_local_place(*local),
899         Place::Promoted(promoted) => crate::constant::trans_promoted(fx, promoted.0),
900         Place::Static(static_) => crate::constant::codegen_static_ref(fx, static_),
901         Place::Projection(projection) => {
902             let base = trans_place(fx, &projection.base);
903             match projection.elem {
904                 ProjectionElem::Deref => base.place_deref(fx),
905                 ProjectionElem::Field(field, _ty) => base.place_field(fx, field),
906                 ProjectionElem::Index(local) => {
907                     let index = fx.get_local_place(local).to_cvalue(fx).load_value(fx);
908                     base.place_index(fx, index)
909                 }
910                 ProjectionElem::ConstantIndex {
911                     offset,
912                     min_length: _,
913                     from_end: false,
914                 } => unimplemented!(
915                     "projection const index {:?} offset {:?} not from end",
916                     projection.base,
917                     offset
918                 ),
919                 ProjectionElem::ConstantIndex {
920                     offset,
921                     min_length: _,
922                     from_end: true,
923                 } => unimplemented!(
924                     "projection const index {:?} offset {:?} from end",
925                     projection.base,
926                     offset
927                 ),
928                 ProjectionElem::Subslice { from, to } => unimplemented!(
929                     "projection subslice {:?} from {} to {}",
930                     projection.base,
931                     from,
932                     to
933                 ),
934                 ProjectionElem::Downcast(_adt_def, variant) => base.downcast_variant(fx, variant),
935             }
936         }
937     }
938 }
939
940 pub fn trans_operand<'a, 'tcx>(
941     fx: &mut FunctionCx<'a, 'tcx, impl Backend>,
942     operand: &Operand<'tcx>,
943 ) -> CValue<'tcx> {
944     match operand {
945         Operand::Move(place) | Operand::Copy(place) => {
946             let cplace = trans_place(fx, place);
947             cplace.to_cvalue(fx)
948         }
949         Operand::Constant(const_) => crate::constant::trans_constant(fx, const_),
950     }
951 }