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::*;
}
bitflags! {
- #[derive(Debug)]
+ #[derive(Default, Debug)]
flags Attribute : u64 {
const ZExt = 1 << 0,
const SExt = 1 << 1,
// 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 {
}
}
- 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) {
//! 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;
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);
}
// 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;
// `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);
}
_ => {}
}
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);
}
}
}
// 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);
}
}
}
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);
}
}
// 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);
}
}