summaryrefslogtreecommitdiff
path: root/src/librustc_trans/trans/attributes.rs
diff options
context:
space:
mode:
Diffstat (limited to 'src/librustc_trans/trans/attributes.rs')
-rw-r--r--src/librustc_trans/trans/attributes.rs205
1 files changed, 5 insertions, 200 deletions
diff --git a/src/librustc_trans/trans/attributes.rs b/src/librustc_trans/trans/attributes.rs
index d93d32f8e0d..99dc3ade823 100644
--- a/src/librustc_trans/trans/attributes.rs
+++ b/src/librustc_trans/trans/attributes.rs
@@ -10,20 +10,11 @@
//! Set and unset common attributes on LLVM values.
use libc::{c_uint, c_ulonglong};
-use llvm::{self, ValueRef, AttrHelper};
-use middle::ty;
-use middle::infer;
-use middle::traits::ProjectionMode;
+use llvm::{self, ValueRef};
use session::config::NoDebugInfo;
-use syntax::abi::Abi;
pub use syntax::attr::InlineAttr;
use syntax::ast;
-use rustc_front::hir;
-use trans::base;
-use trans::common;
use trans::context::CrateContext;
-use trans::machine;
-use trans::type_of;
/// Mark LLVM function to use provided inline heuristic.
#[inline]
@@ -112,199 +103,13 @@ pub fn from_fn_attrs(ccx: &CrateContext, attrs: &[ast::Attribute], llfn: ValueRe
for attr in attrs {
if attr.check_name("cold") {
- unsafe {
- llvm::LLVMAddFunctionAttribute(llfn,
- llvm::FunctionIndex as c_uint,
- llvm::ColdAttribute as u64)
- }
+ llvm::Attributes::default().set(llvm::Attribute::Cold)
+ .apply_llfn(llvm::FunctionIndex as usize, llfn)
} else if attr.check_name("allocator") {
- llvm::Attribute::NoAlias.apply_llfn(llvm::ReturnIndex as c_uint, llfn);
+ llvm::Attributes::default().set(llvm::Attribute::NoAlias)
+ .apply_llfn(llvm::ReturnIndex as usize, llfn)
} else if attr.check_name("unwind") {
unwind(llfn, true);
}
}
}
-
-/// Composite function which converts function type into LLVM attributes for the function.
-pub fn from_fn_type<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, fn_type: ty::Ty<'tcx>)
- -> llvm::AttrBuilder {
- use middle::ty::{BrAnon, ReLateBound};
-
- let function_type;
- let (fn_sig, abi, env_ty) = match fn_type.sty {
- ty::TyFnDef(_, _, ref f) | ty::TyFnPtr(ref f) => (&f.sig, f.abi, None),
- ty::TyClosure(closure_did, ref substs) => {
- let infcx = infer::normalizing_infer_ctxt(ccx.tcx(),
- &ccx.tcx().tables,
- ProjectionMode::Any);
- function_type = infcx.closure_type(closure_did, substs);
- let self_type = base::self_type_for_closure(ccx, closure_did, fn_type);
- (&function_type.sig, Abi::RustCall, Some(self_type))
- }
- _ => ccx.sess().bug("expected closure or function.")
- };
-
- let fn_sig = ccx.tcx().erase_late_bound_regions(fn_sig);
- let fn_sig = infer::normalize_associated_type(ccx.tcx(), &fn_sig);
-
- let mut attrs = llvm::AttrBuilder::new();
- let ret_ty = fn_sig.output;
-
- // These have an odd calling convention, so we need to manually
- // unpack the input ty's
- let input_tys = match fn_type.sty {
- ty::TyClosure(..) => {
- assert!(abi == Abi::RustCall);
-
- match fn_sig.inputs[0].sty {
- ty::TyTuple(ref inputs) => {
- let mut full_inputs = vec![env_ty.expect("Missing closure environment")];
- full_inputs.extend_from_slice(inputs);
- full_inputs
- }
- _ => ccx.sess().bug("expected tuple'd inputs")
- }
- },
- ty::TyFnDef(..) | ty::TyFnPtr(_) if abi == Abi::RustCall => {
- let mut inputs = vec![fn_sig.inputs[0]];
-
- match fn_sig.inputs[1].sty {
- ty::TyTuple(ref t_in) => {
- inputs.extend_from_slice(&t_in[..]);
- inputs
- }
- _ => ccx.sess().bug("expected tuple'd inputs")
- }
- }
- _ => fn_sig.inputs.clone()
- };
-
- // Index 0 is the return value of the llvm func, so we start at 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
- // 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) {
- let llret_sz = machine::llsize_of_real(ccx, type_of::type_of(ccx, ret_ty));
-
- // The outptr can be noalias and nocapture because it's entirely
- // invisible to the program. We also know it's nonnull as well
- // as how many bytes we can dereference
- attrs.arg(1, llvm::Attribute::StructRet)
- .arg(1, llvm::Attribute::NoAlias)
- .arg(1, llvm::Attribute::NoCapture)
- .arg(1, llvm::DereferenceableAttribute(llret_sz));
-
- // Add one more since there's an outptr
- idx += 1;
- } else {
- // The `noalias` attribute on the return value is useful to a
- // function ptr caller.
- match ret_ty.sty {
- // `Box` pointer return values never alias because ownership
- // is transferred
- ty::TyBox(it) if common::type_is_sized(ccx.tcx(), it) => {
- attrs.ret(llvm::Attribute::NoAlias);
- }
- _ => {}
- }
-
- // We can also mark the return value as `dereferenceable` in certain cases
- match ret_ty.sty {
- // These are not really pointers but pairs, (pointer, len)
- ty::TyRef(_, ty::TypeAndMut { ty: inner, .. })
- | ty::TyBox(inner) if common::type_is_sized(ccx.tcx(), inner) => {
- let llret_sz = machine::llsize_of_real(ccx, type_of::type_of(ccx, inner));
- attrs.ret(llvm::DereferenceableAttribute(llret_sz));
- }
- _ => {}
- }
-
- if let ty::TyBool = ret_ty.sty {
- attrs.ret(llvm::Attribute::ZExt);
- }
- }
- }
-
- for &t in input_tys.iter() {
- match t.sty {
- _ 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
- // the value on the stack, so there are no aliases. It's also
- // program-invisible so can't possibly capture
- attrs.arg(idx, llvm::Attribute::NoAlias)
- .arg(idx, llvm::Attribute::NoCapture)
- .arg(idx, llvm::DereferenceableAttribute(llarg_sz));
- }
-
- ty::TyBool => {
- attrs.arg(idx, llvm::Attribute::ZExt);
- }
-
- // `Box` pointer parameters never alias because ownership is transferred
- ty::TyBox(inner) => {
- 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 inner.is_trait() {
- attrs.arg(idx + 1, llvm::NonNullAttribute);
- }
- }
- }
-
- ty::TyRef(b, mt) => {
- // `&mut` pointer parameters never alias other parameters, or mutable global data
- //
- // `&T` where `T` contains no `UnsafeCell<U>` 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 = mt.ty.type_contents(ccx.tcx()).interior_unsafe();
-
- if mt.mutbl != hir::MutMutable && !interior_unsafe {
- attrs.arg(idx, llvm::Attribute::NoAlias);
- }
-
- if mt.mutbl == hir::MutImmutable && !interior_unsafe {
- attrs.arg(idx, llvm::Attribute::ReadOnly);
- }
-
- // & 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 mt.ty.is_trait() {
- 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
- // (returned or stored beyond the call by a closure).
- if let ReLateBound(_, BrAnon(_)) = *b {
- attrs.arg(idx, llvm::Attribute::NoCapture);
- }
- }
-
- _ => ()
- }
-
- if common::type_is_fat_ptr(ccx.tcx(), t) {
- idx += 2;
- } else {
- idx += 1;
- }
- }
-
- attrs
-}