From f862da5bb8283bff99052c045fc470b8a45688c5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B6rn=20Steinbrink?= Date: Thu, 18 Jun 2015 14:23:19 +0200 Subject: [PATCH 1/4] Use a single match arm for all TyRef variants when deducing function argument attributes This makes it a lot easier to later add attributes for fat pointers. --- src/librustc_trans/trans/attributes.rs | 46 +++++++++++--------------- 1 file changed, 20 insertions(+), 26 deletions(-) diff --git a/src/librustc_trans/trans/attributes.rs b/src/librustc_trans/trans/attributes.rs index b0f44e6573957..8422c782b4f0d 100644 --- a/src/librustc_trans/trans/attributes.rs +++ b/src/librustc_trans/trans/attributes.rs @@ -262,41 +262,35 @@ pub fn from_fn_type<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, fn_type: ty::Ty<'tcx .arg(idx, llvm::DereferenceableAttribute(llsz)); } - // `&mut` pointer parameters never alias other parameters, or mutable global data - // - // `&T` where `T` contains no `UnsafeCell` is immutable, and can be marked as both - // `readonly` and `noalias`, as LLVM's definition of `noalias` is based solely on - // memory dependencies rather than pointer equality - ty::TyRef(b, mt) if mt.mutbl == ast::MutMutable || - !ty::type_contents(ccx.tcx(), mt.ty).interior_unsafe() => { - - let llsz = machine::llsize_of_real(ccx, type_of::type_of(ccx, mt.ty)); - attrs.arg(idx, llvm::Attribute::NoAlias) - .arg(idx, llvm::DereferenceableAttribute(llsz)); + ty::TyRef(b, mt) => { + // `&mut` pointer parameters never alias other parameters, or mutable global data + // + // `&T` where `T` contains no `UnsafeCell` is immutable, and can be marked as + // both `readonly` and `noalias`, as LLVM's definition of `noalias` is based solely + // on memory dependencies rather than pointer equality + let interior_unsafe = ty::type_contents(ccx.tcx(), mt.ty).interior_unsafe(); + + if mt.mutbl == ast::MutMutable || !interior_unsafe { + attrs.arg(idx, llvm::Attribute::NoAlias); + } - if mt.mutbl == ast::MutImmutable { + if mt.mutbl == ast::MutImmutable && !interior_unsafe { attrs.arg(idx, llvm::Attribute::ReadOnly); } + // & pointer parameters are also never null and we know exactly + // how many bytes we can dereference + let llsz = machine::llsize_of_real(ccx, type_of::type_of(ccx, mt.ty)); + attrs.arg(idx, llvm::DereferenceableAttribute(llsz)); + + // When a reference in an argument has no named lifetime, it's + // impossible for that reference to escape this function + // (returned or stored beyond the call by a closure). if let ReLateBound(_, BrAnon(_)) = *b { attrs.arg(idx, llvm::Attribute::NoCapture); } } - // When a reference in an argument has no named lifetime, it's impossible for that - // reference to escape this function (returned or stored beyond the call by a closure). - ty::TyRef(&ReLateBound(_, BrAnon(_)), mt) => { - let llsz = machine::llsize_of_real(ccx, type_of::type_of(ccx, mt.ty)); - attrs.arg(idx, llvm::Attribute::NoCapture) - .arg(idx, llvm::DereferenceableAttribute(llsz)); - } - - // & pointer parameters are also never null and we know exactly how - // many bytes we can dereference - ty::TyRef(_, mt) => { - let llsz = machine::llsize_of_real(ccx, type_of::type_of(ccx, mt.ty)); - attrs.arg(idx, llvm::DereferenceableAttribute(llsz)); - } _ => () } } From dea5a9608c5dd111b68cd03428f1d1f98fbec14b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B6rn=20Steinbrink?= Date: Thu, 18 Jun 2015 20:07:36 +0200 Subject: [PATCH 2/4] Simplify argument forwarding in the various shim generators --- src/librustc_llvm/lib.rs | 12 +++++++++ src/librustc_trans/trans/callee.rs | 18 +++++-------- src/librustc_trans/trans/closure.rs | 21 ++++------------ src/librustc_trans/trans/meth.rs | 39 ++++------------------------- 4 files changed, 28 insertions(+), 62 deletions(-) diff --git a/src/librustc_llvm/lib.rs b/src/librustc_llvm/lib.rs index 6d36e457b3d43..c4960c8d6a399 100644 --- a/src/librustc_llvm/lib.rs +++ b/src/librustc_llvm/lib.rs @@ -2252,6 +2252,18 @@ pub fn get_param(llfn: ValueRef, index: c_uint) -> ValueRef { } } +pub fn get_params(llfn: ValueRef) -> Vec { + unsafe { + let num_params = LLVMCountParams(llfn); + let mut params = Vec::with_capacity(num_params as usize); + for idx in 0..num_params { + params.push(LLVMGetParam(llfn, idx)); + } + + params + } +} + #[allow(missing_copy_implementations)] pub enum RustString_opaque {} pub type RustStringRef = *mut RustString_opaque; diff --git a/src/librustc_trans/trans/callee.rs b/src/librustc_trans/trans/callee.rs index 46f762a519585..10aea37f2e95e 100644 --- a/src/librustc_trans/trans/callee.rs +++ b/src/librustc_trans/trans/callee.rs @@ -21,9 +21,7 @@ pub use self::CallArgs::*; use arena::TypedArena; use back::link; use session; -use llvm::ValueRef; -use llvm::get_param; -use llvm; +use llvm::{self, ValueRef, get_params}; use metadata::csearch; use middle::def; use middle::subst; @@ -343,19 +341,15 @@ pub fn trans_fn_pointer_shim<'a, 'tcx>( &block_arena); let mut bcx = init_function(&fcx, false, sig.output); + let llargs = get_params(fcx.llfn); + // the first argument (`self`) will be ptr to the the fn pointer let llfnpointer = if is_by_ref { - Load(bcx, get_param(fcx.llfn, fcx.arg_pos(0) as u32)) + Load(bcx, llargs[fcx.arg_pos(0)]) } else { - get_param(fcx.llfn, fcx.arg_pos(0) as u32) + llargs[fcx.arg_pos(0)] }; - // the remaining arguments will be the untupled values - let llargs: Vec<_> = - sig.inputs.iter() - .enumerate() - .map(|(i, _)| get_param(fcx.llfn, fcx.arg_pos(i+1) as u32)) - .collect(); assert!(!fcx.needs_ret_allocas); let dest = fcx.llretslotptr.get().map(|_| @@ -366,7 +360,7 @@ pub fn trans_fn_pointer_shim<'a, 'tcx>( DebugLoc::None, bare_fn_ty, |bcx, _| Callee { bcx: bcx, data: Fn(llfnpointer) }, - ArgVals(&llargs[..]), + ArgVals(&llargs[fcx.arg_pos(1)..]), dest).bcx; finish_fn(&fcx, bcx, sig.output, DebugLoc::None); diff --git a/src/librustc_trans/trans/closure.rs b/src/librustc_trans/trans/closure.rs index 91b0a6c00696f..127fee222da01 100644 --- a/src/librustc_trans/trans/closure.rs +++ b/src/librustc_trans/trans/closure.rs @@ -10,7 +10,7 @@ use arena::TypedArena; use back::link::{self, mangle_internal_name_by_path_and_seq}; -use llvm::{ValueRef, get_param}; +use llvm::{ValueRef, get_params}; use middle::mem_categorization::Typer; use trans::adt; use trans::attributes; @@ -405,11 +405,13 @@ fn trans_fn_once_adapter_shim<'a, 'tcx>( &block_arena); let mut bcx = init_function(&fcx, false, sig.output); + let llargs = get_params(fcx.llfn); + // the first argument (`self`) will be the (by value) closure env. let self_scope = fcx.push_custom_cleanup_scope(); let self_scope_id = CustomScope(self_scope); let rvalue_mode = datum::appropriate_rvalue_mode(ccx, closure_ty); - let llself = get_param(lloncefn, fcx.arg_pos(0) as u32); + let llself = llargs[fcx.arg_pos(0)]; let env_datum = Datum::new(llself, closure_ty, Rvalue::new(rvalue_mode)); let env_datum = unpack_datum!(bcx, env_datum.to_lvalue_datum_in_scope(bcx, "self", @@ -418,19 +420,6 @@ fn trans_fn_once_adapter_shim<'a, 'tcx>( debug!("trans_fn_once_adapter_shim: env_datum={}", bcx.val_to_string(env_datum.val)); - // the remaining arguments will be packed up in a tuple. - let input_tys = match sig.inputs[1].sty { - ty::TyTuple(ref tys) => &**tys, - _ => bcx.sess().bug(&format!("trans_fn_once_adapter_shim: not rust-call! \ - closure_def_id={:?}", - closure_def_id)) - }; - let llargs: Vec<_> = - input_tys.iter() - .enumerate() - .map(|(i, _)| get_param(lloncefn, fcx.arg_pos(i+1) as u32)) - .collect(); - let dest = fcx.llretslotptr.get().map( |_| expr::SaveIn(fcx.get_ret_slot(bcx, sig.output, "ret_slot"))); @@ -442,7 +431,7 @@ fn trans_fn_once_adapter_shim<'a, 'tcx>( DebugLoc::None, llref_fn_ty, |bcx, _| Callee { bcx: bcx, data: callee_data }, - ArgVals(&llargs), + ArgVals(&llargs[fcx.arg_pos(1)..]), dest).bcx; fcx.pop_custom_cleanup_scope(self_scope); diff --git a/src/librustc_trans/trans/meth.rs b/src/librustc_trans/trans/meth.rs index eca6eecff4279..6955e03596fde 100644 --- a/src/librustc_trans/trans/meth.rs +++ b/src/librustc_trans/trans/meth.rs @@ -11,7 +11,7 @@ use arena::TypedArena; use back::abi; use back::link; -use llvm::{ValueRef, get_param}; +use llvm::{ValueRef, get_params}; use metadata::csearch; use middle::subst::{Subst, Substs}; use middle::subst::VecPerParamSpace; @@ -611,43 +611,14 @@ pub fn trans_object_shim<'a, 'tcx>( &block_arena); let mut bcx = init_function(&fcx, false, sig.output); + let llargs = get_params(fcx.llfn); + // the first argument (`self`) will be a trait object - let llobject = get_param(fcx.llfn, fcx.arg_pos(0) as u32); + let llobject = llargs[fcx.arg_pos(0)]; debug!("trans_object_shim: llobject={}", bcx.val_to_string(llobject)); - // the remaining arguments will be, well, whatever they are - let input_tys = - match fty.abi { - RustCall => { - // unpack the tuple to extract the input type arguments: - match sig.inputs[1].sty { - ty::TyTuple(ref tys) => &**tys, - _ => { - bcx.sess().bug( - &format!("rust-call expects a tuple not {:?}", - sig.inputs[1])); - } - } - } - _ => { - // skip the self parameter: - &sig.inputs[1..] - } - }; - - let llargs: Vec<_> = - input_tys.iter() - .enumerate() - .map(|(i, _)| { - let llarg = get_param(fcx.llfn, fcx.arg_pos(i+1) as u32); - debug!("trans_object_shim: input #{} == {}", - i, bcx.val_to_string(llarg)); - llarg - }) - .collect(); - assert!(!fcx.needs_ret_allocas); let dest = @@ -669,7 +640,7 @@ pub fn trans_object_shim<'a, 'tcx>( method_bare_fn_ty, method_offset_in_vtable, llobject), - ArgVals(&llargs), + ArgVals(&llargs[fcx.arg_pos(1)..]), dest).bcx; finish_fn(&fcx, bcx, sig.output, DebugLoc::None); From 02d74a4852f9138dbabdfeab8ac31298226620fd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B6rn=20Steinbrink?= Date: Thu, 18 Jun 2015 21:16:47 +0200 Subject: [PATCH 3/4] Make trans_arg_datum fill a destination vector instead of returning its result This makes it easier to support translating a single rust argument to more than one llvm argument value later. --- src/librustc_trans/trans/asm.rs | 25 ++++---- src/librustc_trans/trans/callee.rs | 93 +++++++++++++++--------------- 2 files changed, 57 insertions(+), 61 deletions(-) diff --git a/src/librustc_trans/trans/asm.rs b/src/librustc_trans/trans/asm.rs index db726fe4b8e3b..b25d6f2daaca9 100644 --- a/src/librustc_trans/trans/asm.rs +++ b/src/librustc_trans/trans/asm.rs @@ -45,13 +45,12 @@ pub fn trans_inline_asm<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, ia: &ast::InlineAsm) output_types.push(type_of::type_of(bcx.ccx(), out_datum.ty)); let val = out_datum.val; if is_rw { - ext_inputs.push(unpack_result!(bcx, { - callee::trans_arg_datum(bcx, - expr_ty(bcx, &**out), - out_datum, - cleanup::CustomScope(temp_scope), - callee::DontAutorefArg) - })); + bcx = callee::trans_arg_datum(bcx, + expr_ty(bcx, &**out), + out_datum, + cleanup::CustomScope(temp_scope), + callee::DontAutorefArg, + &mut ext_inputs); ext_constraints.push(i.to_string()); } val @@ -59,18 +58,18 @@ pub fn trans_inline_asm<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, ia: &ast::InlineAsm) }).collect::>(); // Now the input operands - let mut inputs = ia.inputs.iter().map(|&(ref c, ref input)| { + let mut inputs = Vec::new(); + for &(ref c, ref input) in &ia.inputs { constraints.push((*c).clone()); let in_datum = unpack_datum!(bcx, expr::trans(bcx, &**input)); - unpack_result!(bcx, { - callee::trans_arg_datum(bcx, + bcx = callee::trans_arg_datum(bcx, expr_ty(bcx, &**input), in_datum, cleanup::CustomScope(temp_scope), - callee::DontAutorefArg) - }) - }).collect::>(); + callee::DontAutorefArg, + &mut inputs); + } inputs.push_all(&ext_inputs[..]); // no failure occurred preparing operands, no need to cleanup diff --git a/src/librustc_trans/trans/callee.rs b/src/librustc_trans/trans/callee.rs index 10aea37f2e95e..a77c5d8f60675 100644 --- a/src/librustc_trans/trans/callee.rs +++ b/src/librustc_trans/trans/callee.rs @@ -921,13 +921,12 @@ fn trans_args_under_call_abi<'blk, 'tcx>( // Translate the `self` argument first. if !ignore_self { let arg_datum = unpack_datum!(bcx, expr::trans(bcx, &*arg_exprs[0])); - llargs.push(unpack_result!(bcx, { - trans_arg_datum(bcx, - args[0], - arg_datum, - arg_cleanup_scope, - DontAutorefArg) - })) + bcx = trans_arg_datum(bcx, + args[0], + arg_datum, + arg_cleanup_scope, + DontAutorefArg, + llargs); } // Now untuple the rest of the arguments. @@ -945,21 +944,20 @@ fn trans_args_under_call_abi<'blk, 'tcx>( tuple_expr.id)); let repr = adt::represent_type(bcx.ccx(), tuple_type); let repr_ptr = &*repr; - llargs.extend(field_types.iter().enumerate().map(|(i, field_type)| { + for (i, field_type) in field_types.iter().enumerate() { let arg_datum = tuple_lvalue_datum.get_element( bcx, field_type, |srcval| { adt::trans_field_ptr(bcx, repr_ptr, srcval, 0, i) }).to_expr_datum(); - unpack_result!(bcx, trans_arg_datum( - bcx, - field_type, - arg_datum, - arg_cleanup_scope, - DontAutorefArg) - ) - })); + bcx = trans_arg_datum(bcx, + field_type, + arg_datum, + arg_cleanup_scope, + DontAutorefArg, + llargs); + } } _ => { bcx.sess().span_bug(tuple_expr.span, @@ -982,13 +980,12 @@ fn trans_overloaded_call_args<'blk, 'tcx>( let arg_tys = ty::erase_late_bound_regions(bcx.tcx(), &ty::ty_fn_args(fn_ty)); if !ignore_self { let arg_datum = unpack_datum!(bcx, expr::trans(bcx, arg_exprs[0])); - llargs.push(unpack_result!(bcx, { - trans_arg_datum(bcx, - arg_tys[0], - arg_datum, - arg_cleanup_scope, - DontAutorefArg) - })) + bcx = trans_arg_datum(bcx, + arg_tys[0], + arg_datum, + arg_cleanup_scope, + DontAutorefArg, + llargs); } // Now untuple the rest of the arguments. @@ -998,13 +995,12 @@ fn trans_overloaded_call_args<'blk, 'tcx>( for (i, &field_type) in field_types.iter().enumerate() { let arg_datum = unpack_datum!(bcx, expr::trans(bcx, arg_exprs[i + 1])); - llargs.push(unpack_result!(bcx, { - trans_arg_datum(bcx, - field_type, - arg_datum, - arg_cleanup_scope, - DontAutorefArg) - })) + bcx = trans_arg_datum(bcx, + field_type, + arg_datum, + arg_cleanup_scope, + DontAutorefArg, + llargs); } } _ => { @@ -1061,11 +1057,10 @@ pub fn trans_args<'a, 'blk, 'tcx>(cx: Block<'blk, 'tcx>, }; let arg_datum = unpack_datum!(bcx, expr::trans(bcx, &**arg_expr)); - llargs.push(unpack_result!(bcx, { - trans_arg_datum(bcx, arg_ty, arg_datum, - arg_cleanup_scope, - DontAutorefArg) - })); + bcx = trans_arg_datum(bcx, arg_ty, arg_datum, + arg_cleanup_scope, + DontAutorefArg, + llargs); } } ArgOverloadedCall(arg_exprs) => { @@ -1079,19 +1074,17 @@ pub fn trans_args<'a, 'blk, 'tcx>(cx: Block<'blk, 'tcx>, ArgOverloadedOp(lhs, rhs, autoref) => { assert!(!variadic); - llargs.push(unpack_result!(bcx, { - trans_arg_datum(bcx, arg_tys[0], lhs, - arg_cleanup_scope, - DontAutorefArg) - })); + bcx = trans_arg_datum(bcx, arg_tys[0], lhs, + arg_cleanup_scope, + DontAutorefArg, + llargs); assert_eq!(arg_tys.len(), 1 + rhs.len()); for (rhs, rhs_id) in rhs { - llargs.push(unpack_result!(bcx, { - trans_arg_datum(bcx, arg_tys[1], rhs, - arg_cleanup_scope, - if autoref { DoAutorefArg(rhs_id) } else { DontAutorefArg }) - })); + bcx = trans_arg_datum(bcx, arg_tys[1], rhs, + arg_cleanup_scope, + if autoref { DoAutorefArg(rhs_id) } else { DontAutorefArg }, + llargs); } } ArgVals(vs) => { @@ -1112,8 +1105,9 @@ pub fn trans_arg_datum<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, formal_arg_ty: Ty<'tcx>, arg_datum: Datum<'tcx, Expr>, arg_cleanup_scope: cleanup::ScopeId, - autoref_arg: AutorefArg) - -> Result<'blk, 'tcx> { + autoref_arg: AutorefArg, + llargs: &mut Vec) + -> Block<'blk, 'tcx> { let _icx = push_ctxt("trans_arg_datum"); let mut bcx = bcx; let ccx = bcx.ccx(); @@ -1164,5 +1158,8 @@ pub fn trans_arg_datum<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, } debug!("--- trans_arg_datum passing {}", bcx.val_to_string(val)); - Result::new(bcx, val) + + llargs.push(val); + + bcx } From f777562eabdb676fafe738b4a652d33866292d7a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B6rn=20Steinbrink?= Date: Thu, 18 Jun 2015 23:57:40 +0200 Subject: [PATCH 4/4] Pass fat pointers in two immediate arguments This has a number of advantages compared to creating a copy in memory and passing a pointer. The obvious one is that we don't have to put the data into memory but can keep it in registers. Since we're currently passing a pointer anyway (instead of using e.g. a known offset on the stack, which is what the `byval` attribute would achieve), we only use a single additional register for each fat pointer, but save at least two pointers worth of stack in exchange (sometimes more because more than one copy gets eliminated). On archs that pass arguments on the stack, we save a pointer worth of stack even without considering the omitted copies. Additionally, LLVM can optimize the code a lot better, to a large degree due to the fact that lots of copies are gone or can be optimized away. Additionally, we can now emit attributes like nonnull on the data and/or vtable pointers contained in the fat pointer, potentially allowing for even more optimizations. This results in LLVM passes being about 3-7% faster (depending on the crate), and the resulting code is also a few percent smaller, for example: text data filename 5671479 3941461 before/librustc-d8ace771.so 5447663 3905745 after/librustc-d8ace771.so 1944425 2394024 before/libstd-d8ace771.so 1896769 2387610 after/libstd-d8ace771.so I had to remove a call in the backtrace-debuginfo test, because LLVM can now merge the tails of some blocks when optimizations are turned on, which can't correctly preserve line info. Fixes #22924 Cc #22891 (at least for fat pointers the code is good now) --- src/librustc_trans/trans/_match.rs | 18 ++----- src/librustc_trans/trans/attributes.rs | 45 ++++++++++++----- src/librustc_trans/trans/base.rs | 63 +++++++++++++++++------- src/librustc_trans/trans/callee.rs | 20 ++++++-- src/librustc_trans/trans/closure.rs | 5 +- src/librustc_trans/trans/common.rs | 9 +--- src/librustc_trans/trans/expr.rs | 3 ++ src/librustc_trans/trans/foreign.rs | 40 ++++++++++----- src/librustc_trans/trans/glue.rs | 2 +- src/librustc_trans/trans/intrinsic.rs | 35 +++++++------ src/librustc_trans/trans/meth.rs | 40 +++++++-------- src/librustc_trans/trans/type_.rs | 4 -- src/librustc_trans/trans/type_of.rs | 15 ++++-- src/test/codegen/function-arguments.rs | 47 ++++++++++++++++++ src/test/run-pass/backtrace-debuginfo.rs | 4 -- 15 files changed, 230 insertions(+), 120 deletions(-) diff --git a/src/librustc_trans/trans/_match.rs b/src/librustc_trans/trans/_match.rs index 05672153b018a..4df10ee3d098e 100644 --- a/src/librustc_trans/trans/_match.rs +++ b/src/librustc_trans/trans/_match.rs @@ -828,19 +828,11 @@ fn compare_values<'blk, 'tcx>(cx: Block<'blk, 'tcx>, None, &format!("comparison of `{}`", rhs_t), StrEqFnLangItem); - let t = ty::mk_str_slice(cx.tcx(), cx.tcx().mk_region(ty::ReStatic), ast::MutImmutable); - // The comparison function gets the slices by value, so we have to make copies here. Even - // if the function doesn't write through the pointer, things like lifetime intrinsics - // require that we do this properly - let lhs_arg = alloc_ty(cx, t, "lhs"); - let rhs_arg = alloc_ty(cx, t, "rhs"); - memcpy_ty(cx, lhs_arg, lhs, t); - memcpy_ty(cx, rhs_arg, rhs, t); - let res = callee::trans_lang_call(cx, did, &[lhs_arg, rhs_arg], None, debug_loc); - call_lifetime_end(res.bcx, lhs_arg); - call_lifetime_end(res.bcx, rhs_arg); - - res + let lhs_data = Load(cx, expr::get_dataptr(cx, lhs)); + let lhs_len = Load(cx, expr::get_len(cx, lhs)); + let rhs_data = Load(cx, expr::get_dataptr(cx, rhs)); + let rhs_len = Load(cx, expr::get_len(cx, rhs)); + callee::trans_lang_call(cx, did, &[lhs_data, lhs_len, rhs_data, rhs_len], None, debug_loc) } let _icx = push_ctxt("compare_values"); diff --git a/src/librustc_trans/trans/attributes.rs b/src/librustc_trans/trans/attributes.rs index 8422c782b4f0d..39e5670c975e0 100644 --- a/src/librustc_trans/trans/attributes.rs +++ b/src/librustc_trans/trans/attributes.rs @@ -188,7 +188,7 @@ pub fn from_fn_type<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, fn_type: ty::Ty<'tcx }; // Index 0 is the return value of the llvm func, so we start at 1 - let mut first_arg_offset = 1; + let mut idx = 1; if let ty::FnConverging(ret_ty) = ret_ty { // A function pointer is called without the declaration // available, so we have to apply any attributes with ABI @@ -206,7 +206,7 @@ pub fn from_fn_type<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, fn_type: ty::Ty<'tcx .arg(1, llvm::DereferenceableAttribute(llret_sz)); // Add one more since there's an outptr - first_arg_offset += 1; + idx += 1; } else { // The `noalias` attribute on the return value is useful to a // function ptr caller. @@ -236,10 +236,9 @@ pub fn from_fn_type<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, fn_type: ty::Ty<'tcx } } - for (idx, &t) in input_tys.iter().enumerate().map(|(i, v)| (i + first_arg_offset, v)) { + for &t in input_tys.iter() { match t.sty { - // this needs to be first to prevent fat pointers from falling through - _ if !common::type_is_immediate(ccx, t) => { + _ if type_of::arg_is_indirect(ccx, t) => { let llarg_sz = machine::llsize_of_real(ccx, type_of::type_of(ccx, t)); // For non-immediate arguments the callee gets its own copy of @@ -256,10 +255,17 @@ pub fn from_fn_type<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, fn_type: ty::Ty<'tcx // `Box` pointer parameters never alias because ownership is transferred ty::TyBox(inner) => { - let llsz = machine::llsize_of_real(ccx, type_of::type_of(ccx, inner)); - - attrs.arg(idx, llvm::Attribute::NoAlias) - .arg(idx, llvm::DereferenceableAttribute(llsz)); + attrs.arg(idx, llvm::Attribute::NoAlias); + + if common::type_is_sized(ccx.tcx(), inner) { + let llsz = machine::llsize_of_real(ccx, type_of::type_of(ccx, inner)); + attrs.arg(idx, llvm::DereferenceableAttribute(llsz)); + } else { + attrs.arg(idx, llvm::NonNullAttribute); + if ty::type_is_trait(inner) { + attrs.arg(idx + 1, llvm::NonNullAttribute); + } + } } ty::TyRef(b, mt) => { @@ -278,10 +284,17 @@ pub fn from_fn_type<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, fn_type: ty::Ty<'tcx attrs.arg(idx, llvm::Attribute::ReadOnly); } - // & pointer parameters are also never null and we know exactly - // how many bytes we can dereference - let llsz = machine::llsize_of_real(ccx, type_of::type_of(ccx, mt.ty)); - attrs.arg(idx, llvm::DereferenceableAttribute(llsz)); + // & pointer parameters are also never null and for sized types we also know + // exactly how many bytes we can dereference + if common::type_is_sized(ccx.tcx(), mt.ty) { + let llsz = machine::llsize_of_real(ccx, type_of::type_of(ccx, mt.ty)); + attrs.arg(idx, llvm::DereferenceableAttribute(llsz)); + } else { + attrs.arg(idx, llvm::NonNullAttribute); + if ty::type_is_trait(mt.ty) { + attrs.arg(idx + 1, llvm::NonNullAttribute); + } + } // When a reference in an argument has no named lifetime, it's // impossible for that reference to escape this function @@ -293,6 +306,12 @@ pub fn from_fn_type<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, fn_type: ty::Ty<'tcx _ => () } + + if common::type_is_fat_ptr(ccx.tcx(), t) { + idx += 2; + } else { + idx += 1; + } } attrs diff --git a/src/librustc_trans/trans/base.rs b/src/librustc_trans/trans/base.rs index 8fa47ed2c267c..461739a362d30 100644 --- a/src/librustc_trans/trans/base.rs +++ b/src/librustc_trans/trans/base.rs @@ -1297,16 +1297,28 @@ pub type RvalueDatum<'tcx> = datum::Datum<'tcx, datum::Rvalue>; // create_datums_for_fn_args: creates rvalue datums for each of the // incoming function arguments. These will later be stored into // appropriate lvalue datums. -pub fn create_datums_for_fn_args<'a, 'tcx>(fcx: &FunctionContext<'a, 'tcx>, +pub fn create_datums_for_fn_args<'a, 'tcx>(bcx: Block<'a, 'tcx>, arg_tys: &[Ty<'tcx>]) -> Vec> { let _icx = push_ctxt("create_datums_for_fn_args"); + let fcx = bcx.fcx; // Return an array wrapping the ValueRefs that we get from `get_param` for // each argument into datums. - arg_tys.iter().enumerate().map(|(i, &arg_ty)| { - let llarg = get_param(fcx.llfn, fcx.arg_pos(i) as c_uint); - datum::Datum::new(llarg, arg_ty, arg_kind(fcx, arg_ty)) + let mut i = fcx.arg_offset() as c_uint; + arg_tys.iter().map(|&arg_ty| { + if common::type_is_fat_ptr(bcx.tcx(), arg_ty) { + let llty = type_of::type_of(bcx.ccx(), arg_ty); + let data = get_param(fcx.llfn, i); + let extra = get_param(fcx.llfn, i + 1); + let fat_ptr = expr::make_fat_ptr(bcx, llty, data, extra); + i += 2; + datum::Datum::new(fat_ptr, arg_ty, datum::Rvalue { mode: datum::ByValue }) + } else { + let llarg = get_param(fcx.llfn, i); + i += 1; + datum::Datum::new(llarg, arg_ty, arg_kind(fcx, arg_ty)) + } }).collect() } @@ -1321,12 +1333,23 @@ fn create_datums_for_fn_args_under_call_abi<'blk, 'tcx>( arg_tys: &[Ty<'tcx>]) -> Vec> { let mut result = Vec::new(); + let mut idx = bcx.fcx.arg_offset() as c_uint; for (i, &arg_ty) in arg_tys.iter().enumerate() { if i < arg_tys.len() - 1 { // Regular argument. - let llarg = get_param(bcx.fcx.llfn, bcx.fcx.arg_pos(i) as c_uint); - result.push(datum::Datum::new(llarg, arg_ty, arg_kind(bcx.fcx, - arg_ty))); + result.push(if common::type_is_fat_ptr(bcx.tcx(), arg_ty) { + let llty = type_of::type_of(bcx.ccx(), arg_ty); + let data = get_param(bcx.fcx.llfn, idx); + let extra = get_param(bcx.fcx.llfn, idx + 1); + idx += 2; + let fat_ptr = expr::make_fat_ptr(bcx, llty, data, extra); + datum::Datum::new(fat_ptr, arg_ty, datum::Rvalue { mode: datum::ByValue }) + } else { + let val = get_param(bcx.fcx.llfn, idx); + idx += 1; + datum::Datum::new(val, arg_ty, arg_kind(bcx.fcx, arg_ty)) + }); + continue } @@ -1346,15 +1369,21 @@ fn create_datums_for_fn_args_under_call_abi<'blk, 'tcx>( llval| { for (j, &tupled_arg_ty) in tupled_arg_tys.iter().enumerate() { - let llarg = - get_param(bcx.fcx.llfn, - bcx.fcx.arg_pos(i + j) as c_uint); let lldest = GEPi(bcx, llval, &[0, j]); - let datum = datum::Datum::new( - llarg, - tupled_arg_ty, - arg_kind(bcx.fcx, tupled_arg_ty)); - bcx = datum.store_to(bcx, lldest); + if common::type_is_fat_ptr(bcx.tcx(), tupled_arg_ty) { + let data = get_param(bcx.fcx.llfn, idx); + let extra = get_param(bcx.fcx.llfn, idx + 1); + Store(bcx, data, expr::get_dataptr(bcx, lldest)); + Store(bcx, extra, expr::get_len(bcx, lldest)); + idx += 2; + } else { + let datum = datum::Datum::new( + get_param(bcx.fcx.llfn, idx), + tupled_arg_ty, + arg_kind(bcx.fcx, tupled_arg_ty)); + idx += 1; + bcx = datum.store_to(bcx, lldest); + }; } bcx })); @@ -1566,7 +1595,7 @@ pub fn trans_closure<'a, 'b, 'tcx>(ccx: &CrateContext<'a, 'tcx>, } _ => { let arg_tys = untuple_arguments_if_necessary(ccx, &monomorphized_arg_types, abi); - create_datums_for_fn_args(&fcx, &arg_tys) + create_datums_for_fn_args(bcx, &arg_tys) } }; @@ -1773,7 +1802,7 @@ fn trans_enum_variant_or_tuple_like_struct<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx ty::erase_late_bound_regions( ccx.tcx(), &ty::ty_fn_args(ctor_ty)); - let arg_datums = create_datums_for_fn_args(&fcx, &arg_tys[..]); + let arg_datums = create_datums_for_fn_args(bcx, &arg_tys[..]); if !type_is_zero_size(fcx.ccx, result_ty.unwrap()) { let dest = fcx.get_ret_slot(bcx, result_ty, "eret_slot"); diff --git a/src/librustc_trans/trans/callee.rs b/src/librustc_trans/trans/callee.rs index a77c5d8f60675..093b824701fa4 100644 --- a/src/librustc_trans/trans/callee.rs +++ b/src/librustc_trans/trans/callee.rs @@ -343,11 +343,12 @@ pub fn trans_fn_pointer_shim<'a, 'tcx>( let llargs = get_params(fcx.llfn); + let self_idx = fcx.arg_offset(); // the first argument (`self`) will be ptr to the the fn pointer let llfnpointer = if is_by_ref { - Load(bcx, llargs[fcx.arg_pos(0)]) + Load(bcx, llargs[self_idx]) } else { - llargs[fcx.arg_pos(0)] + llargs[self_idx] }; assert!(!fcx.needs_ret_allocas); @@ -360,7 +361,7 @@ pub fn trans_fn_pointer_shim<'a, 'tcx>( DebugLoc::None, bare_fn_ty, |bcx, _| Callee { bcx: bcx, data: Fn(llfnpointer) }, - ArgVals(&llargs[fcx.arg_pos(1)..]), + ArgVals(&llargs[(self_idx + 1)..]), dest).bcx; finish_fn(&fcx, bcx, sig.output, DebugLoc::None); @@ -1129,6 +1130,10 @@ pub fn trans_arg_datum<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, bcx, arg_datum.to_lvalue_datum(bcx, "arg", arg_id)); val = arg_datum.val; } + DontAutorefArg if common::type_is_fat_ptr(bcx.tcx(), arg_datum_ty) && + !bcx.fcx.type_needs_drop(arg_datum_ty) => { + val = arg_datum.val + } DontAutorefArg => { // Make this an rvalue, since we are going to be // passing ownership. @@ -1147,7 +1152,7 @@ pub fn trans_arg_datum<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, } } - if formal_arg_ty != arg_datum_ty { + if type_of::arg_is_indirect(ccx, formal_arg_ty) && formal_arg_ty != arg_datum_ty { // this could happen due to e.g. subtyping let llformal_arg_ty = type_of::type_of_explicit_arg(ccx, formal_arg_ty); debug!("casting actual type ({}) to match formal ({})", @@ -1159,7 +1164,12 @@ pub fn trans_arg_datum<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, debug!("--- trans_arg_datum passing {}", bcx.val_to_string(val)); - llargs.push(val); + if common::type_is_fat_ptr(bcx.tcx(), formal_arg_ty) { + llargs.push(Load(bcx, expr::get_dataptr(bcx, val))); + llargs.push(Load(bcx, expr::get_len(bcx, val))); + } else { + llargs.push(val); + } bcx } diff --git a/src/librustc_trans/trans/closure.rs b/src/librustc_trans/trans/closure.rs index 127fee222da01..61351847a830c 100644 --- a/src/librustc_trans/trans/closure.rs +++ b/src/librustc_trans/trans/closure.rs @@ -411,7 +411,8 @@ fn trans_fn_once_adapter_shim<'a, 'tcx>( let self_scope = fcx.push_custom_cleanup_scope(); let self_scope_id = CustomScope(self_scope); let rvalue_mode = datum::appropriate_rvalue_mode(ccx, closure_ty); - let llself = llargs[fcx.arg_pos(0)]; + let self_idx = fcx.arg_offset(); + let llself = llargs[self_idx]; let env_datum = Datum::new(llself, closure_ty, Rvalue::new(rvalue_mode)); let env_datum = unpack_datum!(bcx, env_datum.to_lvalue_datum_in_scope(bcx, "self", @@ -431,7 +432,7 @@ fn trans_fn_once_adapter_shim<'a, 'tcx>( DebugLoc::None, llref_fn_ty, |bcx, _| Callee { bcx: bcx, data: callee_data }, - ArgVals(&llargs[fcx.arg_pos(1)..]), + ArgVals(&llargs[(self_idx + 1)..]), dest).bcx; fcx.pop_custom_cleanup_scope(self_scope); diff --git a/src/librustc_trans/trans/common.rs b/src/librustc_trans/trans/common.rs index 5dddf161e69fb..403755c536d75 100644 --- a/src/librustc_trans/trans/common.rs +++ b/src/librustc_trans/trans/common.rs @@ -421,13 +421,8 @@ pub struct FunctionContext<'a, 'tcx: 'a> { } impl<'a, 'tcx> FunctionContext<'a, 'tcx> { - pub fn arg_pos(&self, arg: usize) -> usize { - let arg = self.env_arg_pos() + arg; - if self.llenv.is_some() { - arg + 1 - } else { - arg - } + pub fn arg_offset(&self) -> usize { + self.env_arg_pos() + if self.llenv.is_some() { 1 } else { 0 } } pub fn env_arg_pos(&self) -> usize { diff --git a/src/librustc_trans/trans/expr.rs b/src/librustc_trans/trans/expr.rs index 48deceeeef73f..aff91e295c9bf 100644 --- a/src/librustc_trans/trans/expr.rs +++ b/src/librustc_trans/trans/expr.rs @@ -293,6 +293,9 @@ pub fn get_dataptr(bcx: Block, fat_ptr: ValueRef) -> ValueRef { GEPi(bcx, fat_ptr, &[0, abi::FAT_PTR_ADDR]) } +pub fn make_fat_ptr(bcx: Block, ty: Type, data: ValueRef, extra: ValueRef) -> ValueRef { + InsertValue(bcx, InsertValue(bcx, C_undef(ty), data, 0), extra, 1) +} pub fn copy_fat_ptr(bcx: Block, src_ptr: ValueRef, dst_ptr: ValueRef) { Store(bcx, Load(bcx, get_dataptr(bcx, src_ptr)), get_dataptr(bcx, dst_ptr)); Store(bcx, Load(bcx, get_len(bcx, src_ptr)), get_len(bcx, dst_ptr)); diff --git a/src/librustc_trans/trans/foreign.rs b/src/librustc_trans/trans/foreign.rs index 977d636d253e4..4f3f13e4bed24 100644 --- a/src/librustc_trans/trans/foreign.rs +++ b/src/librustc_trans/trans/foreign.rs @@ -9,7 +9,7 @@ // except according to those terms. -use back::link; +use back::{abi, link}; use llvm::{ValueRef, CallConv, get_param}; use llvm; use middle::weak_lang_items; @@ -22,6 +22,7 @@ use trans::cabi; use trans::common::*; use trans::debuginfo::DebugLoc; use trans::declare; +use trans::expr; use trans::machine; use trans::monomorphize; use trans::type_::Type; @@ -272,10 +273,11 @@ pub fn trans_native_call<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, } } - for (i, &llarg_rust) in llargs_rust.iter().enumerate() { - let mut llarg_rust = llarg_rust; + let mut offset = 0; + for (i, arg_ty) in arg_tys.iter().enumerate() { + let mut llarg_rust = llargs_rust[i + offset]; - if arg_tys[i].is_ignore() { + if arg_ty.is_ignore() { continue; } @@ -286,7 +288,7 @@ pub fn trans_native_call<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, i, ccx.tn().val_to_string(llarg_rust), rust_indirect, - ccx.tn().type_to_string(arg_tys[i].ty)); + ccx.tn().type_to_string(arg_ty.ty)); // Ensure that we always have the Rust value indirectly, // because it makes bitcasting easier. @@ -295,7 +297,13 @@ pub fn trans_native_call<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, base::alloca(bcx, type_of::type_of(ccx, passed_arg_tys[i]), "__arg"); - base::store_ty(bcx, llarg_rust, scratch, passed_arg_tys[i]); + if type_is_fat_ptr(ccx.tcx(), passed_arg_tys[i]) { + Store(bcx, llargs_rust[i + offset], expr::get_dataptr(bcx, scratch)); + Store(bcx, llargs_rust[i + offset + 1], expr::get_len(bcx, scratch)); + offset += 1; + } else { + base::store_ty(bcx, llarg_rust, scratch, passed_arg_tys[i]); + } llarg_rust = scratch; } @@ -303,7 +311,7 @@ pub fn trans_native_call<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, ccx.tn().val_to_string(llarg_rust)); // Check whether we need to do any casting - match arg_tys[i].cast { + match arg_ty.cast { Some(ty) => llarg_rust = BitCast(bcx, llarg_rust, ty.ptr_to()), None => () } @@ -312,7 +320,7 @@ pub fn trans_native_call<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, ccx.tn().val_to_string(llarg_rust)); // Finally, load the value if needed for the foreign ABI - let foreign_indirect = arg_tys[i].is_indirect(); + let foreign_indirect = arg_ty.is_indirect(); let llarg_foreign = if foreign_indirect { llarg_rust } else { @@ -328,7 +336,7 @@ pub fn trans_native_call<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, i, ccx.tn().val_to_string(llarg_foreign)); // fill padding with undef value - match arg_tys[i].pad { + match arg_ty.pad { Some(ty) => llargs_foreign.push(C_undef(ty)), None => () } @@ -783,12 +791,12 @@ pub fn trans_rust_fn_with_foreign_abi<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, // If the types in the ABI and the Rust types don't match, // bitcast the llforeign_arg pointer so it matches the types // Rust expects. - if llforeign_arg_ty.cast.is_some() { + if llforeign_arg_ty.cast.is_some() && !type_is_fat_ptr(ccx.tcx(), rust_ty){ assert!(!foreign_indirect); llforeign_arg = builder.bitcast(llforeign_arg, llrust_ty.ptr_to()); } - let llrust_arg = if rust_indirect { + let llrust_arg = if rust_indirect || type_is_fat_ptr(ccx.tcx(), rust_ty) { llforeign_arg } else { if ty::type_is_bool(rust_ty) { @@ -810,7 +818,15 @@ pub fn trans_rust_fn_with_foreign_abi<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, debug!("llrust_arg {}{}: {}", "#", i, ccx.tn().val_to_string(llrust_arg)); - llrust_args.push(llrust_arg); + if type_is_fat_ptr(ccx.tcx(), rust_ty) { + let next_llrust_ty = rust_param_tys.next().expect("Not enough parameter types!"); + llrust_args.push(builder.load(builder.bitcast(builder.gepi( + llrust_arg, &[0, abi::FAT_PTR_ADDR]), llrust_ty.ptr_to()))); + llrust_args.push(builder.load(builder.bitcast(builder.gepi( + llrust_arg, &[0, abi::FAT_PTR_EXTRA]), next_llrust_ty.ptr_to()))); + } else { + llrust_args.push(llrust_arg); + } } // Perform the call itself diff --git a/src/librustc_trans/trans/glue.rs b/src/librustc_trans/trans/glue.rs index 6caf00634b63a..b84475d915a4f 100644 --- a/src/librustc_trans/trans/glue.rs +++ b/src/librustc_trans/trans/glue.rs @@ -259,7 +259,7 @@ fn get_drop_glue_core<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, // llfn is expected be declared to take a parameter of the appropriate // type, so we don't need to explicitly cast the function parameter. - let llrawptr0 = get_param(llfn, fcx.arg_pos(0) as c_uint); + let llrawptr0 = get_param(llfn, fcx.arg_offset() as c_uint); let bcx = make_drop_glue(bcx, llrawptr0, g); finish_fn(&fcx, bcx, ty::FnConverging(ty::mk_nil(ccx.tcx())), DebugLoc::None); diff --git a/src/librustc_trans/trans/intrinsic.rs b/src/librustc_trans/trans/intrinsic.rs index 41d150ac265c9..dd97265e428ed 100644 --- a/src/librustc_trans/trans/intrinsic.rs +++ b/src/librustc_trans/trans/intrinsic.rs @@ -275,17 +275,13 @@ pub fn trans_intrinsic_call<'a, 'blk, 'tcx>(mut bcx: Block<'blk, 'tcx>, } else { (&exprs[0], &exprs[1]) }; - let arg_tys = ty::erase_late_bound_regions(bcx.tcx(), &ty::ty_fn_args(callee_ty)); // evaluate destination address - let lldest_addr = unpack_result!(bcx, { - let dest_datum = unpack_datum!(bcx, expr::trans(bcx, dest_expr)); - callee::trans_arg_datum(bcx, - arg_tys[0], - dest_datum, - cleanup::CustomScope(cleanup_scope), - callee::DontAutorefArg) - }); + let dest_datum = unpack_datum!(bcx, expr::trans(bcx, dest_expr)); + let dest_datum = unpack_datum!( + bcx, dest_datum.to_rvalue_datum(bcx, "arg")); + let dest_datum = unpack_datum!( + bcx, dest_datum.to_appropriate_datum(bcx)); // `expr::trans_into(bcx, expr, dest)` is equiv to // @@ -294,7 +290,7 @@ pub fn trans_intrinsic_call<'a, 'blk, 'tcx>(mut bcx: Block<'blk, 'tcx>, // which for `dest == expr::SaveIn(addr)`, is equivalent to: // // `trans(bcx, expr).store_to(bcx, addr)`. - let lldest = expr::Dest::SaveIn(lldest_addr); + let lldest = expr::Dest::SaveIn(dest_datum.val); bcx = expr::trans_into(bcx, source_expr, lldest); let llresult = C_nil(ccx); @@ -370,8 +366,7 @@ pub fn trans_intrinsic_call<'a, 'blk, 'tcx>(mut bcx: Block<'blk, 'tcx>, (_, "size_of_val") => { let tp_ty = *substs.types.get(FnSpace, 0); if !type_is_sized(tcx, tp_ty) { - let info = Load(bcx, expr::get_len(bcx, llargs[0])); - let (llsize, _) = glue::size_and_align_of_dst(bcx, tp_ty, info); + let (llsize, _) = glue::size_and_align_of_dst(bcx, tp_ty, llargs[1]); llsize } else { let lltp_ty = type_of::type_of(ccx, tp_ty); @@ -385,8 +380,7 @@ pub fn trans_intrinsic_call<'a, 'blk, 'tcx>(mut bcx: Block<'blk, 'tcx>, (_, "min_align_of_val") => { let tp_ty = *substs.types.get(FnSpace, 0); if !type_is_sized(tcx, tp_ty) { - let info = Load(bcx, expr::get_len(bcx, llargs[0])); - let (_, llalign) = glue::size_and_align_of_dst(bcx, tp_ty, info); + let (_, llalign) = glue::size_and_align_of_dst(bcx, tp_ty, llargs[1]); llalign } else { C_uint(ccx, type_of::align_of(ccx, tp_ty)) @@ -399,7 +393,16 @@ pub fn trans_intrinsic_call<'a, 'blk, 'tcx>(mut bcx: Block<'blk, 'tcx>, } (_, "drop_in_place") => { let tp_ty = *substs.types.get(FnSpace, 0); - glue::drop_ty(bcx, llargs[0], tp_ty, call_debug_location); + let ptr = if type_is_sized(tcx, tp_ty) { + llargs[0] + } else { + let scratch = rvalue_scratch_datum(bcx, tp_ty, "tmp"); + Store(bcx, llargs[0], expr::get_dataptr(bcx, scratch.val)); + Store(bcx, llargs[1], expr::get_len(bcx, scratch.val)); + fcx.schedule_lifetime_end(cleanup::CustomScope(cleanup_scope), scratch.val); + scratch.val + }; + glue::drop_ty(bcx, ptr, tp_ty, call_debug_location); C_nil(ccx) } (_, "type_name") => { @@ -980,7 +983,7 @@ fn with_overflow_intrinsic<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, let ret = C_undef(type_of::type_of(bcx.ccx(), t)); let ret = InsertValue(bcx, ret, result, 0); let ret = InsertValue(bcx, ret, overflow, 1); - if type_is_immediate(bcx.ccx(), t) { + if !arg_is_indirect(bcx.ccx(), t) { let tmp = alloc_ty(bcx, t, "tmp"); Store(bcx, ret, tmp); load_ty(bcx, tmp, t) diff --git a/src/librustc_trans/trans/meth.rs b/src/librustc_trans/trans/meth.rs index 6955e03596fde..e61770768db22 100644 --- a/src/librustc_trans/trans/meth.rs +++ b/src/librustc_trans/trans/meth.rs @@ -468,7 +468,9 @@ fn trans_trait_callee<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, self_datum.val }; - trans_trait_callee_from_llval(bcx, method_ty, vtable_index, llval) + let llself = Load(bcx, GEPi(bcx, llval, &[0, abi::FAT_PTR_ADDR])); + let llvtable = Load(bcx, GEPi(bcx, llval, &[0, abi::FAT_PTR_EXTRA])); + trans_trait_callee_from_llval(bcx, method_ty, vtable_index, llself, llvtable) } /// Same as `trans_trait_callee()` above, except that it is given a by-ref pointer to the object @@ -476,19 +478,18 @@ fn trans_trait_callee<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, pub fn trans_trait_callee_from_llval<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, callee_ty: Ty<'tcx>, vtable_index: usize, - llpair: ValueRef) + llself: ValueRef, + llvtable: ValueRef) -> Callee<'blk, 'tcx> { let _icx = push_ctxt("meth::trans_trait_callee"); let ccx = bcx.ccx(); // Load the data pointer from the object. - debug!("trans_trait_callee_from_llval(callee_ty={}, vtable_index={}, llpair={})", + debug!("trans_trait_callee_from_llval(callee_ty={}, vtable_index={}, llself={}, llvtable={})", callee_ty, vtable_index, - bcx.val_to_string(llpair)); - let llboxptr = GEPi(bcx, llpair, &[0, abi::FAT_PTR_ADDR]); - let llbox = Load(bcx, llboxptr); - let llself = PointerCast(bcx, llbox, Type::i8p(ccx)); + bcx.val_to_string(llself), + bcx.val_to_string(llvtable)); // Replace the self type (&Self or Box) with an opaque pointer. let llcallee_ty = match callee_ty.sty { @@ -505,19 +506,13 @@ pub fn trans_trait_callee_from_llval<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, ccx.sess().bug("meth::trans_trait_callee given non-bare-rust-fn"); } }; - let llvtable = Load(bcx, - PointerCast(bcx, - GEPi(bcx, llpair, - &[0, abi::FAT_PTR_EXTRA]), - Type::vtable(ccx).ptr_to().ptr_to())); - let mptr = Load(bcx, GEPi(bcx, llvtable, &[0, vtable_index + VTABLE_OFFSET])); - let mptr = PointerCast(bcx, mptr, llcallee_ty.ptr_to()); + let mptr = Load(bcx, GEPi(bcx, llvtable, &[vtable_index + VTABLE_OFFSET])); return Callee { bcx: bcx, data: TraitItem(MethodData { - llfn: mptr, - llself: llself, + llfn: PointerCast(bcx, mptr, llcallee_ty.ptr_to()), + llself: PointerCast(bcx, llself, Type::i8p(ccx)), }) }; } @@ -613,11 +608,12 @@ pub fn trans_object_shim<'a, 'tcx>( let llargs = get_params(fcx.llfn); - // the first argument (`self`) will be a trait object - let llobject = llargs[fcx.arg_pos(0)]; + let self_idx = fcx.arg_offset(); + let llself = llargs[self_idx]; + let llvtable = llargs[self_idx + 1]; - debug!("trans_object_shim: llobject={}", - bcx.val_to_string(llobject)); + debug!("trans_object_shim: llself={}, llvtable={}", + bcx.val_to_string(llself), bcx.val_to_string(llvtable)); assert!(!fcx.needs_ret_allocas); @@ -639,8 +635,8 @@ pub fn trans_object_shim<'a, 'tcx>( |bcx, _| trans_trait_callee_from_llval(bcx, method_bare_fn_ty, method_offset_in_vtable, - llobject), - ArgVals(&llargs[fcx.arg_pos(1)..]), + llself, llvtable), + ArgVals(&llargs[(self_idx + 2)..]), dest).bcx; finish_fn(&fcx, bcx, sig.output, DebugLoc::None); diff --git a/src/librustc_trans/trans/type_.rs b/src/librustc_trans/trans/type_.rs index 339b4734ee4b1..b80b2b8266a2c 100644 --- a/src/librustc_trans/trans/type_.rs +++ b/src/librustc_trans/trans/type_.rs @@ -171,10 +171,6 @@ impl Type { Type::struct_(ccx, &[], false) } - pub fn vtable(ccx: &CrateContext) -> Type { - Type::array(&Type::i8p(ccx).ptr_to(), 1) - } - pub fn glue_fn(ccx: &CrateContext, t: Type) -> Type { Type::func(&[t], &Type::void(ccx)) } diff --git a/src/librustc_trans/trans/type_of.rs b/src/librustc_trans/trans/type_of.rs index 26b54142d6316..49601ac6fe94d 100644 --- a/src/librustc_trans/trans/type_of.rs +++ b/src/librustc_trans/trans/type_of.rs @@ -36,12 +36,12 @@ fn ensure_array_fits_in_address_space<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, pub fn arg_is_indirect<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, arg_ty: Ty<'tcx>) -> bool { - !type_is_immediate(ccx, arg_ty) + !type_is_immediate(ccx, arg_ty) && !type_is_fat_ptr(ccx.tcx(), arg_ty) } pub fn return_uses_outptr<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, ty: Ty<'tcx>) -> bool { - !type_is_immediate(ccx, ty) + arg_is_indirect(ccx, ty) } pub fn type_of_explicit_arg<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, @@ -136,8 +136,15 @@ pub fn type_of_rust_fn<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, } // ... then explicit args. - let input_tys = inputs.iter().map(|&arg_ty| type_of_explicit_arg(cx, arg_ty)); - atys.extend(input_tys); + for input in &inputs { + let arg_ty = type_of_explicit_arg(cx, input); + + if type_is_fat_ptr(cx.tcx(), input) { + atys.extend(arg_ty.field_types()); + } else { + atys.push(arg_ty); + } + } Type::func(&atys[..], &lloutputtype) } diff --git a/src/test/codegen/function-arguments.rs b/src/test/codegen/function-arguments.rs index f11e769ca6c0f..7706c97380b16 100644 --- a/src/test/codegen/function-arguments.rs +++ b/src/test/codegen/function-arguments.rs @@ -87,6 +87,53 @@ pub fn struct_return() -> S { } } +// Hack to get the correct size for the length part in slices +// CHECK: @helper([[USIZE:i[0-9]+]]) +#[no_mangle] +fn helper(_: usize) { +} + +// CHECK: @slice(i8* noalias nonnull readonly, [[USIZE]]) +// FIXME #25759 This should also have `nocapture` +#[no_mangle] +fn slice(_: &[u8]) { +} + +// CHECK: @mutable_slice(i8* noalias nonnull, [[USIZE]]) +// FIXME #25759 This should also have `nocapture` +#[no_mangle] +fn mutable_slice(_: &mut [u8]) { +} + +// CHECK: @unsafe_slice(%UnsafeInner* nonnull, [[USIZE]]) +// unsafe interior means this isn't actually readonly and there may be aliases ... +#[no_mangle] +pub fn unsafe_slice(_: &[UnsafeInner]) { +} + +// CHECK: @str(i8* noalias nonnull readonly, [[USIZE]]) +// FIXME #25759 This should also have `nocapture` +#[no_mangle] +fn str(_: &[u8]) { +} + +// CHECK: @trait_borrow(i8* nonnull, void (i8*)** nonnull) +// FIXME #25759 This should also have `nocapture` +#[no_mangle] +fn trait_borrow(_: &Drop) { +} + +// CHECK: @trait_box(i8* noalias nonnull, void (i8*)** nonnull) +#[no_mangle] +fn trait_box(_: Box) { +} + +// CHECK: { i16*, [[USIZE]] } @return_slice(i16* noalias nonnull readonly, [[USIZE]]) +#[no_mangle] +fn return_slice(x: &[u16]) -> &[u16] { + x +} + // CHECK: noalias i8* @allocator() #[no_mangle] #[allocator] diff --git a/src/test/run-pass/backtrace-debuginfo.rs b/src/test/run-pass/backtrace-debuginfo.rs index 2a74e36aff3dd..8f41c68b0473f 100644 --- a/src/test/run-pass/backtrace-debuginfo.rs +++ b/src/test/run-pass/backtrace-debuginfo.rs @@ -97,10 +97,6 @@ fn inner_inlined(counter: &mut i32, main_pos: Pos, outer_pos: Pos) { let inner_pos = pos!(); aux::callback_inlined(|aux_pos| { check!(counter; main_pos, outer_pos, inner_pos, aux_pos); }); - - // this tests a distinction between two independent calls to the inlined function. - // (un)fortunately, LLVM somehow merges two consecutive such calls into one node. - inner_further_inlined(counter, main_pos, outer_pos, pos!()); } #[inline(never)]