rustc_llvm: An AttrBuilder that's not completely wasteful.

This commit is contained in:
Eduard Burtescu 2016-02-25 19:08:10 +02:00
parent 763b6cba37
commit c7172a9935
3 changed files with 114 additions and 103 deletions

View 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,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) {

View File

@ -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;

View 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(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);
}
}