about summary refs log tree commit diff
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2016-11-19 16:39:25 -0600
committerGitHub <noreply@github.com>2016-11-19 16:39:25 -0600
commit0bd2ce62b27e2b9a7dfe92fc23d9098854008089 (patch)
tree86d6fdcf938c5eadf071a2e03890f72047481d5d
parentbfa709a38a8c607e1c13ee5635fbfd1940eb18b1 (diff)
parent30daedf60355d105d92ad011b9e115b01350593e (diff)
downloadrust-0bd2ce62b27e2b9a7dfe92fc23d9098854008089.tar.gz
rust-0bd2ce62b27e2b9a7dfe92fc23d9098854008089.zip
Auto merge of #37831 - rkruppe:llvm-attr-fwdcompat, r=eddyb
[LLVM 4.0] Use llvm::Attribute APIs instead of "raw value" APIs

The latter will be removed in LLVM 4.0 (see https://github.com/llvm-mirror/llvm/commit/4a6fc8bacf11d8066da72cf8481467167877ed16).

The librustc_llvm API remains mostly unchanged, except that llvm::Attribute is no longer a bitflag but represents only a *single* attribute.
The ability to store many attributes in a small number of bits and modify them without interacting with LLVM is only used in rustc_trans::abi and closely related modules, and only attributes for function arguments are considered there.
Thus rustc_trans::abi now has its own bit-packed representation of argument attributes, which are translated to rustc_llvm::Attribute when applying the attributes.

cc #37609
-rw-r--r--src/Cargo.lock2
-rw-r--r--src/librustc_llvm/Cargo.toml3
-rw-r--r--src/librustc_llvm/build.rs3
-rw-r--r--src/librustc_llvm/ffi.rs101
-rw-r--r--src/librustc_llvm/lib.rs64
-rw-r--r--src/librustc_trans/Cargo.toml1
-rw-r--r--src/librustc_trans/abi.rs123
-rw-r--r--src/librustc_trans/attributes.rs7
-rw-r--r--src/librustc_trans/cabi_asmjs.rs6
-rw-r--r--src/librustc_trans/cabi_x86.rs4
-rw-r--r--src/librustc_trans/cabi_x86_64.rs8
-rw-r--r--src/librustc_trans/lib.rs4
-rw-r--r--src/rustllvm/RustWrapper.cpp115
-rw-r--r--src/rustllvm/rustllvm.h22
14 files changed, 264 insertions, 199 deletions
diff --git a/src/Cargo.lock b/src/Cargo.lock
index 2d5207e5c6b..ab1c1c453dd 100644
--- a/src/Cargo.lock
+++ b/src/Cargo.lock
@@ -409,7 +409,6 @@ version = "0.0.0"
 dependencies = [
  "build_helper 0.1.0",
  "gcc 0.3.38 (registry+https://github.com/rust-lang/crates.io-index)",
- "rustc_bitflags 0.0.0",
 ]
 
 [[package]]
@@ -520,6 +519,7 @@ dependencies = [
  "log 0.0.0",
  "rustc 0.0.0",
  "rustc_back 0.0.0",
+ "rustc_bitflags 0.0.0",
  "rustc_const_eval 0.0.0",
  "rustc_const_math 0.0.0",
  "rustc_data_structures 0.0.0",
diff --git a/src/librustc_llvm/Cargo.toml b/src/librustc_llvm/Cargo.toml
index f97daa22ff6..88f8c0553ad 100644
--- a/src/librustc_llvm/Cargo.toml
+++ b/src/librustc_llvm/Cargo.toml
@@ -12,9 +12,6 @@ crate-type = ["dylib"]
 [features]
 static-libstdcpp = []
 
-[dependencies]
-rustc_bitflags = { path = "../librustc_bitflags" }
-
 [build-dependencies]
 build_helper = { path = "../build_helper" }
 gcc = "0.3.27"
diff --git a/src/librustc_llvm/build.rs b/src/librustc_llvm/build.rs
index 6be3d1172dc..50bc3e7b624 100644
--- a/src/librustc_llvm/build.rs
+++ b/src/librustc_llvm/build.rs
@@ -145,6 +145,9 @@ fn main() {
         cfg.flag("-DLLVM_RUSTLLVM");
     }
 
+    println!("cargo:rerun-if-changed=../rustllvm/PassWrapper.cpp");
+    println!("cargo:rerun-if-changed=../rustllvm/RustWrapper.cpp");
+    println!("cargo:rerun-if-changed=../rustllvm/ArchiveWrapper.cpp");
     cfg.file("../rustllvm/PassWrapper.cpp")
        .file("../rustllvm/RustWrapper.cpp")
        .file("../rustllvm/ArchiveWrapper.cpp")
diff --git a/src/librustc_llvm/ffi.rs b/src/librustc_llvm/ffi.rs
index 2173adf2e6e..ebd75be7bba 100644
--- a/src/librustc_llvm/ffi.rs
+++ b/src/librustc_llvm/ffi.rs
@@ -83,59 +83,31 @@ pub enum DLLStorageClass {
     DllExport = 2, // Function to be accessible from DLL.
 }
 
-bitflags! {
-    #[derive(Default, Debug)]
-    flags Attribute : u64 {
-        const ZExt            = 1 << 0,
-        const SExt            = 1 << 1,
-        const NoReturn        = 1 << 2,
-        const InReg           = 1 << 3,
-        const StructRet       = 1 << 4,
-        const NoUnwind        = 1 << 5,
-        const NoAlias         = 1 << 6,
-        const ByVal           = 1 << 7,
-        const Nest            = 1 << 8,
-        const ReadNone        = 1 << 9,
-        const ReadOnly        = 1 << 10,
-        const NoInline        = 1 << 11,
-        const AlwaysInline    = 1 << 12,
-        const OptimizeForSize = 1 << 13,
-        const StackProtect    = 1 << 14,
-        const StackProtectReq = 1 << 15,
-        const NoCapture       = 1 << 21,
-        const NoRedZone       = 1 << 22,
-        const NoImplicitFloat = 1 << 23,
-        const Naked           = 1 << 24,
-        const InlineHint      = 1 << 25,
-        const ReturnsTwice    = 1 << 29,
-        const UWTable         = 1 << 30,
-        const NonLazyBind     = 1 << 31,
-
-        // Some of these are missing from the LLVM C API, the rest are
-        // present, but commented out, and preceded by the following warning:
-        // 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,
-    }
+/// Matches LLVMRustAttribute in rustllvm.h
+/// Semantically a subset of the C++ enum llvm::Attribute::AttrKind,
+/// though it is not ABI compatible (since it's a C++ enum)
+#[repr(C)]
+#[derive(Copy, Clone, Debug)]
+pub enum Attribute {
+    AlwaysInline    = 0,
+    ByVal           = 1,
+    Cold            = 2,
+    InlineHint      = 3,
+    MinSize         = 4,
+    Naked           = 5,
+    NoAlias         = 6,
+    NoCapture       = 7,
+    NoInline        = 8,
+    NonNull         = 9,
+    NoRedZone       = 10,
+    NoReturn        = 11,
+    NoUnwind        = 12,
+    OptimizeForSize = 13,
+    ReadOnly        = 14,
+    SExt            = 15,
+    StructRet       = 16,
+    UWTable         = 17,
+    ZExt            = 18,
 }
 
 /// LLVMIntPredicate
@@ -423,6 +395,9 @@ pub type RustArchiveMemberRef = *mut RustArchiveMember_opaque;
 #[allow(missing_copy_implementations)]
 pub enum OperandBundleDef_opaque {}
 pub type OperandBundleDefRef = *mut OperandBundleDef_opaque;
+#[allow(missing_copy_implementations)]
+pub enum Attribute_opaque {}
+pub type AttributeRef = *mut Attribute_opaque;
 
 pub type DiagnosticHandler = unsafe extern "C" fn(DiagnosticInfoRef, *mut c_void);
 pub type InlineAsmDiagHandler = unsafe extern "C" fn(SMDiagnosticRef, *const c_void, c_uint);
@@ -530,6 +505,9 @@ extern "C" {
     /// See llvm::LLVMType::getContext.
     pub fn LLVMGetTypeContext(Ty: TypeRef) -> ContextRef;
 
+    /// See llvm::Value::getContext
+    pub fn LLVMRustGetValueContext(V: ValueRef) -> ContextRef;
+
     // Operations on integer types
     pub fn LLVMInt1TypeInContext(C: ContextRef) -> TypeRef;
     pub fn LLVMInt8TypeInContext(C: ContextRef) -> TypeRef;
@@ -792,6 +770,8 @@ extern "C" {
                         Name: *const c_char)
                         -> ValueRef;
 
+    pub fn LLVMRustCreateAttribute(C: ContextRef, kind: Attribute, val: u64) -> AttributeRef;
+
     // Operations on functions
     pub fn LLVMAddFunction(M: ModuleRef, Name: *const c_char, FunctionTy: TypeRef) -> ValueRef;
     pub fn LLVMGetNamedFunction(M: ModuleRef, Name: *const c_char) -> ValueRef;
@@ -810,16 +790,12 @@ extern "C" {
     pub fn LLVMGetGC(Fn: ValueRef) -> *const c_char;
     pub fn LLVMSetGC(Fn: ValueRef, Name: *const c_char);
     pub fn LLVMRustAddDereferenceableAttr(Fn: ValueRef, index: c_uint, bytes: u64);
-    pub fn LLVMRustAddFunctionAttribute(Fn: ValueRef, index: c_uint, PA: u64);
-    pub fn LLVMRustAddFunctionAttrString(Fn: ValueRef, index: c_uint, Name: *const c_char);
+    pub fn LLVMRustAddFunctionAttribute(Fn: ValueRef, index: c_uint, attr: AttributeRef);
     pub fn LLVMRustAddFunctionAttrStringValue(Fn: ValueRef,
                                               index: c_uint,
                                               Name: *const c_char,
                                               Value: *const c_char);
-    pub fn LLVMRustRemoveFunctionAttributes(Fn: ValueRef, index: c_uint, attr: u64);
-    pub fn LLVMRustRemoveFunctionAttrString(Fn: ValueRef, index: c_uint, Name: *const c_char);
-    pub fn LLVMGetFunctionAttr(Fn: ValueRef) -> c_uint;
-    pub fn LLVMRemoveFunctionAttr(Fn: ValueRef, val: c_uint);
+    pub fn LLVMRustRemoveFunctionAttributes(Fn: ValueRef, index: c_uint, attr: AttributeRef);
 
     // Operations on parameters
     pub fn LLVMCountParams(Fn: ValueRef) -> c_uint;
@@ -830,9 +806,8 @@ extern "C" {
     pub fn LLVMGetLastParam(Fn: ValueRef) -> ValueRef;
     pub fn LLVMGetNextParam(Arg: ValueRef) -> ValueRef;
     pub fn LLVMGetPreviousParam(Arg: ValueRef) -> ValueRef;
-    pub fn LLVMAddAttribute(Arg: ValueRef, PA: c_uint);
-    pub fn LLVMRemoveAttribute(Arg: ValueRef, PA: c_uint);
-    pub fn LLVMGetAttribute(Arg: ValueRef) -> c_uint;
+    pub fn LLVMAddAttribute(Arg: ValueRef, attr: AttributeRef);
+    pub fn LLVMRemoveAttribute(Arg: ValueRef, attr: AttributeRef);
     pub fn LLVMSetParamAlignment(Arg: ValueRef, align: c_uint);
 
     // Operations on basic blocks
@@ -876,7 +851,7 @@ extern "C" {
     pub fn LLVMAddInstrAttribute(Instr: ValueRef, index: c_uint, IA: c_uint);
     pub fn LLVMRemoveInstrAttribute(Instr: ValueRef, index: c_uint, IA: c_uint);
     pub fn LLVMSetInstrParamAlignment(Instr: ValueRef, index: c_uint, align: c_uint);
-    pub fn LLVMRustAddCallSiteAttribute(Instr: ValueRef, index: c_uint, Val: u64);
+    pub fn LLVMRustAddCallSiteAttribute(Instr: ValueRef, index: c_uint, attr: AttributeRef);
     pub fn LLVMRustAddDereferenceableCallSiteAttr(Instr: ValueRef, index: c_uint, bytes: u64);
 
     // Operations on call instructions (only)
diff --git a/src/librustc_llvm/lib.rs b/src/librustc_llvm/lib.rs
index 65e0dbcad3a..c81d3b48aa9 100644
--- a/src/librustc_llvm/lib.rs
+++ b/src/librustc_llvm/lib.rs
@@ -29,12 +29,8 @@
 #![feature(staged_api)]
 #![feature(linked_from)]
 #![feature(concat_idents)]
-#![cfg_attr(not(stage0), feature(rustc_private))]
 
 extern crate libc;
-#[macro_use]
-#[no_link]
-extern crate rustc_bitflags;
 
 pub use self::IntPredicate::*;
 pub use self::RealPredicate::*;
@@ -68,54 +64,6 @@ impl LLVMRustResult {
     }
 }
 
-#[derive(Copy, Clone, Default, Debug)]
-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: AttributePlace, llfn: ValueRef) {
-        unsafe {
-            self.regular.apply_llfn(idx, llfn);
-            if self.dereferenceable_bytes != 0 {
-                LLVMRustAddDereferenceableAttr(llfn, idx.as_uint(), self.dereferenceable_bytes);
-            }
-        }
-    }
-
-    pub fn apply_callsite(&self, idx: AttributePlace, callsite: ValueRef) {
-        unsafe {
-            self.regular.apply_callsite(idx, callsite);
-            if self.dereferenceable_bytes != 0 {
-                LLVMRustAddDereferenceableCallSiteAttr(callsite,
-                                                       idx.as_uint(),
-                                                       self.dereferenceable_bytes);
-            }
-        }
-    }
-}
-
 pub fn AddFunctionAttrStringValue(llfn: ValueRef,
                                   idx: AttributePlace,
                                   attr: &'static str,
@@ -140,7 +88,7 @@ impl AttributePlace {
         AttributePlace::Argument(0)
     }
 
-    fn as_uint(self) -> c_uint {
+    pub fn as_uint(self) -> c_uint {
         match self {
             AttributePlace::Function => !0,
             AttributePlace::Argument(i) => i,
@@ -228,16 +176,20 @@ pub fn set_thread_local(global: ValueRef, is_thread_local: bool) {
 }
 
 impl Attribute {
+    fn as_object(&self, value: ValueRef) -> AttributeRef {
+        unsafe { LLVMRustCreateAttribute(LLVMRustGetValueContext(value), *self, 0) }
+    }
+
     pub fn apply_llfn(&self, idx: AttributePlace, llfn: ValueRef) {
-        unsafe { LLVMRustAddFunctionAttribute(llfn, idx.as_uint(), self.bits()) }
+        unsafe { LLVMRustAddFunctionAttribute(llfn, idx.as_uint(), self.as_object(llfn)) }
     }
 
     pub fn apply_callsite(&self, idx: AttributePlace, callsite: ValueRef) {
-        unsafe { LLVMRustAddCallSiteAttribute(callsite, idx.as_uint(), self.bits()) }
+        unsafe { LLVMRustAddCallSiteAttribute(callsite, idx.as_uint(), self.as_object(callsite)) }
     }
 
     pub fn unapply_llfn(&self, idx: AttributePlace, llfn: ValueRef) {
-        unsafe { LLVMRustRemoveFunctionAttributes(llfn, idx.as_uint(), self.bits()) }
+        unsafe { LLVMRustRemoveFunctionAttributes(llfn, idx.as_uint(), self.as_object(llfn)) }
     }
 
     pub fn toggle_llfn(&self, idx: AttributePlace, llfn: ValueRef, set: bool) {
diff --git a/src/librustc_trans/Cargo.toml b/src/librustc_trans/Cargo.toml
index 38f9e7ab0c5..796a80d0809 100644
--- a/src/librustc_trans/Cargo.toml
+++ b/src/librustc_trans/Cargo.toml
@@ -16,6 +16,7 @@ graphviz = { path = "../libgraphviz" }
 log = { path = "../liblog" }
 rustc = { path = "../librustc" }
 rustc_back = { path = "../librustc_back" }
+rustc_bitflags = { path = "../librustc_bitflags" }
 rustc_const_eval = { path = "../librustc_const_eval" }
 rustc_const_math = { path = "../librustc_const_math" }
 rustc_data_structures = { path = "../librustc_data_structures" }
diff --git a/src/librustc_trans/abi.rs b/src/librustc_trans/abi.rs
index cb06fac2c67..07f53466b49 100644
--- a/src/librustc_trans/abi.rs
+++ b/src/librustc_trans/abi.rs
@@ -8,7 +8,7 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-use llvm::{self, ValueRef, Integer, Pointer, Float, Double, Struct, Array, Vector};
+use llvm::{self, ValueRef, Integer, Pointer, Float, Double, Struct, Array, Vector, AttributePlace};
 use base;
 use build::AllocaFcx;
 use common::{type_is_fat_ptr, BlockAndBuilder, C_uint};
@@ -50,6 +50,93 @@ enum ArgKind {
     Ignore,
 }
 
+// Hack to disable non_upper_case_globals only for the bitflags! and not for the rest
+// of this module
+pub use self::attr_impl::ArgAttribute;
+
+#[allow(non_upper_case_globals)]
+mod attr_impl {
+    // The subset of llvm::Attribute needed for arguments, packed into a bitfield.
+    bitflags! {
+        #[derive(Default, Debug)]
+        flags ArgAttribute : u8 {
+            const ByVal     = 1 << 0,
+            const NoAlias   = 1 << 1,
+            const NoCapture = 1 << 2,
+            const NonNull   = 1 << 3,
+            const ReadOnly  = 1 << 4,
+            const SExt      = 1 << 5,
+            const StructRet = 1 << 6,
+            const ZExt      = 1 << 7,
+        }
+    }
+}
+
+macro_rules! for_each_kind {
+    ($flags: ident, $f: ident, $($kind: ident),+) => ({
+        $(if $flags.contains(ArgAttribute::$kind) { $f(llvm::Attribute::$kind) })+
+    })
+}
+
+impl ArgAttribute {
+    fn for_each_kind<F>(&self, mut f: F) where F: FnMut(llvm::Attribute) {
+        for_each_kind!(self, f,
+                       ByVal, NoAlias, NoCapture, NonNull, ReadOnly, SExt, StructRet, ZExt)
+    }
+}
+
+/// A compact representation of LLVM attributes (at least those relevant for this module)
+/// that can be manipulated without interacting with LLVM's Attribute machinery.
+#[derive(Copy, Clone, Debug, Default)]
+pub struct ArgAttributes {
+    regular: ArgAttribute,
+    dereferenceable_bytes: u64,
+}
+
+impl ArgAttributes {
+    pub fn set(&mut self, attr: ArgAttribute) -> &mut Self {
+        self.regular = self.regular | attr;
+        self
+    }
+
+    pub fn unset(&mut self, attr: ArgAttribute) -> &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: AttributePlace, llfn: ValueRef) {
+        unsafe {
+            self.regular.for_each_kind(|attr| attr.apply_llfn(idx, llfn));
+            if self.dereferenceable_bytes != 0 {
+                llvm::LLVMRustAddDereferenceableAttr(llfn,
+                                                     idx.as_uint(),
+                                                     self.dereferenceable_bytes);
+            }
+        }
+    }
+
+    pub fn apply_callsite(&self, idx: AttributePlace, callsite: ValueRef) {
+        unsafe {
+            self.regular.for_each_kind(|attr| attr.apply_callsite(idx, callsite));
+            if self.dereferenceable_bytes != 0 {
+                llvm::LLVMRustAddDereferenceableCallSiteAttr(callsite,
+                                                             idx.as_uint(),
+                                                             self.dereferenceable_bytes);
+            }
+        }
+    }
+}
+
 /// Information about how a specific C type
 /// should be passed to or returned from a function
 ///
@@ -81,7 +168,7 @@ pub struct ArgType {
     /// Dummy argument, which is emitted before the real argument
     pub pad: Option<Type>,
     /// LLVM attributes of argument
-    pub attrs: llvm::Attributes
+    pub attrs: ArgAttributes
 }
 
 impl ArgType {
@@ -93,7 +180,7 @@ impl ArgType {
             signedness: None,
             cast: None,
             pad: None,
-            attrs: llvm::Attributes::default()
+            attrs: ArgAttributes::default()
         }
     }
 
@@ -101,15 +188,15 @@ impl ArgType {
         assert_eq!(self.kind, ArgKind::Direct);
 
         // Wipe old attributes, likely not valid through indirection.
-        self.attrs = llvm::Attributes::default();
+        self.attrs = ArgAttributes::default();
 
         let llarg_sz = llsize_of_alloc(ccx, self.ty);
 
         // 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
-        self.attrs.set(llvm::Attribute::NoAlias)
-                  .set(llvm::Attribute::NoCapture)
+        self.attrs.set(ArgAttribute::NoAlias)
+                  .set(ArgAttribute::NoCapture)
                   .set_dereferenceable(llarg_sz);
 
         self.kind = ArgKind::Indirect;
@@ -125,9 +212,9 @@ impl ArgType {
         if let Some(signed) = self.signedness {
             if self.ty.int_width() < bits {
                 self.attrs.set(if signed {
-                    llvm::Attribute::SExt
+                    ArgAttribute::SExt
                 } else {
-                    llvm::Attribute::ZExt
+                    ArgAttribute::ZExt
                 });
             }
         }
@@ -315,7 +402,7 @@ impl FnType {
             if ty.is_bool() {
                 let llty = Type::i1(ccx);
                 let mut arg = ArgType::new(llty, llty);
-                arg.attrs.set(llvm::Attribute::ZExt);
+                arg.attrs.set(ArgAttribute::ZExt);
                 arg
             } else {
                 let mut arg = ArgType::new(type_of::type_of(ccx, ty),
@@ -350,7 +437,7 @@ impl FnType {
             if let ty::TyBox(_) = ret_ty.sty {
                 // `Box` pointer return values never alias because ownership
                 // is transferred
-                ret.attrs.set(llvm::Attribute::NoAlias);
+                ret.attrs.set(ArgAttribute::NoAlias);
             }
 
             // We can also mark the return value as `dereferenceable` in certain cases
@@ -372,7 +459,7 @@ impl FnType {
         let rust_ptr_attrs = |ty: Ty<'tcx>, arg: &mut ArgType| match ty.sty {
             // `Box` pointer parameters never alias because ownership is transferred
             ty::TyBox(inner) => {
-                arg.attrs.set(llvm::Attribute::NoAlias);
+                arg.attrs.set(ArgAttribute::NoAlias);
                 Some(inner)
             }
 
@@ -387,18 +474,18 @@ impl FnType {
                 let interior_unsafe = mt.ty.type_contents(ccx.tcx()).interior_unsafe();
 
                 if mt.mutbl != hir::MutMutable && !interior_unsafe {
-                    arg.attrs.set(llvm::Attribute::NoAlias);
+                    arg.attrs.set(ArgAttribute::NoAlias);
                 }
 
                 if mt.mutbl == hir::MutImmutable && !interior_unsafe {
-                    arg.attrs.set(llvm::Attribute::ReadOnly);
+                    arg.attrs.set(ArgAttribute::ReadOnly);
                 }
 
                 // 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 {
-                    arg.attrs.set(llvm::Attribute::NoCapture);
+                    arg.attrs.set(ArgAttribute::NoCapture);
                 }
 
                 Some(mt.ty)
@@ -418,9 +505,9 @@ impl FnType {
                 let mut info = ArgType::new(original_tys[1], sizing_tys[1]);
 
                 if let Some(inner) = rust_ptr_attrs(ty, &mut data) {
-                    data.attrs.set(llvm::Attribute::NonNull);
+                    data.attrs.set(ArgAttribute::NonNull);
                     if ccx.tcx().struct_tail(inner).is_trait() {
-                        info.attrs.set(llvm::Attribute::NonNull);
+                        info.attrs.set(ArgAttribute::NonNull);
                     }
                 }
                 args.push(data);
@@ -491,7 +578,7 @@ impl FnType {
                 fixup(arg);
             }
             if self.ret.is_indirect() {
-                self.ret.attrs.set(llvm::Attribute::StructRet);
+                self.ret.attrs.set(ArgAttribute::StructRet);
             }
             return;
         }
@@ -526,7 +613,7 @@ impl FnType {
         }
 
         if self.ret.is_indirect() {
-            self.ret.attrs.set(llvm::Attribute::StructRet);
+            self.ret.attrs.set(ArgAttribute::StructRet);
         }
     }
 
diff --git a/src/librustc_trans/attributes.rs b/src/librustc_trans/attributes.rs
index 62eac35e0ab..f1e90419a49 100644
--- a/src/librustc_trans/attributes.rs
+++ b/src/librustc_trans/attributes.rs
@@ -24,10 +24,9 @@ pub fn inline(val: ValueRef, inline: InlineAttr) {
         Always => Attribute::AlwaysInline.apply_llfn(Function, val),
         Never  => Attribute::NoInline.apply_llfn(Function, val),
         None   => {
-            let attr = Attribute::InlineHint |
-                       Attribute::AlwaysInline |
-                       Attribute::NoInline;
-            attr.unapply_llfn(Function, val)
+            Attribute::InlineHint.unapply_llfn(Function, val);
+            Attribute::AlwaysInline.unapply_llfn(Function, val);
+            Attribute::NoInline.unapply_llfn(Function, val);
         },
     };
 }
diff --git a/src/librustc_trans/cabi_asmjs.rs b/src/librustc_trans/cabi_asmjs.rs
index 3cbc378ab02..f410627400c 100644
--- a/src/librustc_trans/cabi_asmjs.rs
+++ b/src/librustc_trans/cabi_asmjs.rs
@@ -10,8 +10,8 @@
 
 #![allow(non_upper_case_globals)]
 
-use llvm::{Struct, Array, Attribute};
-use abi::{FnType, ArgType};
+use llvm::{Struct, Array};
+use abi::{FnType, ArgType, ArgAttribute};
 use context::CrateContext;
 
 // Data layout: e-p:32:32-i64:64-v128:32:128-n32-S128
@@ -39,7 +39,7 @@ fn classify_ret_ty(ccx: &CrateContext, ret: &mut ArgType) {
 fn classify_arg_ty(ccx: &CrateContext, arg: &mut ArgType) {
     if arg.ty.is_aggregate() {
         arg.make_indirect(ccx);
-        arg.attrs.set(Attribute::ByVal);
+        arg.attrs.set(ArgAttribute::ByVal);
     }
 }
 
diff --git a/src/librustc_trans/cabi_x86.rs b/src/librustc_trans/cabi_x86.rs
index b52231fa6b4..5377b49a2b4 100644
--- a/src/librustc_trans/cabi_x86.rs
+++ b/src/librustc_trans/cabi_x86.rs
@@ -9,7 +9,7 @@
 // except according to those terms.
 
 use llvm::*;
-use abi::FnType;
+use abi::{ArgAttribute, FnType};
 use type_::Type;
 use super::common::*;
 use super::machine::*;
@@ -45,7 +45,7 @@ pub fn compute_abi_info(ccx: &CrateContext, fty: &mut FnType) {
         if arg.is_ignore() { continue; }
         if arg.ty.kind() == Struct {
             arg.make_indirect(ccx);
-            arg.attrs.set(Attribute::ByVal);
+            arg.attrs.set(ArgAttribute::ByVal);
         } else {
             arg.extend_integer_width_to(32);
         }
diff --git a/src/librustc_trans/cabi_x86_64.rs b/src/librustc_trans/cabi_x86_64.rs
index 33990148c8b..7f2fdbf000b 100644
--- a/src/librustc_trans/cabi_x86_64.rs
+++ b/src/librustc_trans/cabi_x86_64.rs
@@ -15,8 +15,8 @@
 use self::RegClass::*;
 
 use llvm::{Integer, Pointer, Float, Double};
-use llvm::{Struct, Array, Attribute, Vector};
-use abi::{self, ArgType, FnType};
+use llvm::{Struct, Array, Vector};
+use abi::{self, ArgType, ArgAttribute, FnType};
 use context::CrateContext;
 use type_::Type;
 
@@ -334,7 +334,7 @@ pub fn compute_abi_info(ccx: &CrateContext, fty: &mut FnType) {
     fn x86_64_ty<F>(ccx: &CrateContext,
                     arg: &mut ArgType,
                     is_mem_cls: F,
-                    ind_attr: Option<Attribute>)
+                    ind_attr: Option<ArgAttribute>)
         where F: FnOnce(&[RegClass]) -> bool
     {
         if !arg.ty.is_reg_ty() {
@@ -384,7 +384,7 @@ pub fn compute_abi_info(ccx: &CrateContext, fty: &mut FnType) {
                 sse_regs -= needed_sse;
             }
             in_mem
-        }, Some(Attribute::ByVal));
+        }, Some(ArgAttribute::ByVal));
 
         // An integer, pointer, double or float parameter
         // thus the above closure passed to `x86_64_ty` won't
diff --git a/src/librustc_trans/lib.rs b/src/librustc_trans/lib.rs
index 611b93d2de1..d0cb302e1ab 100644
--- a/src/librustc_trans/lib.rs
+++ b/src/librustc_trans/lib.rs
@@ -23,6 +23,7 @@
       html_root_url = "https://doc.rust-lang.org/nightly/")]
 #![cfg_attr(not(stage0), deny(warnings))]
 
+#![feature(associated_consts)]
 #![feature(box_patterns)]
 #![feature(box_syntax)]
 #![feature(cell_extras)]
@@ -55,6 +56,9 @@ extern crate rustc_platform_intrinsics as intrinsics;
 extern crate serialize;
 extern crate rustc_const_math;
 extern crate rustc_const_eval;
+#[macro_use]
+#[no_link]
+extern crate rustc_bitflags;
 
 #[macro_use] extern crate log;
 #[macro_use] extern crate syntax;
diff --git a/src/rustllvm/RustWrapper.cpp b/src/rustllvm/RustWrapper.cpp
index 369388caa04..7f0c7e2e5c9 100644
--- a/src/rustllvm/RustWrapper.cpp
+++ b/src/rustllvm/RustWrapper.cpp
@@ -109,37 +109,84 @@ extern "C" LLVMTypeRef LLVMRustMetadataTypeInContext(LLVMContextRef C) {
   return wrap(Type::getMetadataTy(*unwrap(C)));
 }
 
-extern "C" void LLVMRustAddCallSiteAttribute(LLVMValueRef Instr, unsigned index, uint64_t Val) {
+static Attribute::AttrKind
+from_rust(LLVMRustAttribute kind) {
+  switch (kind) {
+    case AlwaysInline:
+      return Attribute::AlwaysInline;
+    case ByVal:
+      return Attribute::ByVal;
+    case Cold:
+      return Attribute::Cold;
+    case InlineHint:
+      return Attribute::InlineHint;
+    case MinSize:
+      return Attribute::MinSize;
+    case Naked:
+      return Attribute::Naked;
+    case NoAlias:
+      return Attribute::NoAlias;
+    case NoCapture:
+      return Attribute::NoCapture;
+    case NoInline:
+      return Attribute::NoInline;
+    case NonNull:
+      return Attribute::NonNull;
+    case NoRedZone:
+      return Attribute::NoRedZone;
+    case NoReturn:
+      return Attribute::NoReturn;
+    case NoUnwind:
+      return Attribute::NoUnwind;
+    case OptimizeForSize:
+      return Attribute::OptimizeForSize;
+    case ReadOnly:
+      return Attribute::ReadOnly;
+    case SExt:
+      return Attribute::SExt;
+    case StructRet:
+      return Attribute::StructRet;
+    case UWTable:
+      return Attribute::UWTable;
+    case ZExt:
+      return Attribute::ZExt;
+    default:
+      llvm_unreachable("bad AttributeKind");
+  }
+}
+
+extern "C" LLVMAttributeRef LLVMRustCreateAttribute(LLVMContextRef C, LLVMRustAttribute Kind, uint64_t Val) {
+  return wrap(Attribute::get(*unwrap(C), from_rust(Kind), Val));
+}
+
+extern "C" void LLVMRustAddCallSiteAttribute(LLVMValueRef Instr, unsigned index, LLVMAttributeRef attr) {
   CallSite Call = CallSite(unwrap<Instruction>(Instr));
-  AttrBuilder B;
-  B.addRawValue(Val);
+  AttrBuilder B(unwrap(attr));
   Call.setAttributes(
     Call.getAttributes().addAttributes(Call->getContext(), index,
                                        AttributeSet::get(Call->getContext(),
                                                          index, B)));
 }
 
-
 extern "C" void LLVMRustAddDereferenceableCallSiteAttr(LLVMValueRef Instr,
-						       unsigned idx,
-						       uint64_t b)
+                                                      unsigned index,
+                                                      uint64_t bytes)
 {
   CallSite Call = CallSite(unwrap<Instruction>(Instr));
   AttrBuilder B;
-  B.addDereferenceableAttr(b);
+  B.addDereferenceableAttr(bytes);
   Call.setAttributes(
-    Call.getAttributes().addAttributes(Call->getContext(), idx,
+    Call.getAttributes().addAttributes(Call->getContext(), index,
                                        AttributeSet::get(Call->getContext(),
-                                                         idx, B)));
+                                                         index, B)));
 }
 
 extern "C" void LLVMRustAddFunctionAttribute(LLVMValueRef Fn,
 					     unsigned index,
-					     uint64_t Val)
+					     LLVMAttributeRef attr)
 {
   Function *A = unwrap<Function>(Fn);
-  AttrBuilder B;
-  B.addRawValue(Val);
+  AttrBuilder B(unwrap(attr));
   A->addAttributes(index, AttributeSet::get(A->getContext(), index, B));
 }
 
@@ -153,16 +200,6 @@ extern "C" void LLVMRustAddDereferenceableAttr(LLVMValueRef Fn,
   A->addAttributes(index, AttributeSet::get(A->getContext(), index, B));
 }
 
-extern "C" void LLVMRustAddFunctionAttrString(LLVMValueRef Fn,
-					      unsigned index,
-					      const char *Name)
-{
-  Function *F = unwrap<Function>(Fn);
-  AttrBuilder B;
-  B.addAttribute(Name);
-  F->addAttributes(index, AttributeSet::get(F->getContext(), index, B));
-}
-
 extern "C" void LLVMRustAddFunctionAttrStringValue(LLVMValueRef Fn,
 						   unsigned index,
 						   const char *Name,
@@ -175,31 +212,15 @@ extern "C" void LLVMRustAddFunctionAttrStringValue(LLVMValueRef Fn,
 
 extern "C" void LLVMRustRemoveFunctionAttributes(LLVMValueRef Fn,
 						 unsigned index,
-						 uint64_t Val)
+						 LLVMAttributeRef attr)
 {
-  Function *A = unwrap<Function>(Fn);
-  const AttributeSet PAL = A->getAttributes();
-  AttrBuilder B(Val);
+  Function *F = unwrap<Function>(Fn);
+  const AttributeSet PAL = F->getAttributes();
+  AttrBuilder B(unwrap(attr));
   const AttributeSet PALnew =
-    PAL.removeAttributes(A->getContext(), index,
-                         AttributeSet::get(A->getContext(), index, B));
-  A->setAttributes(PALnew);
-}
-
-extern "C" void LLVMRustRemoveFunctionAttrString(LLVMValueRef fn,
-						 unsigned index,
-						 const char *Name)
-{
-  Function *f = unwrap<Function>(fn);
-  LLVMContext &C = f->getContext();
-  AttrBuilder B;
-  B.addAttribute(Name);
-  AttributeSet to_remove = AttributeSet::get(C, index, B);
-
-  AttributeSet attrs = f->getAttributes();
-  f->setAttributes(attrs.removeAttributes(f->getContext(),
-                                          index,
-                                          to_remove));
+    PAL.removeAttributes(F->getContext(), index,
+                         AttributeSet::get(F->getContext(), index, B));
+  F->setAttributes(PALnew);
 }
 
 // enable fpmath flag UnsafeAlgebra
@@ -1293,3 +1314,7 @@ extern "C" LLVMRustLinkage LLVMRustGetLinkage(LLVMValueRef V) {
 extern "C" void LLVMRustSetLinkage(LLVMValueRef V, LLVMRustLinkage RustLinkage) {
     LLVMSetLinkage(V, from_rust(RustLinkage));
 }
+
+extern "C" LLVMContextRef LLVMRustGetValueContext(LLVMValueRef V) {
+    return wrap(&unwrap(V)->getContext());
+}
diff --git a/src/rustllvm/rustllvm.h b/src/rustllvm/rustllvm.h
index ffe94d1e22f..346153d578c 100644
--- a/src/rustllvm/rustllvm.h
+++ b/src/rustllvm/rustllvm.h
@@ -72,6 +72,28 @@ enum class LLVMRustResult {
     Failure
 };
 
+enum LLVMRustAttribute {
+    AlwaysInline    = 0,
+    ByVal           = 1,
+    Cold            = 2,
+    InlineHint      = 3,
+    MinSize         = 4,
+    Naked           = 5,
+    NoAlias         = 6,
+    NoCapture       = 7,
+    NoInline        = 8,
+    NonNull         = 9,
+    NoRedZone       = 10,
+    NoReturn        = 11,
+    NoUnwind        = 12,
+    OptimizeForSize = 13,
+    ReadOnly        = 14,
+    SExt            = 15,
+    StructRet       = 16,
+    UWTable         = 17,
+    ZExt            = 18,
+};
+
 typedef struct OpaqueRustString *RustStringRef;
 typedef struct LLVMOpaqueTwine *LLVMTwineRef;
 typedef struct LLVMOpaqueDebugLoc *LLVMDebugLocRef;