diff --git a/src/librustc/lib/llvm.rs b/src/librustc/lib/llvm.rs index 711081f46d666..dacda4e2a0b7c 100644 --- a/src/librustc/lib/llvm.rs +++ b/src/librustc/lib/llvm.rs @@ -15,7 +15,7 @@ use std::c_str::ToCStr; use std::cell::RefCell; use collections::HashMap; -use libc::{c_uint, c_ushort, c_void, free}; +use libc::{c_uint, c_ushort, c_void, free, uint64_t}; use std::str::raw::from_c_str; use middle::trans::type_::Type; @@ -92,6 +92,33 @@ pub enum Attribute { NonLazyBindAttribute = 1 << 31, } +#[repr(u64)] +pub enum OtherAttribute { + // The following are not really exposed in + // the LLVM c api so instead to add these + // we call a wrapper function in RustWrapper + // that uses the C++ api. + SanitizeAddressAttribute = 1 << 32, + MinSizeAttribute = 1 << 33, + NoDuplicateAttribute = 1 << 34, + StackProtectStrongAttribute = 1 << 35, + SanitizeThreadAttribute = 1 << 36, + SanitizeMemoryAttribute = 1 << 37, + NoBuiltinAttribute = 1 << 38, + ReturnedAttribute = 1 << 39, + ColdAttribute = 1 << 40, + BuiltinAttribute = 1 << 41, + OptimizeNoneAttribute = 1 << 42, + InAllocaAttribute = 1 << 43, + NonNullAttribute = 1 << 44, +} + +#[repr(C)] +pub enum AttributeSet { + ReturnIndex = 0, + FunctionIndex = !0 +} + // enum for the LLVM IntPredicate type pub enum IntPredicate { IntEQ = 32, @@ -308,7 +335,7 @@ pub mod llvm { use super::{CodeGenModel, RelocMode, CodeGenOptLevel}; use super::debuginfo::*; use libc::{c_char, c_int, c_longlong, c_ushort, c_uint, c_ulonglong, - size_t}; + size_t, uint64_t}; // Link to our native llvm bindings (things that we need to use the C++ api // for) and because llvm is written in C++ we need to link against libstdc++ @@ -706,20 +733,11 @@ pub mod llvm { pub fn LLVMSetFunctionCallConv(Fn: ValueRef, CC: c_uint); pub fn LLVMGetGC(Fn: ValueRef) -> *c_char; pub fn LLVMSetGC(Fn: ValueRef, Name: *c_char); - pub fn LLVMAddFunctionAttr(Fn: ValueRef, PA: c_uint); - pub fn LLVMAddFunctionAttrString(Fn: ValueRef, Name: *c_char); - pub fn LLVMRemoveFunctionAttrString(Fn: ValueRef, Name: *c_char); + pub fn LLVMAddFunctionAttribute(Fn: ValueRef, index: c_uint, PA: uint64_t); + pub fn LLVMAddFunctionAttrString(Fn: ValueRef, index: c_uint, Name: *c_char); + pub fn LLVMRemoveFunctionAttrString(Fn: ValueRef, index: c_uint, Name: *c_char); pub fn LLVMGetFunctionAttr(Fn: ValueRef) -> c_ulonglong; - pub fn LLVMAddReturnAttribute(Fn: ValueRef, PA: c_uint); - pub fn LLVMRemoveReturnAttribute(Fn: ValueRef, PA: c_uint); - - pub fn LLVMAddColdAttribute(Fn: ValueRef); - - pub fn LLVMRemoveFunctionAttr(Fn: ValueRef, - PA: c_ulonglong, - HighPA: c_ulonglong); - /* Operations on parameters */ pub fn LLVMCountParams(Fn: ValueRef) -> c_uint; pub fn LLVMGetParams(Fn: ValueRef, Params: *ValueRef); @@ -783,6 +801,9 @@ pub mod llvm { pub fn LLVMSetInstrParamAlignment(Instr: ValueRef, index: c_uint, align: c_uint); + pub fn LLVMAddCallSiteAttribute(Instr: ValueRef, + index: c_uint, + Val: uint64_t); /* Operations on call instructions (only) */ pub fn LLVMIsTailCall(CallInst: ValueRef) -> Bool; @@ -1835,7 +1856,7 @@ pub fn ConstFCmp(pred: RealPredicate, v1: ValueRef, v2: ValueRef) -> ValueRef { pub fn SetFunctionAttribute(fn_: ValueRef, attr: Attribute) { unsafe { - llvm::LLVMAddFunctionAttr(fn_, attr as c_uint) + llvm::LLVMAddFunctionAttribute(fn_, FunctionIndex as c_uint, attr as uint64_t) } } /* Memory-managed object interface to type handles. */ diff --git a/src/librustc/middle/trans/base.rs b/src/librustc/middle/trans/base.rs index e208097e99b33..43f3442ec472e 100644 --- a/src/librustc/middle/trans/base.rs +++ b/src/librustc/middle/trans/base.rs @@ -73,7 +73,7 @@ use util::sha2::Sha256; use util::nodemap::NodeMap; use arena::TypedArena; -use libc::c_uint; +use libc::{c_uint, uint64_t}; use std::c_str::ToCStr; use std::cell::{Cell, RefCell}; use std::rc::Rc; @@ -167,6 +167,7 @@ impl<'a> Drop for StatRecorder<'a> { // only use this for foreign function ABIs and glue, use `decl_rust_fn` for Rust functions fn decl_fn(llmod: ModuleRef, name: &str, cc: lib::llvm::CallConv, ty: Type, output: ty::t) -> ValueRef { + let llfn: ValueRef = name.with_c_str(|buf| { unsafe { llvm::LLVMGetOrInsertFunction(llmod, buf, ty.to_ref()) @@ -177,14 +178,9 @@ fn decl_fn(llmod: ModuleRef, name: &str, cc: lib::llvm::CallConv, // functions returning bottom may unwind, but can never return normally ty::ty_bot => { unsafe { - llvm::LLVMAddFunctionAttr(llfn, lib::llvm::NoReturnAttribute as c_uint) - } - } - // `~` pointer return values never alias because ownership is transferred - ty::ty_uniq(..) // | ty::ty_trait(_, _, ty::UniqTraitStore, _, _) - => { - unsafe { - llvm::LLVMAddReturnAttribute(llfn, lib::llvm::NoAliasAttribute as c_uint); + llvm::LLVMAddFunctionAttribute(llfn, + lib::llvm::FunctionIndex as c_uint, + lib::llvm::NoReturnAttribute as uint64_t) } } _ => {} @@ -207,8 +203,8 @@ pub fn decl_cdecl_fn(llmod: ModuleRef, } // only use this for foreign function ABIs and glue, use `get_extern_rust_fn` for Rust functions -pub fn get_extern_fn(externs: &mut ExternMap, - llmod: ModuleRef, +pub fn get_extern_fn(ccx: &CrateContext, + externs: &mut ExternMap, name: &str, cc: lib::llvm::CallConv, ty: Type, @@ -218,19 +214,19 @@ pub fn get_extern_fn(externs: &mut ExternMap, Some(n) => return *n, None => {} } - let f = decl_fn(llmod, name, cc, ty, output); + let f = decl_fn(ccx.llmod, name, cc, ty, output); externs.insert(name.to_strbuf(), f); f } -fn get_extern_rust_fn(ccx: &CrateContext, inputs: &[ty::t], output: ty::t, - name: &str, did: ast::DefId) -> ValueRef { +fn get_extern_rust_fn(ccx: &CrateContext, fn_ty: ty::t, name: &str, did: ast::DefId) -> ValueRef { match ccx.externs.borrow().find_equiv(&name) { Some(n) => return *n, None => () } - let f = decl_rust_fn(ccx, false, inputs, output, name); + let f = decl_rust_fn(ccx, fn_ty, name); + csearch::get_item_attrs(&ccx.sess().cstore, did, |meta_items| { set_llvm_fn_attrs(meta_items.iter().map(|&x| attr::mk_attr_outer(x)) .collect::>().as_slice(), f) @@ -240,72 +236,27 @@ fn get_extern_rust_fn(ccx: &CrateContext, inputs: &[ty::t], output: ty::t, f } -pub fn decl_rust_fn(ccx: &CrateContext, has_env: bool, - inputs: &[ty::t], output: ty::t, - name: &str) -> ValueRef { - use middle::ty::{BrAnon, ReLateBound}; - - let llfty = type_of_rust_fn(ccx, has_env, inputs, output); - let llfn = decl_cdecl_fn(ccx.llmod, name, llfty, output); - - let uses_outptr = type_of::return_uses_outptr(ccx, output); - let offset = if uses_outptr { 1 } else { 0 }; - let offset = if has_env { offset + 1 } else { offset }; - - for (i, &arg_ty) in inputs.iter().enumerate() { - let llarg = unsafe { llvm::LLVMGetParam(llfn, (offset + i) as c_uint) }; - match ty::get(arg_ty).sty { - // `~` pointer parameters never alias because ownership is transferred - ty::ty_uniq(..) => { - unsafe { - llvm::LLVMAddAttribute(llarg, lib::llvm::NoAliasAttribute as c_uint); - } - } - // `&mut` pointer parameters never alias other parameters, or mutable global data - ty::ty_rptr(_, mt) if mt.mutbl == ast::MutMutable => { - unsafe { - llvm::LLVMAddAttribute(llarg, lib::llvm::NoAliasAttribute as c_uint); - } - } - // 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::ty_rptr(ReLateBound(_, BrAnon(_)), _) => { - debug!("marking argument of {} as nocapture because of anonymous lifetime", name); - unsafe { - llvm::LLVMAddAttribute(llarg, lib::llvm::NoCaptureAttribute as c_uint); - } - } - _ => { - // For non-immediate arguments the callee gets its own copy of - // the value on the stack, so there are no aliases - if !type_is_immediate(ccx, arg_ty) { - unsafe { - llvm::LLVMAddAttribute(llarg, lib::llvm::NoAliasAttribute as c_uint); - llvm::LLVMAddAttribute(llarg, lib::llvm::NoCaptureAttribute as c_uint); - } - } - } - } - } +pub fn decl_rust_fn(ccx: &CrateContext, fn_ty: ty::t, name: &str) -> ValueRef { + let (inputs, output, has_env) = match ty::get(fn_ty).sty { + ty::ty_bare_fn(ref f) => (f.sig.inputs.clone(), f.sig.output, false), + ty::ty_closure(ref f) => (f.sig.inputs.clone(), f.sig.output, true), + _ => fail!("expected closure or fn") + }; - // The out pointer will never alias with any other pointers, as the object only exists at a - // language level after the call. It can also be tagged with SRet to indicate that it is - // guaranteed to point to a usable block of memory for the type. - if uses_outptr { + let llfty = type_of_rust_fn(ccx, has_env, inputs.as_slice(), output); + let llfn = decl_fn(ccx.llmod, name, lib::llvm::CCallConv, llfty, output); + let attrs = get_fn_llvm_attributes(ccx, fn_ty); + for &(idx, attr) in attrs.iter() { unsafe { - let outptr = llvm::LLVMGetParam(llfn, 0); - llvm::LLVMAddAttribute(outptr, lib::llvm::StructRetAttribute as c_uint); - llvm::LLVMAddAttribute(outptr, lib::llvm::NoAliasAttribute as c_uint); + llvm::LLVMAddFunctionAttribute(llfn, idx as c_uint, attr); } } llfn } -pub fn decl_internal_rust_fn(ccx: &CrateContext, has_env: bool, - inputs: &[ty::t], output: ty::t, - name: &str) -> ValueRef { - let llfn = decl_rust_fn(ccx, has_env, inputs, output, name); +pub fn decl_internal_rust_fn(ccx: &CrateContext, fn_ty: ty::t, name: &str) -> ValueRef { + let llfn = decl_rust_fn(ccx, fn_ty, name); lib::llvm::SetLinkage(llfn, lib::llvm::InternalLinkage); llfn } @@ -453,7 +404,11 @@ pub fn set_llvm_fn_attrs(attrs: &[ast::Attribute], llfn: ValueRef) { } if contains_name(attrs, "cold") { - unsafe { llvm::LLVMAddColdAttribute(llfn) } + unsafe { + llvm::LLVMAddFunctionAttribute(llfn, + lib::llvm::FunctionIndex as c_uint, + lib::llvm::ColdAttribute as uint64_t) + } } } @@ -463,13 +418,13 @@ pub fn set_always_inline(f: ValueRef) { pub fn set_split_stack(f: ValueRef) { "split-stack".with_c_str(|buf| { - unsafe { llvm::LLVMAddFunctionAttrString(f, buf); } + unsafe { llvm::LLVMAddFunctionAttrString(f, lib::llvm::FunctionIndex as c_uint, buf); } }) } pub fn unset_split_stack(f: ValueRef) { "split-stack".with_c_str(|buf| { - unsafe { llvm::LLVMRemoveFunctionAttrString(f, buf); } + unsafe { llvm::LLVMRemoveFunctionAttrString(f, lib::llvm::FunctionIndex as c_uint, buf); } }) } @@ -485,6 +440,7 @@ pub fn note_unique_llvm_symbol(ccx: &CrateContext, sym: StrBuf) { pub fn get_res_dtor(ccx: &CrateContext, did: ast::DefId, + t: ty::t, parent_id: ast::DefId, substs: &ty::substs) -> ValueRef { @@ -510,13 +466,14 @@ pub fn get_res_dtor(ccx: &CrateContext, let class_ty = ty::subst(tcx, substs, ty::lookup_item_type(tcx, parent_id).ty); let llty = type_of_dtor(ccx, class_ty); - - get_extern_fn(&mut *ccx.externs.borrow_mut(), - ccx.llmod, + let dtor_ty = ty::mk_ctor_fn(ccx.tcx(), ast::DUMMY_NODE_ID, + [glue::get_drop_glue_type(ccx, t)], ty::mk_nil()); + get_extern_fn(ccx, + &mut *ccx.externs.borrow_mut(), name.as_slice(), lib::llvm::CCallConv, llty, - ty::mk_nil()) + dtor_ty) } } @@ -858,11 +815,7 @@ pub fn trans_external_path(ccx: &CrateContext, did: ast::DefId, t: ty::t) -> Val match fn_ty.abi.for_target(ccx.sess().targ_cfg.os, ccx.sess().targ_cfg.arch) { Some(Rust) | Some(RustIntrinsic) => { - get_extern_rust_fn(ccx, - fn_ty.sig.inputs.as_slice(), - fn_ty.sig.output, - name.as_slice(), - did) + get_extern_rust_fn(ccx, t, name.as_slice(), did) } Some(..) | None => { foreign::register_foreign_item_fn(ccx, fn_ty.abi, t, @@ -870,12 +823,8 @@ pub fn trans_external_path(ccx: &CrateContext, did: ast::DefId, t: ty::t) -> Val } } } - ty::ty_closure(ref f) => { - get_extern_rust_fn(ccx, - f.sig.inputs.as_slice(), - f.sig.output, - name.as_slice(), - did) + ty::ty_closure(_) => { + get_extern_rust_fn(ccx, t, name.as_slice(), did) } _ => { let llty = type_of(ccx, t); @@ -891,7 +840,7 @@ pub fn invoke<'a>( bcx: &'a Block<'a>, llfn: ValueRef, llargs: Vec , - attributes: &[(uint, lib::llvm::Attribute)], + fn_ty: ty::t, call_info: Option) -> (ValueRef, &'a Block<'a>) { let _icx = push_ctxt("invoke_"); @@ -899,6 +848,8 @@ pub fn invoke<'a>( return (C_null(Type::i8(bcx.ccx())), bcx); } + let attributes = get_fn_llvm_attributes(bcx.ccx(), fn_ty); + match bcx.opt_node_id { None => { debug!("invoke at ???"); @@ -926,7 +877,7 @@ pub fn invoke<'a>( llargs.as_slice(), normal_bcx.llbb, landing_pad, - attributes); + attributes.as_slice()); return (llresult, normal_bcx); } else { debug!("calling {} at {}", llfn, bcx.llbb); @@ -939,7 +890,7 @@ pub fn invoke<'a>( None => debuginfo::clear_source_location(bcx.fcx) }; - let llresult = Call(bcx, llfn, llargs.as_slice(), attributes); + let llresult = Call(bcx, llfn, llargs.as_slice(), attributes.as_slice()); return (llresult, bcx); } } @@ -1708,34 +1659,132 @@ fn register_fn(ccx: &CrateContext, node_id: ast::NodeId, node_type: ty::t) -> ValueRef { - let f = match ty::get(node_type).sty { + match ty::get(node_type).sty { ty::ty_bare_fn(ref f) => { assert!(f.abi == Rust || f.abi == RustIntrinsic); - f } _ => fail!("expected bare rust fn or an intrinsic") }; - let llfn = decl_rust_fn(ccx, - false, - f.sig.inputs.as_slice(), - f.sig.output, - sym.as_slice()); + let llfn = decl_rust_fn(ccx, node_type, sym.as_slice()); finish_register_fn(ccx, sp, sym, node_id, llfn); llfn } +pub fn get_fn_llvm_attributes(ccx: &CrateContext, fn_ty: ty::t) -> Vec<(uint, u64)> { + use middle::ty::{BrAnon, ReLateBound}; + + let (fn_sig, has_env) = match ty::get(fn_ty).sty { + ty::ty_closure(ref f) => (f.sig.clone(), true), + ty::ty_bare_fn(ref f) => (f.sig.clone(), false), + _ => fail!("expected closure or function.") + }; + + // Since index 0 is the return value of the llvm func, we start + // at either 1 or 2 depending on whether there's an env slot or not + let mut first_arg_offset = if has_env { 2 } else { 1 }; + let mut attrs = Vec::new(); + let ret_ty = fn_sig.output; + + // A function pointer is called without the declaration + // available, so we have to apply any attributes with ABI + // implications directly to the call instruction. Right now, + // the only attribute we need to worry about is `sret`. + if type_of::return_uses_outptr(ccx, ret_ty) { + attrs.push((1, lib::llvm::StructRetAttribute as u64)); + + // The outptr can be noalias and nocapture because it's entirely + // invisible to the program. We can also mark it as nonnull + attrs.push((1, lib::llvm::NoAliasAttribute as u64)); + attrs.push((1, lib::llvm::NoCaptureAttribute as u64)); + attrs.push((1, lib::llvm::NonNullAttribute as u64)); + + // Add one more since there's an outptr + first_arg_offset += 1; + } else { + // The `noalias` attribute on the return value is useful to a + // function ptr caller. + match ty::get(ret_ty).sty { + // `~` pointer return values never alias because ownership + // is transferred + ty::ty_uniq(_) => { + attrs.push((lib::llvm::ReturnIndex as uint, lib::llvm::NoAliasAttribute as u64)); + } + _ => {} + } + + // We can also mark the return value as `nonnull` in certain cases + match ty::get(ret_ty).sty { + // These are not really pointers but pairs, (pointer, len) + ty::ty_rptr(_, ty::mt { ty: it, .. }) | + ty::ty_rptr(_, ty::mt { ty: it, .. }) if match ty::get(it).sty { + ty::ty_str | ty::ty_vec(..) => true, _ => false + } => {} + ty::ty_uniq(_) | ty::ty_rptr(_, _) => { + attrs.push((lib::llvm::ReturnIndex as uint, lib::llvm::NonNullAttribute as u64)); + } + _ => {} + } + } + + for (idx, &t) in fn_sig.inputs.iter().enumerate().map(|(i, v)| (i + first_arg_offset, v)) { + match ty::get(t).sty { + // `~` pointer parameters never alias because ownership is transferred + ty::ty_uniq(_) => { + attrs.push((idx, lib::llvm::NoAliasAttribute as u64)); + attrs.push((idx, lib::llvm::NonNullAttribute as u64)); + } + // These are not really pointers but pairs, (pointer, len) + ty::ty_rptr(_, ty::mt { ty: it, .. }) | + ty::ty_rptr(_, ty::mt { ty: it, .. }) if match ty::get(it).sty { + ty::ty_str | ty::ty_vec(..) => true, _ => false + } => {} + // `&mut` pointer parameters never alias other parameters, or mutable global data + ty::ty_rptr(b, mt) if mt.mutbl == ast::MutMutable => { + attrs.push((idx, lib::llvm::NoAliasAttribute as u64)); + attrs.push((idx, lib::llvm::NonNullAttribute as u64)); + match b { + ReLateBound(_, BrAnon(_)) => { + attrs.push((idx, lib::llvm::NoCaptureAttribute as u64)); + } + _ => {} + } + } + // 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::ty_rptr(ReLateBound(_, BrAnon(_)), _) => { + attrs.push((idx, lib::llvm::NoCaptureAttribute as u64)); + attrs.push((idx, lib::llvm::NonNullAttribute as u64)); + } + // & pointer parameters are never null + ty::ty_rptr(_, _) => { + attrs.push((idx, lib::llvm::NonNullAttribute as u64)); + } + _ => { + // For non-immediate arguments the callee gets its own copy of + // the value on the stack, so there are no aliases. It's also + // program-invisible so can't possibly capture + if !type_is_immediate(ccx, t) { + attrs.push((idx, lib::llvm::NoAliasAttribute as u64)); + attrs.push((idx, lib::llvm::NoCaptureAttribute as u64)); + } + } + } + } + + attrs +} + // only use this for foreign function ABIs and glue, use `register_fn` for Rust functions pub fn register_fn_llvmty(ccx: &CrateContext, sp: Span, sym: StrBuf, node_id: ast::NodeId, cc: lib::llvm::CallConv, - fn_ty: Type, - output: ty::t) -> ValueRef { + llfty: Type) -> ValueRef { debug!("register_fn_llvmty id={} sym={}", node_id, sym); - let llfn = decl_fn(ccx.llmod, sym.as_slice(), cc, fn_ty, output); + let llfn = decl_fn(ccx.llmod, sym.as_slice(), cc, llfty, ty::mk_nil()); finish_register_fn(ccx, sp, sym, node_id, llfn); llfn } diff --git a/src/librustc/middle/trans/build.rs b/src/librustc/middle/trans/build.rs index bc4a2d9f96fb0..b0a73c4e6f791 100644 --- a/src/librustc/middle/trans/build.rs +++ b/src/librustc/middle/trans/build.rs @@ -113,7 +113,7 @@ pub fn Invoke(cx: &Block, args: &[ValueRef], then: BasicBlockRef, catch: BasicBlockRef, - attributes: &[(uint, lib::llvm::Attribute)]) + attributes: &[(uint, u64)]) -> ValueRef { if cx.unreachable.get() { return C_null(Type::i8(cx.ccx())); @@ -679,13 +679,13 @@ pub fn InlineAsmCall(cx: &Block, asm: *c_char, cons: *c_char, } pub fn Call(cx: &Block, fn_: ValueRef, args: &[ValueRef], - attributes: &[(uint, lib::llvm::Attribute)]) -> ValueRef { + attributes: &[(uint, u64)]) -> ValueRef { if cx.unreachable.get() { return _UndefReturn(cx, fn_); } B(cx).call(fn_, args, attributes) } pub fn CallWithConv(cx: &Block, fn_: ValueRef, args: &[ValueRef], conv: CallConv, - attributes: &[(uint, lib::llvm::Attribute)]) -> ValueRef { + attributes: &[(uint, u64)]) -> ValueRef { if cx.unreachable.get() { return _UndefReturn(cx, fn_); } B(cx).call_with_conv(fn_, args, conv, attributes) } diff --git a/src/librustc/middle/trans/builder.rs b/src/librustc/middle/trans/builder.rs index f82a609d69572..278e586c6ac16 100644 --- a/src/librustc/middle/trans/builder.rs +++ b/src/librustc/middle/trans/builder.rs @@ -156,7 +156,7 @@ impl<'a> Builder<'a> { args: &[ValueRef], then: BasicBlockRef, catch: BasicBlockRef, - attributes: &[(uint, lib::llvm::Attribute)]) + attributes: &[(uint, u64)]) -> ValueRef { self.count_insn("invoke"); unsafe { @@ -168,7 +168,7 @@ impl<'a> Builder<'a> { catch, noname()); for &(idx, attr) in attributes.iter() { - llvm::LLVMAddInstrAttribute(v, idx as c_uint, attr as c_uint); + llvm::LLVMAddCallSiteAttribute(v, idx as c_uint, attr); } v } @@ -799,7 +799,7 @@ impl<'a> Builder<'a> { } pub fn call(&self, llfn: ValueRef, args: &[ValueRef], - attributes: &[(uint, lib::llvm::Attribute)]) -> ValueRef { + attributes: &[(uint, u64)]) -> ValueRef { self.count_insn("call"); debug!("Call {} with args ({})", @@ -813,14 +813,14 @@ impl<'a> Builder<'a> { let v = llvm::LLVMBuildCall(self.llbuilder, llfn, args.as_ptr(), args.len() as c_uint, noname()); for &(idx, attr) in attributes.iter() { - llvm::LLVMAddInstrAttribute(v, idx as c_uint, attr as c_uint); + llvm::LLVMAddCallSiteAttribute(v, idx as c_uint, attr); } v } } pub fn call_with_conv(&self, llfn: ValueRef, args: &[ValueRef], - conv: CallConv, attributes: &[(uint, lib::llvm::Attribute)]) -> ValueRef { + conv: CallConv, attributes: &[(uint, u64)]) -> ValueRef { self.count_insn("callwithconv"); let v = self.call(llfn, args, attributes); lib::llvm::SetInstructionCallConv(v, conv); diff --git a/src/librustc/middle/trans/callee.rs b/src/librustc/middle/trans/callee.rs index fe9581c638e77..90600ea2d3b2f 100644 --- a/src/librustc/middle/trans/callee.rs +++ b/src/librustc/middle/trans/callee.rs @@ -18,7 +18,7 @@ use back::abi; use driver::session; -use lib::llvm::{ValueRef, NoAliasAttribute, StructRetAttribute, NoCaptureAttribute}; +use lib::llvm::ValueRef; use lib::llvm::llvm; use metadata::csearch; use middle::trans::base; @@ -614,13 +614,9 @@ pub fn trans_call_inner<'a>( llargs.push(opt_llretslot.unwrap()); } - // start at 1, because index 0 is the return value of the llvm func - let mut first_arg_offset = 1; - // Push the environment (or a trait object's self). match (llenv, llself) { (Some(llenv), None) => { - first_arg_offset += 1; llargs.push(llenv) }, (None, Some(llself)) => llargs.push(llself), @@ -634,61 +630,11 @@ pub fn trans_call_inner<'a>( fcx.pop_custom_cleanup_scope(arg_cleanup_scope); - // A function pointer is called without the declaration - // available, so we have to apply any attributes with ABI - // implications directly to the call instruction. Right now, - // the only attribute we need to worry about is `sret`. - let mut attrs = Vec::new(); - if type_of::return_uses_outptr(ccx, ret_ty) { - attrs.push((1, StructRetAttribute)); - // The outptr can be noalias and nocapture because it's entirely - // invisible to the program. - attrs.push((1, NoAliasAttribute)); - attrs.push((1, NoCaptureAttribute)); - first_arg_offset += 1; - } - - // The `noalias` attribute on the return value is useful to a - // function ptr caller. - match ty::get(ret_ty).sty { - // `~` pointer return values never alias because ownership - // is transferred - ty::ty_uniq(ty) => match ty::get(ty).sty { - ty::ty_str => {} - _ => attrs.push((0, NoAliasAttribute)), - }, - _ => {} - } - - debug!("trans_callee_inner: first_arg_offset={}", first_arg_offset); - - for (idx, &t) in ty::ty_fn_args(callee_ty).iter().enumerate() - .map(|(i, v)| (i+first_arg_offset, v)) { - use middle::ty::{BrAnon, ReLateBound}; - if !type_is_immediate(ccx, t) { - // if it's not immediate, we have a program-invisible pointer, - // which it can't possibly capture - attrs.push((idx, NoCaptureAttribute)); - debug!("trans_callee_inner: argument {} nocapture because it's non-immediate", idx); - continue; - } - - let t_ = ty::get(t); - match t_.sty { - ty::ty_rptr(ReLateBound(_, BrAnon(_)), _) => { - debug!("trans_callee_inner: argument {} nocapture because \ - of anonymous lifetime", idx); - attrs.push((idx, NoCaptureAttribute)); - }, - _ => { } - } - } - // Invoke the actual rust fn and update bcx/llresult. let (llret, b) = base::invoke(bcx, llfn, llargs, - attrs.as_slice(), + callee_ty, call_info); bcx = b; llresult = llret; diff --git a/src/librustc/middle/trans/closure.rs b/src/librustc/middle/trans/closure.rs index c804cb77fb29d..5fe6c234579bb 100644 --- a/src/librustc/middle/trans/closure.rs +++ b/src/librustc/middle/trans/closure.rs @@ -340,21 +340,12 @@ pub fn trans_expr_fn<'a>( }; let ccx = bcx.ccx(); - let fty = node_id_type(bcx, id); - let f = match ty::get(fty).sty { - ty::ty_closure(ref f) => f, - _ => fail!("expected closure") - }; - let tcx = bcx.tcx(); + let fty = node_id_type(bcx, id); let s = tcx.map.with_path(id, |path| { mangle_internal_name_by_path_and_seq(path, "closure") }); - let llfn = decl_internal_rust_fn(ccx, - true, - f.sig.inputs.as_slice(), - f.sig.output, - s.as_slice()); + let llfn = decl_internal_rust_fn(ccx, fty, s.as_slice()); // set an inline hint for all closures set_inline_hint(llfn); @@ -414,17 +405,9 @@ pub fn get_wrapper_for_bare_fn(ccx: &CrateContext, mangle_internal_name_by_path_and_seq(path, "as_closure") }); let llfn = if is_local { - decl_internal_rust_fn(ccx, - true, - f.sig.inputs.as_slice(), - f.sig.output, - name.as_slice()) + decl_internal_rust_fn(ccx, closure_ty, name.as_slice()) } else { - decl_rust_fn(ccx, - true, - f.sig.inputs.as_slice(), - f.sig.output, - name.as_slice()) + decl_rust_fn(ccx, closure_ty, name.as_slice()) }; ccx.closure_bare_wrapper_cache.borrow_mut().insert(fn_ptr, llfn); diff --git a/src/librustc/middle/trans/foreign.rs b/src/librustc/middle/trans/foreign.rs index e08ab33808ac9..f723a4556b9a3 100644 --- a/src/librustc/middle/trans/foreign.rs +++ b/src/librustc/middle/trans/foreign.rs @@ -227,12 +227,12 @@ pub fn register_foreign_item_fn(ccx: &CrateContext, abi: Abi, fty: ty::t, // Create the LLVM value for the C extern fn let llfn_ty = lltype_for_fn_from_foreign_types(ccx, &tys); - let llfn = base::get_extern_fn(&mut *ccx.externs.borrow_mut(), - ccx.llmod, + let llfn = base::get_extern_fn(ccx, + &mut *ccx.externs.borrow_mut(), name, cc, llfn_ty, - tys.fn_sig.output); + fty); add_argument_attributes(&tys, llfn); llfn @@ -378,17 +378,21 @@ pub fn trans_native_call<'a>( // A function pointer is called without the declaration available, so we have to apply // any attributes with ABI implications directly to the call instruction. Right now, the // only attribute we need to worry about is `sret`. - let sret_attr = if fn_type.ret_ty.is_indirect() { - Some((1, StructRetAttribute)) - } else { - None + let mut attrs = Vec::new(); + if fn_type.ret_ty.is_indirect() { + attrs.push((1, lib::llvm::StructRetAttribute as u64)); + + // The outptr can be noalias and nocapture because it's entirely + // invisible to the program. We can also mark it as nonnull + attrs.push((1, lib::llvm::NoAliasAttribute as u64)); + attrs.push((1, lib::llvm::NoCaptureAttribute as u64)); + attrs.push((1, lib::llvm::NonNullAttribute as u64)); }; - let attrs = sret_attr.as_slice(); let llforeign_retval = CallWithConv(bcx, llfn, llargs_foreign.as_slice(), cc, - attrs); + attrs.as_slice()); // If the function we just called does not use an outpointer, // store the result into the rust outpointer. Cast the outpointer @@ -500,14 +504,14 @@ pub fn register_rust_fn_with_foreign_abi(ccx: &CrateContext, let tys = foreign_types_for_id(ccx, node_id); let llfn_ty = lltype_for_fn_from_foreign_types(ccx, &tys); let t = ty::node_id_to_type(ccx.tcx(), node_id); - let (cconv, output) = match ty::get(t).sty { + let cconv = match ty::get(t).sty { ty::ty_bare_fn(ref fn_ty) => { let c = llvm_calling_convention(ccx, fn_ty.abi); - (c.unwrap_or(lib::llvm::CCallConv), fn_ty.sig.output) + c.unwrap_or(lib::llvm::CCallConv) } _ => fail!("expected bare fn in register_rust_fn_with_foreign_abi") }; - let llfn = base::register_fn_llvmty(ccx, sp, sym, node_id, cconv, llfn_ty, output); + let llfn = base::register_fn_llvmty(ccx, sp, sym, node_id, cconv, llfn_ty); add_argument_attributes(&tys, llfn); debug!("register_rust_fn_with_foreign_abi(node_id={:?}, llfn_ty={}, llfn={})", node_id, ccx.tn.type_to_str(llfn_ty), ccx.tn.val_to_str(llfn)); @@ -528,7 +532,7 @@ pub fn trans_rust_fn_with_foreign_abi(ccx: &CrateContext, let llrustfn = build_rust_fn(ccx, decl, body, attrs, id); // Build up the foreign wrapper (`foo` above). - return build_wrap_fn(ccx, llrustfn, llwrapfn, &tys); + return build_wrap_fn(ccx, llrustfn, llwrapfn, &tys, id); } fn build_rust_fn(ccx: &CrateContext, @@ -548,10 +552,9 @@ pub fn trans_rust_fn_with_foreign_abi(ccx: &CrateContext, // Compute the type that the function would have if it were just a // normal Rust function. This will be the type of the wrappee fn. - let f = match ty::get(t).sty { + match ty::get(t).sty { ty::ty_bare_fn(ref f) => { assert!(f.abi != Rust && f.abi != RustIntrinsic); - f } _ => { ccx.sess().bug(format!("build_rust_fn: extern fn {} has ty {}, \ @@ -565,11 +568,7 @@ pub fn trans_rust_fn_with_foreign_abi(ccx: &CrateContext, ccx.tcx.map.path_to_str(id), id, t.repr(tcx)); - let llfn = base::decl_internal_rust_fn(ccx, - false, - f.sig.inputs.as_slice(), - f.sig.output, - ps.as_slice()); + let llfn = base::decl_internal_rust_fn(ccx, t, ps.as_slice()); base::set_llvm_fn_attrs(attrs, llfn); base::trans_fn(ccx, decl, body, llfn, None, id, []); llfn @@ -578,14 +577,18 @@ pub fn trans_rust_fn_with_foreign_abi(ccx: &CrateContext, unsafe fn build_wrap_fn(ccx: &CrateContext, llrustfn: ValueRef, llwrapfn: ValueRef, - tys: &ForeignTypes) { + tys: &ForeignTypes, + id: ast::NodeId) { let _icx = push_ctxt( "foreign::trans_rust_fn_with_foreign_abi::build_wrap_fn"); let tcx = ccx.tcx(); - debug!("build_wrap_fn(llrustfn={}, llwrapfn={})", + let t = ty::node_id_to_type(tcx, id); + + debug!("build_wrap_fn(llrustfn={}, llwrapfn={}, t={})", ccx.tn.val_to_str(llrustfn), - ccx.tn.val_to_str(llwrapfn)); + ccx.tn.val_to_str(llwrapfn), + t.repr(ccx.tcx())); // Avoid all the Rust generation stuff and just generate raw // LLVM here. @@ -731,10 +734,15 @@ pub fn trans_rust_fn_with_foreign_abi(ccx: &CrateContext, } // Perform the call itself - debug!("calling llrustfn = {}", ccx.tn.val_to_str(llrustfn)); + debug!("calling llrustfn = {}, t = {}", ccx.tn.val_to_str(llrustfn), t.repr(ccx.tcx())); let llrust_ret_val = llvm::LLVMBuildCall(builder, llrustfn, llrust_args.as_ptr(), llrust_args.len() as c_uint, noname()); + let attributes = base::get_fn_llvm_attributes(ccx, t); + for &(idx, attr) in attributes.iter() { + llvm::LLVMAddCallSiteAttribute(llrust_ret_val, idx as c_uint, attr); + } + // Get the return value where the foreign fn expects it. let llforeign_ret_ty = match tys.fn_ty.ret_ty.cast { Some(ty) => ty, diff --git a/src/librustc/middle/trans/glue.rs b/src/librustc/middle/trans/glue.rs index c103a44aa7543..6d269756931f7 100644 --- a/src/librustc/middle/trans/glue.rs +++ b/src/librustc/middle/trans/glue.rs @@ -88,7 +88,7 @@ pub fn take_ty<'a>(bcx: &'a Block<'a>, v: ValueRef, t: ty::t) } } -fn get_drop_glue_type(ccx: &CrateContext, t: ty::t) -> ty::t { +pub fn get_drop_glue_type(ccx: &CrateContext, t: ty::t) -> ty::t { let tcx = ccx.tcx(); if !ty::type_needs_drop(tcx, t) { return ty::mk_i8(); @@ -248,7 +248,7 @@ fn trans_struct_drop<'a>(bcx: &'a Block<'a>, let repr = adt::represent_type(bcx.ccx(), t); // Find and call the actual destructor - let dtor_addr = get_res_dtor(bcx.ccx(), dtor_did, + let dtor_addr = get_res_dtor(bcx.ccx(), dtor_did, t, class_did, substs); // The second argument is the "self" argument for drop @@ -279,7 +279,9 @@ fn trans_struct_drop<'a>(bcx: &'a Block<'a>, fld.mt.ty); } - let (_, bcx) = invoke(bcx, dtor_addr, args, [], None); + let dtor_ty = ty::mk_ctor_fn(bcx.tcx(), ast::DUMMY_NODE_ID, + [get_drop_glue_type(bcx.ccx(), t)], ty::mk_nil()); + let (_, bcx) = invoke(bcx, dtor_addr, args, dtor_ty, None); bcx.fcx.pop_and_trans_custom_cleanup_scope(bcx, field_scope) } @@ -459,10 +461,7 @@ fn declare_generic_glue(ccx: &CrateContext, t: ty::t, llfnty: Type, t, format!("glue_{}", name).as_slice()); debug!("{} is for type {}", fn_nm, ppaux::ty_to_str(ccx.tcx(), t)); - let llfn = decl_cdecl_fn(ccx.llmod, - fn_nm.as_slice(), - llfnty, - ty::mk_nil()); + let llfn = decl_cdecl_fn(ccx.llmod, fn_nm.as_slice(), llfnty, ty::mk_nil()); note_unique_llvm_symbol(ccx, fn_nm); return llfn; } diff --git a/src/librustc/middle/trans/monomorphize.rs b/src/librustc/middle/trans/monomorphize.rs index 3076a19228c39..e0fd872fb06a7 100644 --- a/src/librustc/middle/trans/monomorphize.rs +++ b/src/librustc/middle/trans/monomorphize.rs @@ -172,14 +172,6 @@ pub fn monomorphic_fn(ccx: &CrateContext, } }; - let f = match ty::get(mono_ty).sty { - ty::ty_bare_fn(ref f) => { - assert!(f.abi == abi::Rust || f.abi == abi::RustIntrinsic); - f - } - _ => fail!("expected bare rust fn or an intrinsic") - }; - ccx.stats.n_monos.set(ccx.stats.n_monos.get() + 1); let depth; @@ -214,11 +206,7 @@ pub fn monomorphic_fn(ccx: &CrateContext, // This shouldn't need to option dance. let mut hash_id = Some(hash_id); let mk_lldecl = || { - let lldecl = decl_internal_rust_fn(ccx, - false, - f.sig.inputs.as_slice(), - f.sig.output, - s.as_slice()); + let lldecl = decl_internal_rust_fn(ccx, mono_ty, s.as_slice()); ccx.monomorphized.borrow_mut().insert(hash_id.take_unwrap(), lldecl); lldecl }; diff --git a/src/librustc/middle/trans/reflect.rs b/src/librustc/middle/trans/reflect.rs index a65802d2c36ff..f5f3d4366f6e0 100644 --- a/src/librustc/middle/trans/reflect.rs +++ b/src/librustc/middle/trans/reflect.rs @@ -291,10 +291,10 @@ impl<'a, 'b> Reflector<'a, 'b> { let sym = mangle_internal_name_by_path_and_seq( ast_map::Values([].iter()).chain(None), "get_disr"); + let fn_ty = ty::mk_ctor_fn(&ccx.tcx, ast::DUMMY_NODE_ID, + [opaqueptrty], ty::mk_u64()); let llfdecl = decl_internal_rust_fn(ccx, - false, - [opaqueptrty], - ty::mk_u64(), + fn_ty, sym.as_slice()); let arena = TypedArena::new(); let fcx = new_fn_ctxt(ccx, llfdecl, -1, false, diff --git a/src/llvm b/src/llvm index 4b4d0533b4f76..0a894645cf120 160000 --- a/src/llvm +++ b/src/llvm @@ -1 +1 @@ -Subproject commit 4b4d0533b4f76cc3fbba31bd9e7ac02e0c738b1d +Subproject commit 0a894645cf120539876e9eb4eb0d7b572dfa9d14 diff --git a/src/rustllvm/PassWrapper.cpp b/src/rustllvm/PassWrapper.cpp index 64776421fa145..195b044ccdcef 100644 --- a/src/rustllvm/PassWrapper.cpp +++ b/src/rustllvm/PassWrapper.cpp @@ -13,6 +13,7 @@ #include "rustllvm.h" #include "llvm/Support/CBindingWrapping.h" +#include "llvm/Support/FileSystem.h" #include "llvm/Target/TargetLibraryInfo.h" #include "llvm/Transforms/IPO/PassManagerBuilder.h" diff --git a/src/rustllvm/RustWrapper.cpp b/src/rustllvm/RustWrapper.cpp index 717cd333a79ce..2157aecf37613 100644 --- a/src/rustllvm/RustWrapper.cpp +++ b/src/rustllvm/RustWrapper.cpp @@ -12,6 +12,12 @@ #include "llvm/Object/Archive.h" #include "llvm/Object/ObjectFile.h" +#if LLVM_VERSION_MINOR >= 5 +#include "llvm/IR/CallSite.h" +#else +#include "llvm/Support/CallSite.h" +#endif + //===----------------------------------------------------------------------=== // // This file defines alternate interfaces to core functions that are more @@ -83,46 +89,43 @@ extern "C" LLVMTypeRef LLVMMetadataTypeInContext(LLVMContextRef C) { return wrap(Type::getMetadataTy(*unwrap(C))); } -extern "C" void LLVMAddFunctionAttrString(LLVMValueRef fn, const char *Name) { - unwrap(fn)->addFnAttr(Name); +extern "C" void LLVMAddCallSiteAttribute(LLVMValueRef Instr, unsigned index, uint64_t Val) { + CallSite Call = CallSite(unwrap(Instr)); + AttrBuilder B; + B.addRawValue(Val); + Call.setAttributes( + Call.getAttributes().addAttributes(Call->getContext(), index, + AttributeSet::get(Call->getContext(), + index, B))); +} + +extern "C" void LLVMAddFunctionAttribute(LLVMValueRef Fn, unsigned index, uint64_t Val) { + Function *A = unwrap(Fn); + AttrBuilder B; + B.addRawValue(Val); + A->addAttributes(index, AttributeSet::get(A->getContext(), index, B)); +} + +extern "C" void LLVMAddFunctionAttrString(LLVMValueRef Fn, unsigned index, const char *Name) { + Function *F = unwrap(Fn); + AttrBuilder B; + B.addAttribute(Name); + F->addAttributes(index, AttributeSet::get(F->getContext(), index, B)); } -extern "C" void LLVMRemoveFunctionAttrString(LLVMValueRef fn, const char *Name) { +extern "C" void LLVMRemoveFunctionAttrString(LLVMValueRef fn, unsigned index, const char *Name) { Function *f = unwrap(fn); LLVMContext &C = f->getContext(); AttrBuilder B; B.addAttribute(Name); - AttributeSet to_remove = AttributeSet::get(C, AttributeSet::FunctionIndex, B); + AttributeSet to_remove = AttributeSet::get(C, index, B); AttributeSet attrs = f->getAttributes(); f->setAttributes(attrs.removeAttributes(f->getContext(), - AttributeSet::FunctionIndex, + index, to_remove)); } -extern "C" void LLVMAddReturnAttribute(LLVMValueRef Fn, LLVMAttribute PA) { - Function *A = unwrap(Fn); - AttrBuilder B(PA); - A->addAttributes(AttributeSet::ReturnIndex, - AttributeSet::get(A->getContext(), AttributeSet::ReturnIndex, B)); -} - -extern "C" void LLVMRemoveReturnAttribute(LLVMValueRef Fn, LLVMAttribute PA) { - Function *A = unwrap(Fn); - AttrBuilder B(PA); - A->removeAttributes(AttributeSet::ReturnIndex, - AttributeSet::get(A->getContext(), AttributeSet::ReturnIndex, B)); -} - -#if LLVM_VERSION_MINOR >= 5 -extern "C" void LLVMAddColdAttribute(LLVMValueRef Fn) { - Function *A = unwrap(Fn); - A->addAttribute(AttributeSet::FunctionIndex, Attribute::Cold); -} -#else -extern "C" void LLVMAddColdAttribute(LLVMValueRef Fn) {} -#endif - extern "C" LLVMValueRef LLVMBuildAtomicLoad(LLVMBuilderRef B, LLVMValueRef source, const char* Name, diff --git a/src/rustllvm/llvm-auto-clean-trigger b/src/rustllvm/llvm-auto-clean-trigger index 340a491527710..4e599ad115db3 100644 --- a/src/rustllvm/llvm-auto-clean-trigger +++ b/src/rustllvm/llvm-auto-clean-trigger @@ -1,4 +1,4 @@ # If this file is modified, then llvm will be forcibly cleaned and then rebuilt. # The actual contents of this file do not matter, but to trigger a change on the # build bots then the contents should be changed so git updates the mtime. -2014-04-14 +2014-05-20