From c7172a9935771601a67cdcbedcd2a8cda87367e9 Mon Sep 17 00:00:00 2001 From: Eduard Burtescu Date: Thu, 25 Feb 2016 19:08:10 +0200 Subject: [PATCH] rustc_llvm: An AttrBuilder that's not completely wasteful. --- src/librustc_llvm/lib.rs | 151 ++++++++++++++----------- src/librustc_trans/trans/abi.rs | 12 +- src/librustc_trans/trans/attributes.rs | 54 +++++---- 3 files changed, 114 insertions(+), 103 deletions(-) diff --git a/src/librustc_llvm/lib.rs b/src/librustc_llvm/lib.rs index aa7fdfaf676..10865df3a4d 100644 --- a/src/librustc_llvm/lib.rs +++ b/src/librustc_llvm/lib.rs @@ -33,8 +33,6 @@ extern crate libc; #[macro_use] #[no_link] extern crate rustc_bitflags; -pub use self::OtherAttribute::*; -pub use self::SpecialAttribute::*; pub use self::AttributeSet::*; pub use self::IntPredicate::*; pub use self::RealPredicate::*; @@ -133,7 +131,7 @@ pub enum DLLStorageClassTypes { } bitflags! { - #[derive(Debug)] + #[derive(Default, Debug)] flags Attribute : u64 { const ZExt = 1 << 0, const SExt = 1 << 1, @@ -165,31 +163,74 @@ bitflags! { // FIXME: These attributes are currently not included in the C API as // a temporary measure until the API/ABI impact to the C API is understood // and the path forward agreed upon. - const SanitizeAddress = 1 << 32; - const MinSize = 1 << 33; - const NoDuplicate = 1 << 34; - const StackProtectStrong = 1 << 35; - const SanitizeThread = 1 << 36; - const SanitizeMemory = 1 << 37; - const NoBuiltin = 1 << 38; - const Returned = 1 << 39; - const Cold = 1 << 40; - const Builtin = 1 << 41; - const OptimizeNone = 1 << 42; - const InAlloca = 1 << 43; - const NonNull = 1 << 44; - const JumpTable = 1 << 45; - const Convergent = 1 << 46; - const SafeStack = 1 << 47; - const NoRecurse = 1 << 48; - const InaccessibleMemOnly = 1 << 49; - const InaccessibleMemOrArgMemOnly = 1 << 50; + const SanitizeAddress = 1 << 32, + const MinSize = 1 << 33, + const NoDuplicate = 1 << 34, + const StackProtectStrong = 1 << 35, + const SanitizeThread = 1 << 36, + const SanitizeMemory = 1 << 37, + const NoBuiltin = 1 << 38, + const Returned = 1 << 39, + const Cold = 1 << 40, + const Builtin = 1 << 41, + const OptimizeNone = 1 << 42, + const InAlloca = 1 << 43, + const NonNull = 1 << 44, + const JumpTable = 1 << 45, + const Convergent = 1 << 46, + const SafeStack = 1 << 47, + const NoRecurse = 1 << 48, + const InaccessibleMemOnly = 1 << 49, + const InaccessibleMemOrArgMemOnly = 1 << 50, } } -#[derive(Copy, Clone)] -pub enum SpecialAttribute { - DereferenceableAttribute(u64) +#[derive(Copy, Clone, Default)] +pub struct Attributes { + regular: Attribute, + dereferenceable_bytes: u64 +} + +impl Attributes { + pub fn set(&mut self, attr: Attribute) -> &mut Self { + self.regular = self.regular | attr; + self + } + + pub fn unset(&mut self, attr: Attribute) -> &mut Self { + self.regular = self.regular - attr; + self + } + + pub fn set_dereferenceable(&mut self, bytes: u64) -> &mut Self { + self.dereferenceable_bytes = bytes; + self + } + + pub fn unset_dereferenceable(&mut self) -> &mut Self { + self.dereferenceable_bytes = 0; + self + } + + pub fn apply_llfn(&self, idx: c_uint, llfn: ValueRef) { + unsafe { + LLVMAddFunctionAttribute(llfn, idx, self.regular.bits()); + if self.dereferenceable_bytes != 0 { + LLVMAddDereferenceableAttr(llfn, idx, + self.dereferenceable_bytes); + } + } + } + + pub fn apply_callsite(&self, idx: c_uint, callsite: ValueRef) { + unsafe { + LLVMAddCallSiteAttribute(callsite, idx, self.regular.bits()); + if self.dereferenceable_bytes != 0 { + LLVMAddDereferenceableCallSiteAttr(callsite, idx, + self.dereferenceable_bytes); + } + } + } } #[repr(C)] @@ -199,45 +240,8 @@ pub enum AttributeSet { FunctionIndex = !0 } -pub trait AttrHelper { - fn apply_llfn(&self, idx: c_uint, llfn: ValueRef); - fn apply_callsite(&self, idx: c_uint, callsite: ValueRef); -} - -impl AttrHelper for Attribute { - fn apply_llfn(&self, idx: c_uint, llfn: ValueRef) { - unsafe { - LLVMAddFunctionAttribute(llfn, idx, self.bits() as uint64_t); - } - } - - fn apply_callsite(&self, idx: c_uint, callsite: ValueRef) { - unsafe { - LLVMAddCallSiteAttribute(callsite, idx, self.bits() as uint64_t); - } - } -} - -impl AttrHelper for SpecialAttribute { - fn apply_llfn(&self, idx: c_uint, llfn: ValueRef) { - match *self { - DereferenceableAttribute(bytes) => unsafe { - LLVMAddDereferenceableAttr(llfn, idx, bytes as uint64_t); - } - } - } - - fn apply_callsite(&self, idx: c_uint, callsite: ValueRef) { - match *self { - DereferenceableAttribute(bytes) => unsafe { - LLVMAddDereferenceableCallSiteAttr(callsite, idx, bytes as uint64_t); - } - } - } -} - pub struct AttrBuilder { - attrs: Vec<(usize, Box)> + attrs: Vec<(usize, Attributes)> } impl AttrBuilder { @@ -247,14 +251,23 @@ impl AttrBuilder { } } - pub fn arg(&mut self, idx: usize, a: T) -> &mut AttrBuilder { - self.attrs.push((idx, box a as Box)); - self + pub fn arg(&mut self, idx: usize) -> &mut Attributes { + let mut found = None; + for (i, &(idx2, _)) in self.attrs.iter().enumerate() { + if idx == idx2 { + found = Some(i); + break; + } + } + let i = found.unwrap_or_else(|| { + self.attrs.push((idx, Attributes::default())); + self.attrs.len() - 1 + }); + &mut self.attrs[i].1 } - pub fn ret(&mut self, a: T) -> &mut AttrBuilder { - self.attrs.push((ReturnIndex as usize, box a as Box)); - self + pub fn ret(&mut self) -> &mut Attributes { + self.arg(ReturnIndex as usize) } pub fn apply_llfn(&self, llfn: ValueRef) { diff --git a/src/librustc_trans/trans/abi.rs b/src/librustc_trans/trans/abi.rs index 8bf4f143faf..7a639d5c89e 100644 --- a/src/librustc_trans/trans/abi.rs +++ b/src/librustc_trans/trans/abi.rs @@ -313,15 +313,15 @@ impl FnType { // 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(i, llvm::Attribute::StructRet) - .arg(i, llvm::Attribute::NoAlias) - .arg(i, llvm::Attribute::NoCapture) - .arg(i, llvm::DereferenceableAttribute(llret_sz)); + attrs.arg(i).set(llvm::Attribute::StructRet) + .set(llvm::Attribute::NoAlias) + .set(llvm::Attribute::NoCapture) + .set_dereferenceable(llret_sz); }; // Add attributes that depend on the concrete foreign ABI if let Some(attr) = self.ret.attr { - attrs.arg(i, attr); + attrs.arg(i).set(attr); } i += 1; @@ -333,7 +333,7 @@ impl FnType { if arg.pad.is_some() { i += 1; } if let Some(attr) = arg.attr { - attrs.arg(i, attr); + attrs.arg(i).set(attr); } i += 1; diff --git a/src/librustc_trans/trans/attributes.rs b/src/librustc_trans/trans/attributes.rs index 6c99632341f..5eb9560a43a 100644 --- a/src/librustc_trans/trans/attributes.rs +++ b/src/librustc_trans/trans/attributes.rs @@ -10,7 +10,7 @@ //! Set and unset common attributes on LLVM values. use libc::{c_uint, c_ulonglong}; -use llvm::{self, ValueRef, AttrHelper}; +use llvm::{self, ValueRef}; use middle::ty; use middle::infer; use session::config::NoDebugInfo; @@ -110,13 +110,11 @@ 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 c_uint, 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 c_uint, llfn) } else if attr.check_name("unwind") { unwind(llfn, true); } @@ -168,10 +166,10 @@ pub fn from_fn_type<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, fn_type: ty::Ty<'tcx // 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)); + attrs.arg(1).set(llvm::Attribute::StructRet) + .set(llvm::Attribute::NoAlias) + .set(llvm::Attribute::NoCapture) + .set_dereferenceable(llret_sz); // Add one more since there's an outptr idx += 1; @@ -182,7 +180,7 @@ pub fn from_fn_type<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, fn_type: ty::Ty<'tcx // `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); + attrs.ret().set(llvm::Attribute::NoAlias); } _ => {} } @@ -193,13 +191,13 @@ pub fn from_fn_type<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, fn_type: ty::Ty<'tcx 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)); + attrs.ret().set_dereferenceable(llret_sz); } _ => {} } if let ty::TyBool = ret_ty.sty { - attrs.ret(llvm::Attribute::ZExt); + attrs.ret().set(llvm::Attribute::ZExt); } } } @@ -212,26 +210,26 @@ pub fn from_fn_type<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, fn_type: ty::Ty<'tcx // 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)); + attrs.arg(idx).set(llvm::Attribute::NoAlias) + .set(llvm::Attribute::NoCapture) + .set_dereferenceable(llarg_sz); } ty::TyBool => { - attrs.arg(idx, llvm::Attribute::ZExt); + attrs.arg(idx).set(llvm::Attribute::ZExt); } // `Box` pointer parameters never alias because ownership is transferred ty::TyBox(inner) => { - attrs.arg(idx, llvm::Attribute::NoAlias); + attrs.arg(idx).set(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)); + attrs.arg(idx).set_dereferenceable(llsz); } else { - attrs.arg(idx, llvm::NonNullAttribute); + attrs.arg(idx).set(llvm::Attribute::NonNull); if inner.is_trait() { - attrs.arg(idx + 1, llvm::NonNullAttribute); + attrs.arg(idx + 1).set(llvm::Attribute::NonNull); } } } @@ -245,22 +243,22 @@ pub fn from_fn_type<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, fn_type: ty::Ty<'tcx let interior_unsafe = mt.ty.type_contents(ccx.tcx()).interior_unsafe(); if mt.mutbl != hir::MutMutable && !interior_unsafe { - attrs.arg(idx, llvm::Attribute::NoAlias); + attrs.arg(idx).set(llvm::Attribute::NoAlias); } if mt.mutbl == hir::MutImmutable && !interior_unsafe { - attrs.arg(idx, llvm::Attribute::ReadOnly); + attrs.arg(idx).set(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)); + attrs.arg(idx).set_dereferenceable(llsz); } else { - attrs.arg(idx, llvm::NonNullAttribute); + attrs.arg(idx).set(llvm::Attribute::NonNull); if mt.ty.is_trait() { - attrs.arg(idx + 1, llvm::NonNullAttribute); + attrs.arg(idx + 1).set(llvm::Attribute::NonNull); } } @@ -268,7 +266,7 @@ pub fn from_fn_type<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, fn_type: ty::Ty<'tcx // 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); + attrs.arg(idx).set(llvm::Attribute::NoCapture); } }