Skip to content

Commit c7172a9

Browse files
committed
rustc_llvm: An AttrBuilder that's not completely wasteful.
1 parent 763b6cb commit c7172a9

File tree

3 files changed

+106
-95
lines changed

3 files changed

+106
-95
lines changed

src/librustc_llvm/lib.rs

Lines changed: 74 additions & 61 deletions
Original file line numberDiff line numberDiff line change
@@ -33,8 +33,6 @@
3333
extern crate libc;
3434
#[macro_use] #[no_link] extern crate rustc_bitflags;
3535

36-
pub use self::OtherAttribute::*;
37-
pub use self::SpecialAttribute::*;
3836
pub use self::AttributeSet::*;
3937
pub use self::IntPredicate::*;
4038
pub use self::RealPredicate::*;
@@ -133,7 +131,7 @@ pub enum DLLStorageClassTypes {
133131
}
134132

135133
bitflags! {
136-
#[derive(Debug)]
134+
#[derive(Default, Debug)]
137135
flags Attribute : u64 {
138136
const ZExt = 1 << 0,
139137
const SExt = 1 << 1,
@@ -165,79 +163,85 @@ bitflags! {
165163
// FIXME: These attributes are currently not included in the C API as
166164
// a temporary measure until the API/ABI impact to the C API is understood
167165
// and the path forward agreed upon.
168-
const SanitizeAddress = 1 << 32;
169-
const MinSize = 1 << 33;
170-
const NoDuplicate = 1 << 34;
171-
const StackProtectStrong = 1 << 35;
172-
const SanitizeThread = 1 << 36;
173-
const SanitizeMemory = 1 << 37;
174-
const NoBuiltin = 1 << 38;
175-
const Returned = 1 << 39;
176-
const Cold = 1 << 40;
177-
const Builtin = 1 << 41;
178-
const OptimizeNone = 1 << 42;
179-
const InAlloca = 1 << 43;
180-
const NonNull = 1 << 44;
181-
const JumpTable = 1 << 45;
182-
const Convergent = 1 << 46;
183-
const SafeStack = 1 << 47;
184-
const NoRecurse = 1 << 48;
185-
const InaccessibleMemOnly = 1 << 49;
186-
const InaccessibleMemOrArgMemOnly = 1 << 50;
166+
const SanitizeAddress = 1 << 32,
167+
const MinSize = 1 << 33,
168+
const NoDuplicate = 1 << 34,
169+
const StackProtectStrong = 1 << 35,
170+
const SanitizeThread = 1 << 36,
171+
const SanitizeMemory = 1 << 37,
172+
const NoBuiltin = 1 << 38,
173+
const Returned = 1 << 39,
174+
const Cold = 1 << 40,
175+
const Builtin = 1 << 41,
176+
const OptimizeNone = 1 << 42,
177+
const InAlloca = 1 << 43,
178+
const NonNull = 1 << 44,
179+
const JumpTable = 1 << 45,
180+
const Convergent = 1 << 46,
181+
const SafeStack = 1 << 47,
182+
const NoRecurse = 1 << 48,
183+
const InaccessibleMemOnly = 1 << 49,
184+
const InaccessibleMemOrArgMemOnly = 1 << 50,
187185
}
188186
}
189187

190-
#[derive(Copy, Clone)]
191-
pub enum SpecialAttribute {
192-
DereferenceableAttribute(u64)
188+
#[derive(Copy, Clone, Default)]
189+
pub struct Attributes {
190+
regular: Attribute,
191+
dereferenceable_bytes: u64
193192
}
194193

195-
#[repr(C)]
196-
#[derive(Copy, Clone)]
197-
pub enum AttributeSet {
198-
ReturnIndex = 0,
199-
FunctionIndex = !0
200-
}
194+
impl Attributes {
195+
pub fn set(&mut self, attr: Attribute) -> &mut Self {
196+
self.regular = self.regular | attr;
197+
self
198+
}
201199

202-
pub trait AttrHelper {
203-
fn apply_llfn(&self, idx: c_uint, llfn: ValueRef);
204-
fn apply_callsite(&self, idx: c_uint, callsite: ValueRef);
205-
}
200+
pub fn unset(&mut self, attr: Attribute) -> &mut Self {
201+
self.regular = self.regular - attr;
202+
self
203+
}
206204

207-
impl AttrHelper for Attribute {
208-
fn apply_llfn(&self, idx: c_uint, llfn: ValueRef) {
209-
unsafe {
210-
LLVMAddFunctionAttribute(llfn, idx, self.bits() as uint64_t);
211-
}
205+
pub fn set_dereferenceable(&mut self, bytes: u64) -> &mut Self {
206+
self.dereferenceable_bytes = bytes;
207+
self
212208
}
213209

214-
fn apply_callsite(&self, idx: c_uint, callsite: ValueRef) {
215-
unsafe {
216-
LLVMAddCallSiteAttribute(callsite, idx, self.bits() as uint64_t);
217-
}
210+
pub fn unset_dereferenceable(&mut self) -> &mut Self {
211+
self.dereferenceable_bytes = 0;
212+
self
218213
}
219-
}
220214

221-
impl AttrHelper for SpecialAttribute {
222-
fn apply_llfn(&self, idx: c_uint, llfn: ValueRef) {
223-
match *self {
224-
DereferenceableAttribute(bytes) => unsafe {
225-
LLVMAddDereferenceableAttr(llfn, idx, bytes as uint64_t);
215+
pub fn apply_llfn(&self, idx: c_uint, llfn: ValueRef) {
216+
unsafe {
217+
LLVMAddFunctionAttribute(llfn, idx, self.regular.bits());
218+
if self.dereferenceable_bytes != 0 {
219+
LLVMAddDereferenceableAttr(llfn, idx,
220+
self.dereferenceable_bytes);
226221
}
227222
}
228223
}
229224

230-
fn apply_callsite(&self, idx: c_uint, callsite: ValueRef) {
231-
match *self {
232-
DereferenceableAttribute(bytes) => unsafe {
233-
LLVMAddDereferenceableCallSiteAttr(callsite, idx, bytes as uint64_t);
225+
pub fn apply_callsite(&self, idx: c_uint, callsite: ValueRef) {
226+
unsafe {
227+
LLVMAddCallSiteAttribute(callsite, idx, self.regular.bits());
228+
if self.dereferenceable_bytes != 0 {
229+
LLVMAddDereferenceableCallSiteAttr(callsite, idx,
230+
self.dereferenceable_bytes);
234231
}
235232
}
236233
}
237234
}
238235

236+
#[repr(C)]
237+
#[derive(Copy, Clone)]
238+
pub enum AttributeSet {
239+
ReturnIndex = 0,
240+
FunctionIndex = !0
241+
}
242+
239243
pub struct AttrBuilder {
240-
attrs: Vec<(usize, Box<AttrHelper+'static>)>
244+
attrs: Vec<(usize, Attributes)>
241245
}
242246

243247
impl AttrBuilder {
@@ -247,14 +251,23 @@ impl AttrBuilder {
247251
}
248252
}
249253

250-
pub fn arg<T: AttrHelper + 'static>(&mut self, idx: usize, a: T) -> &mut AttrBuilder {
251-
self.attrs.push((idx, box a as Box<AttrHelper+'static>));
252-
self
254+
pub fn arg(&mut self, idx: usize) -> &mut Attributes {
255+
let mut found = None;
256+
for (i, &(idx2, _)) in self.attrs.iter().enumerate() {
257+
if idx == idx2 {
258+
found = Some(i);
259+
break;
260+
}
261+
}
262+
let i = found.unwrap_or_else(|| {
263+
self.attrs.push((idx, Attributes::default()));
264+
self.attrs.len() - 1
265+
});
266+
&mut self.attrs[i].1
253267
}
254268

255-
pub fn ret<T: AttrHelper + 'static>(&mut self, a: T) -> &mut AttrBuilder {
256-
self.attrs.push((ReturnIndex as usize, box a as Box<AttrHelper+'static>));
257-
self
269+
pub fn ret(&mut self) -> &mut Attributes {
270+
self.arg(ReturnIndex as usize)
258271
}
259272

260273
pub fn apply_llfn(&self, llfn: ValueRef) {

src/librustc_trans/trans/abi.rs

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -313,15 +313,15 @@ impl FnType {
313313
// The outptr can be noalias and nocapture because it's entirely
314314
// invisible to the program. We also know it's nonnull as well
315315
// as how many bytes we can dereference
316-
attrs.arg(i, llvm::Attribute::StructRet)
317-
.arg(i, llvm::Attribute::NoAlias)
318-
.arg(i, llvm::Attribute::NoCapture)
319-
.arg(i, llvm::DereferenceableAttribute(llret_sz));
316+
attrs.arg(i).set(llvm::Attribute::StructRet)
317+
.set(llvm::Attribute::NoAlias)
318+
.set(llvm::Attribute::NoCapture)
319+
.set_dereferenceable(llret_sz);
320320
};
321321

322322
// Add attributes that depend on the concrete foreign ABI
323323
if let Some(attr) = self.ret.attr {
324-
attrs.arg(i, attr);
324+
attrs.arg(i).set(attr);
325325
}
326326

327327
i += 1;
@@ -333,7 +333,7 @@ impl FnType {
333333
if arg.pad.is_some() { i += 1; }
334334

335335
if let Some(attr) = arg.attr {
336-
attrs.arg(i, attr);
336+
attrs.arg(i).set(attr);
337337
}
338338

339339
i += 1;

src/librustc_trans/trans/attributes.rs

Lines changed: 26 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010
//! Set and unset common attributes on LLVM values.
1111
1212
use libc::{c_uint, c_ulonglong};
13-
use llvm::{self, ValueRef, AttrHelper};
13+
use llvm::{self, ValueRef};
1414
use middle::ty;
1515
use middle::infer;
1616
use session::config::NoDebugInfo;
@@ -110,13 +110,11 @@ pub fn from_fn_attrs(ccx: &CrateContext, attrs: &[ast::Attribute], llfn: ValueRe
110110

111111
for attr in attrs {
112112
if attr.check_name("cold") {
113-
unsafe {
114-
llvm::LLVMAddFunctionAttribute(llfn,
115-
llvm::FunctionIndex as c_uint,
116-
llvm::ColdAttribute as u64)
117-
}
113+
llvm::Attributes::default().set(llvm::Attribute::Cold)
114+
.apply_llfn(llvm::FunctionIndex as c_uint, llfn)
118115
} else if attr.check_name("allocator") {
119-
llvm::Attribute::NoAlias.apply_llfn(llvm::ReturnIndex as c_uint, llfn);
116+
llvm::Attributes::default().set(llvm::Attribute::NoAlias)
117+
.apply_llfn(llvm::ReturnIndex as c_uint, llfn)
120118
} else if attr.check_name("unwind") {
121119
unwind(llfn, true);
122120
}
@@ -168,10 +166,10 @@ pub fn from_fn_type<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, fn_type: ty::Ty<'tcx
168166
// The outptr can be noalias and nocapture because it's entirely
169167
// invisible to the program. We also know it's nonnull as well
170168
// as how many bytes we can dereference
171-
attrs.arg(1, llvm::Attribute::StructRet)
172-
.arg(1, llvm::Attribute::NoAlias)
173-
.arg(1, llvm::Attribute::NoCapture)
174-
.arg(1, llvm::DereferenceableAttribute(llret_sz));
169+
attrs.arg(1).set(llvm::Attribute::StructRet)
170+
.set(llvm::Attribute::NoAlias)
171+
.set(llvm::Attribute::NoCapture)
172+
.set_dereferenceable(llret_sz);
175173

176174
// Add one more since there's an outptr
177175
idx += 1;
@@ -182,7 +180,7 @@ pub fn from_fn_type<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, fn_type: ty::Ty<'tcx
182180
// `Box` pointer return values never alias because ownership
183181
// is transferred
184182
ty::TyBox(it) if common::type_is_sized(ccx.tcx(), it) => {
185-
attrs.ret(llvm::Attribute::NoAlias);
183+
attrs.ret().set(llvm::Attribute::NoAlias);
186184
}
187185
_ => {}
188186
}
@@ -193,13 +191,13 @@ pub fn from_fn_type<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, fn_type: ty::Ty<'tcx
193191
ty::TyRef(_, ty::TypeAndMut { ty: inner, .. })
194192
| ty::TyBox(inner) if common::type_is_sized(ccx.tcx(), inner) => {
195193
let llret_sz = machine::llsize_of_real(ccx, type_of::type_of(ccx, inner));
196-
attrs.ret(llvm::DereferenceableAttribute(llret_sz));
194+
attrs.ret().set_dereferenceable(llret_sz);
197195
}
198196
_ => {}
199197
}
200198

201199
if let ty::TyBool = ret_ty.sty {
202-
attrs.ret(llvm::Attribute::ZExt);
200+
attrs.ret().set(llvm::Attribute::ZExt);
203201
}
204202
}
205203
}
@@ -212,26 +210,26 @@ pub fn from_fn_type<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, fn_type: ty::Ty<'tcx
212210
// For non-immediate arguments the callee gets its own copy of
213211
// the value on the stack, so there are no aliases. It's also
214212
// program-invisible so can't possibly capture
215-
attrs.arg(idx, llvm::Attribute::NoAlias)
216-
.arg(idx, llvm::Attribute::NoCapture)
217-
.arg(idx, llvm::DereferenceableAttribute(llarg_sz));
213+
attrs.arg(idx).set(llvm::Attribute::NoAlias)
214+
.set(llvm::Attribute::NoCapture)
215+
.set_dereferenceable(llarg_sz);
218216
}
219217

220218
ty::TyBool => {
221-
attrs.arg(idx, llvm::Attribute::ZExt);
219+
attrs.arg(idx).set(llvm::Attribute::ZExt);
222220
}
223221

224222
// `Box` pointer parameters never alias because ownership is transferred
225223
ty::TyBox(inner) => {
226-
attrs.arg(idx, llvm::Attribute::NoAlias);
224+
attrs.arg(idx).set(llvm::Attribute::NoAlias);
227225

228226
if common::type_is_sized(ccx.tcx(), inner) {
229227
let llsz = machine::llsize_of_real(ccx, type_of::type_of(ccx, inner));
230-
attrs.arg(idx, llvm::DereferenceableAttribute(llsz));
228+
attrs.arg(idx).set_dereferenceable(llsz);
231229
} else {
232-
attrs.arg(idx, llvm::NonNullAttribute);
230+
attrs.arg(idx).set(llvm::Attribute::NonNull);
233231
if inner.is_trait() {
234-
attrs.arg(idx + 1, llvm::NonNullAttribute);
232+
attrs.arg(idx + 1).set(llvm::Attribute::NonNull);
235233
}
236234
}
237235
}
@@ -245,30 +243,30 @@ pub fn from_fn_type<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, fn_type: ty::Ty<'tcx
245243
let interior_unsafe = mt.ty.type_contents(ccx.tcx()).interior_unsafe();
246244

247245
if mt.mutbl != hir::MutMutable && !interior_unsafe {
248-
attrs.arg(idx, llvm::Attribute::NoAlias);
246+
attrs.arg(idx).set(llvm::Attribute::NoAlias);
249247
}
250248

251249
if mt.mutbl == hir::MutImmutable && !interior_unsafe {
252-
attrs.arg(idx, llvm::Attribute::ReadOnly);
250+
attrs.arg(idx).set(llvm::Attribute::ReadOnly);
253251
}
254252

255253
// & pointer parameters are also never null and for sized types we also know
256254
// exactly how many bytes we can dereference
257255
if common::type_is_sized(ccx.tcx(), mt.ty) {
258256
let llsz = machine::llsize_of_real(ccx, type_of::type_of(ccx, mt.ty));
259-
attrs.arg(idx, llvm::DereferenceableAttribute(llsz));
257+
attrs.arg(idx).set_dereferenceable(llsz);
260258
} else {
261-
attrs.arg(idx, llvm::NonNullAttribute);
259+
attrs.arg(idx).set(llvm::Attribute::NonNull);
262260
if mt.ty.is_trait() {
263-
attrs.arg(idx + 1, llvm::NonNullAttribute);
261+
attrs.arg(idx + 1).set(llvm::Attribute::NonNull);
264262
}
265263
}
266264

267265
// When a reference in an argument has no named lifetime, it's
268266
// impossible for that reference to escape this function
269267
// (returned or stored beyond the call by a closure).
270268
if let ReLateBound(_, BrAnon(_)) = *b {
271-
attrs.arg(idx, llvm::Attribute::NoCapture);
269+
attrs.arg(idx).set(llvm::Attribute::NoCapture);
272270
}
273271
}
274272

0 commit comments

Comments
 (0)