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