diff --git a/example.rs b/example.rs index 484b97b6c18..b8264709719 100644 --- a/example.rs +++ b/example.rs @@ -46,3 +46,8 @@ fn abc(a: u8) -> u8 { fn call() { abc(42); } + +fn indirect_call() { + let f: fn() = call; + f(); +} diff --git a/src/base.rs b/src/base.rs index 03f900318cb..e68af8f43b4 100644 --- a/src/base.rs +++ b/src/base.rs @@ -141,7 +141,7 @@ impl<'f, 'tcx> CodegenCtxt<'f, 'tcx> { } } -fn trans_fn<'a, 'tcx: 'a>(tcx: TyCtxt<'a, 'tcx, 'tcx>, f: &mut Function, def_id: DefId, substs: &Substs) { +fn trans_fn<'a, 'tcx: 'a>(tcx: TyCtxt<'a, 'tcx, 'tcx>, f: &mut Function, def_id: DefId, substs: &Substs<'tcx>) { let mir = tcx.optimized_mir(def_id); let mut func_ctx = FunctionBuilderContext::new(); let mut bcx: FunctionBuilder = FunctionBuilder::new(f, &mut func_ctx); @@ -198,7 +198,7 @@ fn trans_fn<'a, 'tcx: 'a>(tcx: TyCtxt<'a, 'tcx, 'tcx>, f: &mut Function, def_id: TerminatorKind::Return => { ccx.bcx.ins().return_(&[]); } - TerminatorKind::Assert { cond, expected, msg, target, cleanup: _ } => { + TerminatorKind::Assert { cond, expected, msg: _, target, cleanup: _ } => { let cond_ty = cond.ty(&ccx.mir.local_decls, ccx.tcx); let cond = trans_operand(ccx, cond).load_value(ccx, cond_ty); let target = ccx.get_ebb(*target); @@ -224,6 +224,7 @@ fn trans_fn<'a, 'tcx: 'a>(tcx: TyCtxt<'a, 'tcx, 'tcx>, f: &mut Function, def_id: ccx.bcx.ins().jump(otherwise_ebb, &[]); } TerminatorKind::Call { func, args, destination, cleanup: _ } => { + let func_ty = func.ty(&ccx.mir.local_decls, ccx.tcx); let func = trans_operand(ccx, func); let return_place = if let Some((place, _)) = destination { trans_place(ccx, place) @@ -245,7 +246,17 @@ fn trans_fn<'a, 'tcx: 'a>(tcx: TyCtxt<'a, 'tcx, 'tcx>, f: &mut Function, def_id: CValue::Func(func) => { ccx.bcx.ins().call(func, &args); } - _ => unimplemented!("indirect call"), + func => { + let func = func.load_value(ccx, func_ty); + let sig = match func_ty.sty { + TypeVariants::TyFnDef(def_id, _substs) => ccx.tcx.fn_sig(def_id), + TypeVariants::TyFnPtr(fn_sig) => fn_sig, + _ => bug!("Calling non function type {:?}", func_ty), + }; + let sig = ccx.tcx.subst_and_normalize_erasing_regions(substs, ParamEnv::reveal_all(), &sig); + let sig = ccx.bcx.import_signature(cton_sig_from_fn_sig(sig.skip_binder())); + ccx.bcx.ins().call_indirect(sig, func, &args); + } } if let Some((_, dest)) = *destination { let ret_ebb = ccx.get_ebb(dest); @@ -257,7 +268,14 @@ fn trans_fn<'a, 'tcx: 'a>(tcx: TyCtxt<'a, 'tcx, 'tcx>, f: &mut Function, def_id: TerminatorKind::Resume | TerminatorKind::Abort | TerminatorKind::Unreachable => { ccx.bcx.ins().trap(TrapCode::User(!0)); } - terminator => unimplemented!("terminator {:?}", terminator), + TerminatorKind::Yield { .. } | + TerminatorKind::FalseEdges { .. } | + TerminatorKind::FalseUnwind { .. } => { + bug!("shouldn't exist at trans {:?}", bb_data.terminator()); + } + TerminatorKind::Drop { .. } | TerminatorKind::DropAndReplace { .. } | TerminatorKind::GeneratorDrop { .. } => { + unimplemented!("terminator {:?}", bb_data.terminator()); + } } } @@ -321,13 +339,21 @@ fn trans_rval<'a, 'tcx: 'a>(ccx: &mut CodegenCtxt<'a, 'tcx>, rval: &Rvalue<'tcx> bin_op => unimplemented!("checked bin op {:?} {:?} {:?}", bin_op, lhs, rhs), } } - rval => unimplemented!("{:?}", rval), + Rvalue::Cast(CastKind::ReifyFnPointer, operand, ty) => { + let operand = trans_operand(ccx, operand); + operand.force_stack(ccx, ty) + } + Rvalue::Cast(CastKind::UnsafeFnPointer, operand, ty) => { + trans_operand(ccx, operand).force_stack(ccx, ty) + } + rval => unimplemented!("rval {:?}", rval), } } fn trans_operand<'a, 'tcx>(ccx: &mut CodegenCtxt<'a, 'tcx>, operand: &Operand<'tcx>) -> CValue { match operand { - Operand::Move(place) => CValue::ByRef(trans_place(ccx, place)), + Operand::Move(place) | + Operand::Copy(place) => CValue::ByRef(trans_place(ccx, place)), Operand::Constant(const_) => { match const_.literal { Literal::Value { value } => { @@ -366,9 +392,21 @@ fn trans_operand<'a, 'tcx>(ccx: &mut CodegenCtxt<'a, 'tcx>, operand: &Operand<'t fn do_memcpy<'a, 'tcx: 'a>(ccx: &mut CodegenCtxt<'a, 'tcx>, to: Value, from: Value, ty: Ty<'tcx>) { let layout = ccx.tcx.layout_of(ParamEnv::reveal_all().and(ty)).unwrap(); - for i in 0..(layout.size.bytes() as i32) { - let byte = ccx.bcx.ins().load_complex(types::I8, MemFlags::new(), &[from], i); - ccx.bcx.ins().store_complex(MemFlags::new(), byte, &[to], i); + let size = layout.size.bytes() as i32; + let ty = match size { + 2 => Some(types::I16), + 4 => Some(types::I32), + 8 => Some(types::I64), + _ => None, + }; + if let Some(ty) = ty { + let data = ccx.bcx.ins().load(ty, MemFlags::new(), from, 0); + ccx.bcx.ins().store(MemFlags::new(), data, to, 0); + } else { + for i in 0..size { + let byte = ccx.bcx.ins().load(types::I8, MemFlags::new(), from, i); + ccx.bcx.ins().store(MemFlags::new(), byte, to, i); + } } } @@ -416,6 +454,7 @@ fn cton_type_from_ty(ty: Ty) -> Option { IntTy::Isize => unimplemented!(), } } + TypeVariants::TyFnPtr(_) => types::I64, _ => return None, }) } diff --git a/src/lib.rs b/src/lib.rs index 5389c0b9ec9..31ec965c2a3 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,6 +1,7 @@ #![feature(rustc_private)] extern crate syntax; +#[macro_use] extern crate rustc; extern crate rustc_mir; extern crate rustc_codegen_utils; @@ -173,4 +174,4 @@ impl CodegenBackend for CretonneCodegenBackend { #[no_mangle] pub fn __rustc_codegen_backend() -> Box { CretonneCodegenBackend::new() -} \ No newline at end of file +}