rustc_llvm: An AttrBuilder that's not completely wasteful.
This commit is contained in:
parent
763b6cba37
commit
c7172a9935
@ -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<AttrHelper+'static>)>
|
||||
attrs: Vec<(usize, Attributes)>
|
||||
}
|
||||
|
||||
impl AttrBuilder {
|
||||
@ -247,14 +251,23 @@ 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) {
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user