From 3e98220a1cc9059807961472a9132157cdf3c047 Mon Sep 17 00:00:00 2001 From: Eduard Burtescu Date: Tue, 8 Mar 2016 14:40:37 +0200 Subject: [PATCH] mir: Translate intrinsics, via old trans where possible. --- src/librustc_trans/trans/callee.rs | 16 +---- src/librustc_trans/trans/intrinsic.rs | 30 +++++---- src/librustc_trans/trans/mir/block.rs | 91 +++++++++++++++++++++++++-- 3 files changed, 106 insertions(+), 31 deletions(-) diff --git a/src/librustc_trans/trans/callee.rs b/src/librustc_trans/trans/callee.rs index bef96cb2b45..17d08cd6c2f 100644 --- a/src/librustc_trans/trans/callee.rs +++ b/src/librustc_trans/trans/callee.rs @@ -36,7 +36,7 @@ use trans::cleanup; use trans::cleanup::CleanupMethods; use trans::closure; -use trans::common::{self, Block, Result, NodeIdAndSpan, CrateContext, FunctionContext}; +use trans::common::{self, Block, Result, CrateContext, FunctionContext}; use trans::common::{C_uint, C_undef}; use trans::consts; use trans::datum::*; @@ -56,7 +56,6 @@ use middle::ty::{self, Ty, TyCtxt, TypeFoldable}; use rustc_front::hir; -use syntax::ast; use syntax::codemap::DUMMY_SP; use syntax::errors; use syntax::ptr::P; @@ -624,18 +623,9 @@ fn trans_call_inner<'a, 'blk, 'tcx>(mut bcx: Block<'blk, 'tcx>, assert!(abi == Abi::RustIntrinsic || abi == Abi::PlatformIntrinsic); assert!(dest.is_some()); - let call_info = match debug_loc { - DebugLoc::At(id, span) => NodeIdAndSpan { id: id, span: span }, - DebugLoc::None => { - bcx.sess().bug("No call info for intrinsic call?") - } - }; - - let arg_cleanup_scope = fcx.push_custom_cleanup_scope(); return intrinsic::trans_intrinsic_call(bcx, callee.ty, &fn_ty, - arg_cleanup_scope, args, - dest.unwrap(), - call_info); + args, dest.unwrap(), + debug_loc); } NamedTupleConstructor(disr) => { assert!(dest.is_some()); diff --git a/src/librustc_trans/trans/intrinsic.rs b/src/librustc_trans/trans/intrinsic.rs index 7673c98af2a..b99cb2b6331 100644 --- a/src/librustc_trans/trans/intrinsic.rs +++ b/src/librustc_trans/trans/intrinsic.rs @@ -47,7 +47,7 @@ use rustc::lint; use rustc::session::Session; -use syntax::codemap::Span; +use syntax::codemap::{Span, DUMMY_SP}; use std::cmp::Ordering; @@ -173,10 +173,9 @@ pub fn check_intrinsics(ccx: &CrateContext) { pub fn trans_intrinsic_call<'a, 'blk, 'tcx>(mut bcx: Block<'blk, 'tcx>, callee_ty: Ty<'tcx>, fn_ty: &FnType, - cleanup_scope: cleanup::CustomScopeIndex, args: callee::CallArgs<'a, 'tcx>, dest: expr::Dest, - call_info: NodeIdAndSpan) + call_debug_location: DebugLoc) -> Result<'blk, 'tcx> { let fcx = bcx.fcx; let ccx = fcx.ccx; @@ -195,7 +194,12 @@ pub fn trans_intrinsic_call<'a, 'blk, 'tcx>(mut bcx: Block<'blk, 'tcx>, let ret_ty = sig.output; let name = tcx.item_name(def_id).as_str(); - let call_debug_location = DebugLoc::At(call_info.id, call_info.span); + let span = match call_debug_location { + DebugLoc::At(_, span) => span, + DebugLoc::None => fcx.span.unwrap_or(DUMMY_SP) + }; + + let cleanup_scope = fcx.push_custom_cleanup_scope(); // For `transmute` we can just trans the input expr directly into dest if name == "transmute" { @@ -644,7 +648,7 @@ pub fn trans_intrinsic_call<'a, 'blk, 'tcx>(mut bcx: Block<'blk, 'tcx>, }, None => { span_invalid_monomorphization_error( - tcx.sess, call_info.span, + tcx.sess, span, &format!("invalid monomorphization of `{}` intrinsic: \ expected basic integer type, found `{}`", name, sty)); C_null(llret_ty) @@ -656,7 +660,7 @@ pub fn trans_intrinsic_call<'a, 'blk, 'tcx>(mut bcx: Block<'blk, 'tcx>, (_, "return_address") => { if !fcx.fn_ty.ret.is_indirect() { - span_err!(tcx.sess, call_info.span, E0510, + span_err!(tcx.sess, span, E0510, "invalid use of `return_address` intrinsic: function \ does not use out pointer"); C_null(Type::i8p(ccx)) @@ -684,7 +688,7 @@ pub fn trans_intrinsic_call<'a, 'blk, 'tcx>(mut bcx: Block<'blk, 'tcx>, &llargs, ret_ty, llret_ty, call_debug_location, - call_info) + span) } // This requires that atomic intrinsics follow a specific naming pattern: // "atomic_[_]", and no ordering means SeqCst @@ -1404,7 +1408,7 @@ fn generic_simd_intrinsic<'blk, 'tcx, 'a> ret_ty: Ty<'tcx>, llret_ty: Type, call_debug_location: DebugLoc, - call_info: NodeIdAndSpan) -> ValueRef + span: Span) -> ValueRef { // macros for error handling: macro_rules! emit_error { @@ -1413,7 +1417,7 @@ fn generic_simd_intrinsic<'blk, 'tcx, 'a> }; ($msg: tt, $($fmt: tt)*) => { span_invalid_monomorphization_error( - bcx.sess(), call_info.span, + bcx.sess(), span, &format!(concat!("invalid monomorphization of `{}` intrinsic: ", $msg), name, $($fmt)*)); @@ -1482,7 +1486,7 @@ fn generic_simd_intrinsic<'blk, 'tcx, 'a> if name.starts_with("simd_shuffle") { let n: usize = match name["simd_shuffle".len()..].parse() { Ok(n) => n, - Err(_) => tcx.sess.span_bug(call_info.span, + Err(_) => tcx.sess.span_bug(span, "bad `simd_shuffle` instruction only caught in trans?") }; @@ -1502,14 +1506,14 @@ fn generic_simd_intrinsic<'blk, 'tcx, 'a> let vector = match args { Some(args) => &args[2], - None => bcx.sess().span_bug(call_info.span, + None => bcx.sess().span_bug(span, "intrinsic call with unexpected argument shape"), }; let vector = match consts::const_expr(bcx.ccx(), vector, substs, None, consts::TrueConst::Yes, // this should probably help simd error reporting ) { Ok((vector, _)) => vector, - Err(err) => bcx.sess().span_fatal(call_info.span, &err.description()), + Err(err) => bcx.sess().span_fatal(span, &err.description()), }; let indices: Option> = (0..n) @@ -1652,7 +1656,7 @@ enum Style { Float, Int(/* is signed? */ bool), Unsupported } simd_or: TyUint, TyInt => Or; simd_xor: TyUint, TyInt => Xor; } - bcx.sess().span_bug(call_info.span, "unknown SIMD intrinsic"); + bcx.sess().span_bug(span, "unknown SIMD intrinsic"); } // Returns the width of an int TypeVariant, and if it's signed or not diff --git a/src/librustc_trans/trans/mir/block.rs b/src/librustc_trans/trans/mir/block.rs index ac57cd843aa..547382daab3 100644 --- a/src/librustc_trans/trans/mir/block.rs +++ b/src/librustc_trans/trans/mir/block.rs @@ -15,11 +15,11 @@ use trans::adt; use trans::base; use trans::build; -use trans::callee::{Callee, CalleeData, Fn, Virtual}; +use trans::callee::{Callee, CalleeData, Fn, Intrinsic, NamedTupleConstructor, Virtual}; use trans::common::{self, Block, BlockAndBuilder, C_undef}; use trans::debuginfo::DebugLoc; use trans::Disr; -use trans::machine::llalign_of_min; +use trans::machine::{llalign_of_min, llbitsize_of_real}; use trans::meth; use trans::type_of; use trans::glue; @@ -27,6 +27,7 @@ use super::{MirContext, drop}; use super::lvalue::LvalueRef; +use super::operand::OperandRef; use super::operand::OperandValue::{self, FatPtr, Immediate, Ref}; impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> { @@ -168,8 +169,51 @@ pub fn trans_block(&mut self, bb: mir::BasicBlock) { _ => unreachable!("{} is not callable", callee.ty) }; - // We do not translate intrinsics here (they shouldn’t be functions) - assert!(abi != Abi::RustIntrinsic && abi != Abi::PlatformIntrinsic); + // Handle intrinsics old trans wants Expr's for, ourselves. + let intrinsic = match (&callee.ty.sty, &callee.data) { + (&ty::TyFnDef(def_id, _, _), &Intrinsic) => { + Some(bcx.tcx().item_name(def_id).as_str()) + } + _ => None + }; + let intrinsic = intrinsic.as_ref().map(|s| &s[..]); + + if intrinsic == Some("move_val_init") { + let &(_, target) = destination.as_ref().unwrap(); + // The first argument is a thin destination pointer. + let llptr = self.trans_operand(&bcx, &args[0]).immediate(); + let val = self.trans_operand(&bcx, &args[1]); + self.store_operand(&bcx, llptr, val); + self.set_operand_dropped(&bcx, &args[1]); + funclet_br(bcx, self.llblock(target)); + return; + } + + if intrinsic == Some("transmute") { + let &(ref dest, target) = destination.as_ref().unwrap(); + let dst = self.trans_lvalue(&bcx, dest); + let mut val = self.trans_operand(&bcx, &args[0]); + if let ty::TyFnDef(def_id, substs, _) = val.ty.sty { + let llouttype = type_of::type_of(bcx.ccx(), dst.ty.to_ty(bcx.tcx())); + let out_type_size = llbitsize_of_real(bcx.ccx(), llouttype); + if out_type_size != 0 { + // FIXME #19925 Remove this hack after a release cycle. + let f = Callee::def(bcx.ccx(), def_id, substs); + let datum = f.reify(bcx.ccx()); + val = OperandRef { + val: OperandValue::Immediate(datum.val), + ty: datum.ty + }; + } + } + + let llty = type_of::type_of(bcx.ccx(), val.ty); + let cast_ptr = bcx.pointercast(dst.llval, llty.ptr_to()); + self.store_operand(&bcx, cast_ptr, val); + self.set_operand_dropped(&bcx, &args[0]); + funclet_br(bcx, self.llblock(target)); + return; + } let extra_args = &args[sig.0.inputs.len()..]; let extra_args = extra_args.iter().map(|op_arg| { @@ -215,7 +259,44 @@ pub fn trans_block(&mut self, bb: mir::BasicBlock) { &mut idx, &mut callee.data) } - let fn_ptr = callee.reify(bcx.ccx()).val; + let fn_ptr = match callee.data { + NamedTupleConstructor(_) => { + // FIXME translate this like mir::Rvalue::Aggregate. + callee.reify(bcx.ccx()).val + } + Intrinsic => { + use trans::callee::ArgVals; + use trans::expr::{Ignore, SaveIn}; + use trans::intrinsic::trans_intrinsic_call; + + let (dest, llargs) = if fn_ty.ret.is_indirect() { + (SaveIn(llargs[0]), &llargs[1..]) + } else if let Some(dest) = ret_dest { + (SaveIn(dest.llval), &llargs[..]) + } else { + (Ignore, &llargs[..]) + }; + + bcx.with_block(|bcx| { + let res = trans_intrinsic_call(bcx, callee.ty, &fn_ty, + ArgVals(llargs), dest, + DebugLoc::None); + let bcx = res.bcx.build(); + if let Some((_, target)) = *destination { + for op in args { + self.set_operand_dropped(&bcx, op); + } + funclet_br(bcx, self.llblock(target)); + } else { + // trans_intrinsic_call already used Unreachable. + // bcx.unreachable(); + } + }); + return; + } + Fn(f) => f, + Virtual(_) => unreachable!("Virtual fn ptr not extracted") + }; // Many different ways to call a function handled here if let Some(cleanup) = cleanup.map(|bb| self.bcx(bb)) { -- GitLab