]> git.lizzy.rs Git - rust.git/commitdiff
rustc_llvm: An AttrBuilder that's not completely wasteful.
authorEduard Burtescu <edy.burt@gmail.com>
Thu, 25 Feb 2016 17:08:10 +0000 (19:08 +0200)
committerEduard Burtescu <edy.burt@gmail.com>
Thu, 17 Mar 2016 19:51:51 +0000 (21:51 +0200)
src/librustc_llvm/lib.rs
src/librustc_trans/trans/abi.rs
src/librustc_trans/trans/attributes.rs

index aa7fdfaf67669300fb2e12292de2603544e3a2f3..10865df3a4d79c0feb3c22cbcd8416f8771d1075 100644 (file)
@@ -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,79 +163,85 @@ pub enum DLLStorageClassTypes {
         // 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
 }
 
-#[repr(C)]
-#[derive(Copy, Clone)]
-pub enum AttributeSet {
-    ReturnIndex = 0,
-    FunctionIndex = !0
-}
+impl Attributes {
+    pub fn set(&mut self, attr: Attribute) -> &mut Self {
+        self.regular = self.regular | attr;
+        self
+    }
 
-pub trait AttrHelper {
-    fn apply_llfn(&self, idx: c_uint, llfn: ValueRef);
-    fn apply_callsite(&self, idx: c_uint, callsite: ValueRef);
-}
+    pub fn unset(&mut self, attr: Attribute) -> &mut Self {
+        self.regular = self.regular - attr;
+        self
+    }
 
-impl AttrHelper for Attribute {
-    fn apply_llfn(&self, idx: c_uint, llfn: ValueRef) {
-        unsafe {
-            LLVMAddFunctionAttribute(llfn, idx, self.bits() as uint64_t);
-        }
+    pub fn set_dereferenceable(&mut self, bytes: u64) -> &mut Self {
+        self.dereferenceable_bytes = bytes;
+        self
     }
 
-    fn apply_callsite(&self, idx: c_uint, callsite: ValueRef) {
-        unsafe {
-            LLVMAddCallSiteAttribute(callsite, idx, self.bits() as uint64_t);
-        }
+    pub fn unset_dereferenceable(&mut self) -> &mut Self {
+        self.dereferenceable_bytes = 0;
+        self
     }
-}
 
-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);
+    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);
             }
         }
     }
 
-    fn apply_callsite(&self, idx: c_uint, callsite: ValueRef) {
-        match *self {
-            DereferenceableAttribute(bytes) => unsafe {
-                LLVMAddDereferenceableCallSiteAttr(callsite, idx, bytes as uint64_t);
+    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)]
+#[derive(Copy, Clone)]
+pub enum AttributeSet {
+    ReturnIndex = 0,
+    FunctionIndex = !0
+}
+
 pub struct AttrBuilder {
-    attrs: Vec<(usize, Box<AttrHelper+'static>)>
+    attrs: Vec<(usize, Attributes)>
 }
 
 impl AttrBuilder {
@@ -247,14 +251,23 @@ pub fn new() -> AttrBuilder {
         }
     }
 
-    pub fn arg<T: AttrHelper + 'static>(&mut self, idx: usize, a: T) -> &mut AttrBuilder {
-        self.attrs.push((idx, box a as Box<AttrHelper+'static>));
-        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<T: AttrHelper + 'static>(&mut self, a: T) -> &mut AttrBuilder {
-        self.attrs.push((ReturnIndex as usize, box a as Box<AttrHelper+'static>));
-        self
+    pub fn ret(&mut self) -> &mut Attributes {
+        self.arg(ReturnIndex as usize)
     }
 
     pub fn apply_llfn(&self, llfn: ValueRef) {
index 8bf4f143faff8f8e968608b3ae2d89fa8694b33d..7a639d5c89e693175b5b24270ee10d9518643f90 100644 (file)
@@ -313,15 +313,15 @@ pub fn llvm_attrs(&self, ccx: &CrateContext) -> llvm::AttrBuilder {
             // 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(illvm::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(iattr);
+            attrs.arg(i).set(attr);
         }
 
         i += 1;
@@ -333,7 +333,7 @@ pub fn llvm_attrs(&self, ccx: &CrateContext) -> llvm::AttrBuilder {
             if arg.pad.is_some() { i += 1; }
 
             if let Some(attr) = arg.attr {
-                attrs.arg(iattr);
+                attrs.arg(i).set(attr);
             }
 
             i += 1;
index 6c99632341fbdf358638afacd7f26fe6738013b5..5eb9560a43a1eb1abd4329d35e97a171ca509947 100644 (file)
@@ -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(1llvm::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(idxllvm::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(idxllvm::Attribute::ZExt);
+                attrs.arg(idx).set(llvm::Attribute::ZExt);
             }
 
             // `Box` pointer parameters never alias because ownership is transferred
             ty::TyBox(inner) => {
-                attrs.arg(idxllvm::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(idxllvm::Attribute::NoAlias);
+                    attrs.arg(idx).set(llvm::Attribute::NoAlias);
                 }
 
                 if mt.mutbl == hir::MutImmutable && !interior_unsafe {
-                    attrs.arg(idxllvm::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(idxllvm::Attribute::NoCapture);
+                    attrs.arg(idx).set(llvm::Attribute::NoCapture);
                 }
             }