From 17256197a963561d02faff0634e11d7a079e7105 Mon Sep 17 00:00:00 2001 From: Luqman Aden Date: Fri, 25 Jul 2014 16:06:44 -0700 Subject: [PATCH] librustc: Use builder for llvm attributes. --- src/librustc/middle/trans/base.rs | 73 ++++++++++---------- src/librustc/middle/trans/build.rs | 8 +-- src/librustc/middle/trans/builder.rs | 22 +++--- src/librustc/middle/trans/closure.rs | 2 +- src/librustc/middle/trans/expr.rs | 2 +- src/librustc/middle/trans/foreign.rs | 16 ++--- src/librustc/middle/trans/glue.rs | 8 +-- src/librustc/middle/trans/intrinsic.rs | 14 ++-- src/librustc_llvm/lib.rs | 93 ++++++++++++++++++++++++++ src/rustllvm/RustWrapper.cpp | 17 +++++ 10 files changed, 181 insertions(+), 74 deletions(-) diff --git a/src/librustc/middle/trans/base.rs b/src/librustc/middle/trans/base.rs index fcdcb7847cb..41493ce38c4 100644 --- a/src/librustc/middle/trans/base.rs +++ b/src/librustc/middle/trans/base.rs @@ -281,11 +281,7 @@ pub fn decl_rust_fn(ccx: &CrateContext, fn_ty: ty::t, name: &str) -> ValueRef { let llfn = decl_fn(ccx, name, llvm::CCallConv, llfty, output); let attrs = get_fn_llvm_attributes(ccx, fn_ty); - for &(idx, attr) in attrs.iter() { - unsafe { - llvm::LLVMAddFunctionAttribute(llfn, idx as c_uint, attr); - } - } + attrs.apply_llfn(llfn); llfn } @@ -962,7 +958,7 @@ pub fn invoke<'a>( llargs.as_slice(), normal_bcx.llbb, landing_pad, - attributes.as_slice()); + Some(attributes)); return (llresult, normal_bcx); } else { debug!("calling {} at {}", llfn, bcx.llbb); @@ -975,7 +971,7 @@ pub fn invoke<'a>( None => debuginfo::clear_source_location(bcx.fcx) }; - let llresult = Call(bcx, llfn, llargs.as_slice(), attributes.as_slice()); + let llresult = Call(bcx, llfn, llargs.as_slice(), Some(attributes)); return (llresult, bcx); } } @@ -1081,7 +1077,7 @@ pub fn call_lifetime_start(cx: &Block, ptr: ValueRef) { let llsize = C_u64(ccx, machine::llsize_of_alloc(ccx, val_ty(ptr).element_type())); let ptr = PointerCast(cx, ptr, Type::i8p(ccx)); let lifetime_start = ccx.get_intrinsic(&"llvm.lifetime.start"); - Call(cx, lifetime_start, [llsize, ptr], []); + Call(cx, lifetime_start, [llsize, ptr], None); } pub fn call_lifetime_end(cx: &Block, ptr: ValueRef) { @@ -1095,7 +1091,7 @@ pub fn call_lifetime_end(cx: &Block, ptr: ValueRef) { let llsize = C_u64(ccx, machine::llsize_of_alloc(ccx, val_ty(ptr).element_type())); let ptr = PointerCast(cx, ptr, Type::i8p(ccx)); let lifetime_end = ccx.get_intrinsic(&"llvm.lifetime.end"); - Call(cx, lifetime_end, [llsize, ptr], []); + Call(cx, lifetime_end, [llsize, ptr], None); } pub fn call_memcpy(cx: &Block, dst: ValueRef, src: ValueRef, n_bytes: ValueRef, align: u32) { @@ -1111,7 +1107,7 @@ pub fn call_memcpy(cx: &Block, dst: ValueRef, src: ValueRef, n_bytes: ValueRef, let size = IntCast(cx, n_bytes, ccx.int_type); let align = C_i32(ccx, align as i32); let volatile = C_bool(ccx, false); - Call(cx, memcpy, [dst_ptr, src_ptr, size, align, volatile], []); + Call(cx, memcpy, [dst_ptr, src_ptr, size, align, volatile], None); } pub fn memcpy_ty(bcx: &Block, dst: ValueRef, src: ValueRef, t: ty::t) { @@ -1156,7 +1152,7 @@ fn memzero(b: &Builder, llptr: ValueRef, ty: Type) { let size = machine::llsize_of(ccx, ty); let align = C_i32(ccx, llalign_of_min(ccx, ty) as i32); let volatile = C_bool(ccx, false); - b.call(llintrinsicfn, [llptr, llzeroval, size, align, volatile], []); + b.call(llintrinsicfn, [llptr, llzeroval, size, align, volatile], None); } pub fn alloc_ty(bcx: &Block, t: ty::t, name: &str) -> ValueRef { @@ -2040,7 +2036,7 @@ fn register_fn(ccx: &CrateContext, } pub fn get_fn_llvm_attributes(ccx: &CrateContext, fn_ty: ty::t) - -> Vec<(uint, u64)> { + -> llvm::AttrBuilder { use middle::ty::{BrAnon, ReLateBound}; let (fn_sig, abi, has_env) = match ty::get(fn_ty).sty { @@ -2056,31 +2052,30 @@ pub fn get_fn_llvm_attributes(ccx: &CrateContext, fn_ty: ty::t) _ => fail!("expected closure or function.") }; + // Since index 0 is the return value of the llvm func, we start + // at either 1 or 2 depending on whether there's an env slot or not + let mut first_arg_offset = if has_env { 2 } else { 1 }; + let mut attrs = llvm::AttrBuilder::new(); + let ret_ty = fn_sig.output; + // These have an odd calling convention, so we skip them for now. // // FIXME(pcwalton): We don't have to skip them; just untuple the result. if abi == RustCall { - return Vec::new() + return attrs; } - // Since index 0 is the return value of the llvm func, we start - // at either 1 or 2 depending on whether there's an env slot or not - let mut first_arg_offset = if has_env { 2 } else { 1 }; - let mut attrs = Vec::new(); - let ret_ty = fn_sig.output; - // A function pointer is called without the declaration // available, so we have to apply any attributes with ABI // implications directly to the call instruction. Right now, // the only attribute we need to worry about is `sret`. if type_of::return_uses_outptr(ccx, ret_ty) { - attrs.push((1, llvm::StructRetAttribute as u64)); - // The outptr can be noalias and nocapture because it's entirely // invisible to the program. We can also mark it as nonnull - attrs.push((1, llvm::NoAliasAttribute as u64)); - attrs.push((1, llvm::NoCaptureAttribute as u64)); - attrs.push((1, llvm::NonNullAttribute as u64)); + attrs.arg(1, llvm::StructRetAttribute) + .arg(1, llvm::NoAliasAttribute) + .arg(1, llvm::NoCaptureAttribute) + .arg(1, llvm::NonNullAttribute); // Add one more since there's an outptr first_arg_offset += 1; @@ -2094,7 +2089,7 @@ pub fn get_fn_llvm_attributes(ccx: &CrateContext, fn_ty: ty::t) ty::ty_str | ty::ty_vec(..) | ty::ty_trait(..) => true, _ => false } => {} ty::ty_uniq(_) => { - attrs.push((llvm::ReturnIndex as uint, llvm::NoAliasAttribute as u64)); + attrs.ret(llvm::NoAliasAttribute); } _ => {} } @@ -2107,14 +2102,14 @@ pub fn get_fn_llvm_attributes(ccx: &CrateContext, fn_ty: ty::t) ty::ty_str | ty::ty_vec(..) | ty::ty_trait(..) => true, _ => false } => {} ty::ty_uniq(_) | ty::ty_rptr(_, _) => { - attrs.push((llvm::ReturnIndex as uint, llvm::NonNullAttribute as u64)); + attrs.ret(llvm::NonNullAttribute); } _ => {} } match ty::get(ret_ty).sty { ty::ty_bool => { - attrs.push((llvm::ReturnIndex as uint, llvm::ZExtAttribute as u64)); + attrs.ret(llvm::ZExtAttribute); } _ => {} } @@ -2127,28 +2122,28 @@ pub fn get_fn_llvm_attributes(ccx: &CrateContext, fn_ty: ty::t) // 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.push((idx, llvm::NoAliasAttribute as u64)); - attrs.push((idx, llvm::NoCaptureAttribute as u64)); - attrs.push((idx, llvm::NonNullAttribute as u64)); + attrs.arg(idx, llvm::NoAliasAttribute) + .arg(idx, llvm::NoCaptureAttribute) + .arg(idx, llvm::NonNullAttribute); } ty::ty_bool => { - attrs.push((idx, llvm::ZExtAttribute as u64)); + attrs.arg(idx, llvm::ZExtAttribute); } // `~` pointer parameters never alias because ownership is transferred ty::ty_uniq(_) => { - attrs.push((idx, llvm::NoAliasAttribute as u64)); - attrs.push((idx, llvm::NonNullAttribute as u64)); + attrs.arg(idx, llvm::NoAliasAttribute) + .arg(idx, llvm::NonNullAttribute); } // `&mut` pointer parameters never alias other parameters, or mutable global data // `&` pointer parameters never alias either (for LLVM's purposes) as long as the // interior is safe ty::ty_rptr(b, mt) if mt.mutbl == ast::MutMutable || !ty::type_contents(ccx.tcx(), mt.ty).interior_unsafe() => { - attrs.push((idx, llvm::NoAliasAttribute as u64)); - attrs.push((idx, llvm::NonNullAttribute as u64)); + attrs.arg(idx, llvm::NoAliasAttribute) + .arg(idx, llvm::NonNullAttribute); match b { ReLateBound(_, BrAnon(_)) => { - attrs.push((idx, llvm::NoCaptureAttribute as u64)); + attrs.arg(idx, llvm::NoCaptureAttribute); } _ => {} } @@ -2156,12 +2151,12 @@ pub fn get_fn_llvm_attributes(ccx: &CrateContext, fn_ty: ty::t) // 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). ty::ty_rptr(ReLateBound(_, BrAnon(_)), _) => { - attrs.push((idx, llvm::NoCaptureAttribute as u64)); - attrs.push((idx, llvm::NonNullAttribute as u64)); + attrs.arg(idx, llvm::NoCaptureAttribute) + .arg(idx, llvm::NonNullAttribute); } // & pointer parameters are never null ty::ty_rptr(_, _) => { - attrs.push((idx, llvm::NonNullAttribute as u64)); + attrs.arg(idx, llvm::NonNullAttribute); } _ => () } diff --git a/src/librustc/middle/trans/build.rs b/src/librustc/middle/trans/build.rs index 995ad16b59f..d2ddf3ff696 100644 --- a/src/librustc/middle/trans/build.rs +++ b/src/librustc/middle/trans/build.rs @@ -12,7 +12,7 @@ #![allow(non_snake_case_functions)] use llvm; -use llvm::{CallConv, AtomicBinOp, AtomicOrdering, AsmDialect}; +use llvm::{CallConv, AtomicBinOp, AtomicOrdering, AsmDialect, AttrBuilder}; use llvm::{Opcode, IntPredicate, RealPredicate}; use llvm::{ValueRef, BasicBlockRef}; use middle::trans::common::*; @@ -113,7 +113,7 @@ pub fn Invoke(cx: &Block, args: &[ValueRef], then: BasicBlockRef, catch: BasicBlockRef, - attributes: &[(uint, u64)]) + attributes: Option) -> ValueRef { if cx.unreachable.get() { return C_null(Type::i8(cx.ccx())); @@ -681,13 +681,13 @@ pub fn InlineAsmCall(cx: &Block, asm: *const c_char, cons: *const c_char, } pub fn Call(cx: &Block, fn_: ValueRef, args: &[ValueRef], - attributes: &[(uint, u64)]) -> ValueRef { + attributes: Option) -> ValueRef { if cx.unreachable.get() { return _UndefReturn(cx, fn_); } B(cx).call(fn_, args, attributes) } pub fn CallWithConv(cx: &Block, fn_: ValueRef, args: &[ValueRef], conv: CallConv, - attributes: &[(uint, u64)]) -> ValueRef { + attributes: Option) -> ValueRef { if cx.unreachable.get() { return _UndefReturn(cx, fn_); } B(cx).call_with_conv(fn_, args, conv, attributes) } diff --git a/src/librustc/middle/trans/builder.rs b/src/librustc/middle/trans/builder.rs index 32e91c337f0..b3192a405be 100644 --- a/src/librustc/middle/trans/builder.rs +++ b/src/librustc/middle/trans/builder.rs @@ -11,7 +11,7 @@ #![allow(dead_code)] // FFI wrappers use llvm; -use llvm::{CallConv, AtomicBinOp, AtomicOrdering, AsmDialect}; +use llvm::{CallConv, AtomicBinOp, AtomicOrdering, AsmDialect, AttrBuilder}; use llvm::{Opcode, IntPredicate, RealPredicate, False}; use llvm::{ValueRef, BasicBlockRef, BuilderRef, ModuleRef}; use middle::trans::base; @@ -155,7 +155,7 @@ impl<'a> Builder<'a> { args: &[ValueRef], then: BasicBlockRef, catch: BasicBlockRef, - attributes: &[(uint, u64)]) + attributes: Option) -> ValueRef { self.count_insn("invoke"); @@ -174,8 +174,9 @@ impl<'a> Builder<'a> { then, catch, noname()); - for &(idx, attr) in attributes.iter() { - llvm::LLVMAddCallSiteAttribute(v, idx as c_uint, attr); + match attributes { + Some(a) => a.apply_callsite(v), + None => {} } v } @@ -777,7 +778,7 @@ impl<'a> Builder<'a> { c, noname(), False, False) } }); - self.call(asm, [], []); + self.call(asm, [], None); } } @@ -802,12 +803,12 @@ impl<'a> Builder<'a> { unsafe { let v = llvm::LLVMInlineAsm( fty.to_ref(), asm, cons, volatile, alignstack, dia as c_uint); - self.call(v, inputs, []) + self.call(v, inputs, None) } } pub fn call(&self, llfn: ValueRef, args: &[ValueRef], - attributes: &[(uint, u64)]) -> ValueRef { + attributes: Option) -> ValueRef { self.count_insn("call"); debug!("Call {} with args ({})", @@ -820,15 +821,16 @@ impl<'a> Builder<'a> { unsafe { let v = llvm::LLVMBuildCall(self.llbuilder, llfn, args.as_ptr(), args.len() as c_uint, noname()); - for &(idx, attr) in attributes.iter() { - llvm::LLVMAddCallSiteAttribute(v, idx as c_uint, attr); + match attributes { + Some(a) => a.apply_callsite(v), + None => {} } v } } pub fn call_with_conv(&self, llfn: ValueRef, args: &[ValueRef], - conv: CallConv, attributes: &[(uint, u64)]) -> ValueRef { + conv: CallConv, attributes: Option) -> ValueRef { self.count_insn("callwithconv"); let v = self.call(llfn, args, attributes); llvm::SetInstructionCallConv(v, conv); diff --git a/src/librustc/middle/trans/closure.rs b/src/librustc/middle/trans/closure.rs index ed6050b6543..a65d208d4d2 100644 --- a/src/librustc/middle/trans/closure.rs +++ b/src/librustc/middle/trans/closure.rs @@ -588,7 +588,7 @@ pub fn get_wrapper_for_bare_fn(ccx: &CrateContext, } llargs.extend(args.iter().map(|arg| arg.val)); - let retval = Call(bcx, fn_ptr, llargs.as_slice(), []); + let retval = Call(bcx, fn_ptr, llargs.as_slice(), None); if type_is_zero_size(ccx, f.sig.output) || fcx.llretptr.get().is_some() { RetVoid(bcx); } else { diff --git a/src/librustc/middle/trans/expr.rs b/src/librustc/middle/trans/expr.rs index 9d970b1a393..1dad6e3cb18 100644 --- a/src/librustc/middle/trans/expr.rs +++ b/src/librustc/middle/trans/expr.rs @@ -553,7 +553,7 @@ fn trans_index<'a>(bcx: &'a Block<'a>, let expected = Call(bcx, expect, [bounds_check, C_bool(ccx, false)], - []); + None); bcx = with_cond(bcx, expected, |bcx| { controlflow::trans_fail_bounds_check(bcx, index_expr.span, diff --git a/src/librustc/middle/trans/foreign.rs b/src/librustc/middle/trans/foreign.rs index d7630d7ec3a..8fb36862f0d 100644 --- a/src/librustc/middle/trans/foreign.rs +++ b/src/librustc/middle/trans/foreign.rs @@ -382,21 +382,21 @@ pub fn trans_native_call<'a>( // A function pointer is called without the declaration available, so we have to apply // any attributes with ABI implications directly to the call instruction. - let mut attrs = Vec::new(); + let mut attrs = llvm::AttrBuilder::new(); // Add attributes that are always applicable, independent of the concrete foreign ABI if fn_type.ret_ty.is_indirect() { // The outptr can be noalias and nocapture because it's entirely // invisible to the program. We can also mark it as nonnull - attrs.push((1, llvm::NoAliasAttribute as u64)); - attrs.push((1, llvm::NoCaptureAttribute as u64)); - attrs.push((1, llvm::NonNullAttribute as u64)); + attrs.arg(1, llvm::NoAliasAttribute) + .arg(1, llvm::NoCaptureAttribute) + .arg(1, llvm::NonNullAttribute); }; // Add attributes that depend on the concrete foreign ABI let mut arg_idx = if fn_type.ret_ty.is_indirect() { 1 } else { 0 }; match fn_type.ret_ty.attr { - Some(attr) => attrs.push((arg_idx, attr as u64)), + Some(attr) => { attrs.arg(arg_idx, attr); }, _ => () } @@ -409,7 +409,7 @@ pub fn trans_native_call<'a>( if arg_ty.pad.is_some() { arg_idx += 1; } match arg_ty.attr { - Some(attr) => attrs.push((arg_idx, attr as u64)), + Some(attr) => { attrs.arg(arg_idx, attr); }, _ => {} } @@ -420,7 +420,7 @@ pub fn trans_native_call<'a>( llfn, llargs_foreign.as_slice(), cc, - attrs.as_slice()); + Some(attrs)); // If the function we just called does not use an outpointer, // store the result into the rust outpointer. Cast the outpointer @@ -762,7 +762,7 @@ pub fn trans_rust_fn_with_foreign_abi(ccx: &CrateContext, // Perform the call itself debug!("calling llrustfn = {}, t = {}", ccx.tn.val_to_string(llrustfn), t.repr(ccx.tcx())); let attributes = base::get_fn_llvm_attributes(ccx, t); - let llrust_ret_val = builder.call(llrustfn, llrust_args.as_slice(), attributes.as_slice()); + let llrust_ret_val = builder.call(llrustfn, llrust_args.as_slice(), Some(attributes)); // Get the return value where the foreign fn expects it. let llforeign_ret_ty = match tys.fn_ty.ret_ty.cast { diff --git a/src/librustc/middle/trans/glue.rs b/src/librustc/middle/trans/glue.rs index 2d2e5f141a5..5c978d505cb 100644 --- a/src/librustc/middle/trans/glue.rs +++ b/src/librustc/middle/trans/glue.rs @@ -129,7 +129,7 @@ pub fn drop_ty<'a>(bcx: &'a Block<'a>, v: ValueRef, t: ty::t) } else { v }; - Call(bcx, glue, [ptr], []); + Call(bcx, glue, [ptr], None); } bcx } @@ -185,7 +185,7 @@ pub fn call_visit_glue(bcx: &Block, v: ValueRef, tydesc: ValueRef) { let llfn = Load(bcx, GEPi(bcx, tydesc, [0u, abi::tydesc_field_visit_glue])); let llrawptr = PointerCast(bcx, v, Type::i8p(bcx.ccx())); - Call(bcx, llfn, [llrawptr], []); + Call(bcx, llfn, [llrawptr], None); } fn make_visit_glue<'a>(bcx: &'a Block<'a>, v: ValueRef, t: ty::t) @@ -303,7 +303,7 @@ fn make_drop_glue<'a>(bcx: &'a Block<'a>, v0: ValueRef, t: ty::t) -> &'a Block<' Call(bcx, dtor, [PointerCast(bcx, lluniquevalue, Type::i8p(bcx.ccx()))], - []); + None); bcx }) } @@ -342,7 +342,7 @@ fn make_drop_glue<'a>(bcx: &'a Block<'a>, v0: ValueRef, t: ty::t) -> &'a Block<' let dtor_ptr = GEPi(bcx, env, [0u, abi::box_field_tydesc]); let dtor = Load(bcx, dtor_ptr); let cdata = GEPi(bcx, env, [0u, abi::box_field_body]); - Call(bcx, dtor, [PointerCast(bcx, cdata, Type::i8p(bcx.ccx()))], []); + Call(bcx, dtor, [PointerCast(bcx, cdata, Type::i8p(bcx.ccx()))], None); // Free the environment itself // FIXME: #13994: pass align and size here diff --git a/src/librustc/middle/trans/intrinsic.rs b/src/librustc/middle/trans/intrinsic.rs index bf8893904ca..fb420a4035d 100644 --- a/src/librustc/middle/trans/intrinsic.rs +++ b/src/librustc/middle/trans/intrinsic.rs @@ -208,17 +208,17 @@ pub fn trans_intrinsic_call<'a>(mut bcx: &'a Block<'a>, node: ast::NodeId, let llval = match (simple, name.get()) { (Some(llfn), _) => { - Call(bcx, llfn, llargs.as_slice(), []) + Call(bcx, llfn, llargs.as_slice(), None) } (_, "abort") => { let llfn = ccx.get_intrinsic(&("llvm.trap")); - let v = Call(bcx, llfn, [], []); + let v = Call(bcx, llfn, [], None); Unreachable(bcx); v } (_, "breakpoint") => { let llfn = ccx.get_intrinsic(&("llvm.debugtrap")); - Call(bcx, llfn, [], []) + Call(bcx, llfn, [], None) } (_, "size_of") => { let tp_ty = *substs.types.get(FnSpace, 0); @@ -553,7 +553,7 @@ fn copy_intrinsic(bcx: &Block, allow_overlap: bool, volatile: bool, let llfn = ccx.get_intrinsic(&name); Call(bcx, llfn, [dst_ptr, src_ptr, Mul(bcx, size, count), align, - C_bool(ccx, volatile)], []) + C_bool(ccx, volatile)], None) } fn memset_intrinsic(bcx: &Block, volatile: bool, tp_ty: ty::t, @@ -572,13 +572,13 @@ fn memset_intrinsic(bcx: &Block, volatile: bool, tp_ty: ty::t, let llfn = ccx.get_intrinsic(&name); Call(bcx, llfn, [dst_ptr, val, Mul(bcx, size, count), align, - C_bool(ccx, volatile)], []) + C_bool(ccx, volatile)], None) } fn count_zeros_intrinsic(bcx: &Block, name: &'static str, val: ValueRef) -> ValueRef { let y = C_bool(bcx.ccx(), false); let llfn = bcx.ccx().get_intrinsic(&name); - Call(bcx, llfn, [val, y], []) + Call(bcx, llfn, [val, y], None) } fn with_overflow_intrinsic(bcx: &Block, name: &'static str, t: ty::t, @@ -586,7 +586,7 @@ fn with_overflow_intrinsic(bcx: &Block, name: &'static str, t: ty::t, let llfn = bcx.ccx().get_intrinsic(&name); // Convert `i1` to a `bool`, and write it to the out parameter - let val = Call(bcx, llfn, [a, b], []); + let val = Call(bcx, llfn, [a, b], None); let result = ExtractValue(bcx, val, 0); let overflow = ZExt(bcx, ExtractValue(bcx, val, 1), Type::bool(bcx.ccx())); let ret = C_undef(type_of::type_of(bcx.ccx(), t)); diff --git a/src/librustc_llvm/lib.rs b/src/librustc_llvm/lib.rs index 215ae444b69..1ac0aee85d4 100644 --- a/src/librustc_llvm/lib.rs +++ b/src/librustc_llvm/lib.rs @@ -130,12 +130,101 @@ pub enum OtherAttribute { NonNullAttribute = 1 << 44, } +pub enum SpecialAttribute { + DereferenceableAttribute(u64) +} + #[repr(C)] pub enum AttributeSet { ReturnIndex = 0, FunctionIndex = !0 } +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 as uint64_t); + } + } + + fn apply_callsite(&self, idx: c_uint, callsite: ValueRef) { + unsafe { + LLVMAddCallSiteAttribute(callsite, idx, *self as uint64_t); + } + } +} + +impl AttrHelper for OtherAttribute { + fn apply_llfn(&self, idx: c_uint, llfn: ValueRef) { + unsafe { + LLVMAddFunctionAttribute(llfn, idx, *self as uint64_t); + } + } + + fn apply_callsite(&self, idx: c_uint, callsite: ValueRef) { + unsafe { + LLVMAddCallSiteAttribute(callsite, idx, *self 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<(uint, Box)> +} + +impl AttrBuilder { + pub fn new() -> AttrBuilder { + AttrBuilder { + attrs: Vec::new() + } + } + + pub fn arg<'a, T: AttrHelper + 'static>(&'a mut self, idx: uint, a: T) -> &'a mut AttrBuilder { + self.attrs.push((idx, box a as Box)); + self + } + + pub fn ret<'a, T: AttrHelper + 'static>(&'a mut self, a: T) -> &'a mut AttrBuilder { + self.attrs.push((ReturnIndex as uint, box a as Box)); + self + } + + pub fn apply_llfn(&self, llfn: ValueRef) { + for &(idx, ref attr) in self.attrs.iter() { + attr.apply_llfn(idx as c_uint, llfn); + } + } + + pub fn apply_callsite(&self, callsite: ValueRef) { + for &(idx, ref attr) in self.attrs.iter() { + attr.apply_callsite(idx as c_uint, callsite); + } + } +} + // enum for the LLVM IntPredicate type pub enum IntPredicate { IntEQ = 32, @@ -740,6 +829,7 @@ extern { pub fn LLVMSetFunctionCallConv(Fn: ValueRef, CC: c_uint); pub fn LLVMGetGC(Fn: ValueRef) -> *const c_char; pub fn LLVMSetGC(Fn: ValueRef, Name: *const c_char); + pub fn LLVMAddDereferenceableAttr(Fn: ValueRef, index: c_uint, bytes: uint64_t); pub fn LLVMAddFunctionAttribute(Fn: ValueRef, index: c_uint, PA: uint64_t); pub fn LLVMAddFunctionAttrString(Fn: ValueRef, index: c_uint, Name: *const c_char); pub fn LLVMRemoveFunctionAttrString(Fn: ValueRef, index: c_uint, Name: *const c_char); @@ -811,6 +901,9 @@ extern { pub fn LLVMAddCallSiteAttribute(Instr: ValueRef, index: c_uint, Val: uint64_t); + pub fn LLVMAddDereferenceableCallSiteAttr(Instr: ValueRef, + index: c_uint, + bytes: uint64_t); /* Operations on call instructions (only) */ pub fn LLVMIsTailCall(CallInst: ValueRef) -> Bool; diff --git a/src/rustllvm/RustWrapper.cpp b/src/rustllvm/RustWrapper.cpp index e28a78b1ee7..bb4a1b6461a 100644 --- a/src/rustllvm/RustWrapper.cpp +++ b/src/rustllvm/RustWrapper.cpp @@ -113,6 +113,16 @@ extern "C" void LLVMAddCallSiteAttribute(LLVMValueRef Instr, unsigned index, uin index, B))); } +extern "C" void LLVMAddDereferenceableCallSiteAttr(LLVMValueRef Instr, unsigned idx, uint64_t b) { + CallSite Call = CallSite(unwrap(Instr)); + AttrBuilder B; + B.addDereferenceableAttr(b); + Call.setAttributes( + Call.getAttributes().addAttributes(Call->getContext(), idx, + AttributeSet::get(Call->getContext(), + idx, B))); +} + extern "C" void LLVMAddFunctionAttribute(LLVMValueRef Fn, unsigned index, uint64_t Val) { Function *A = unwrap(Fn); AttrBuilder B; @@ -120,6 +130,13 @@ extern "C" void LLVMAddFunctionAttribute(LLVMValueRef Fn, unsigned index, uint64 A->addAttributes(index, AttributeSet::get(A->getContext(), index, B)); } +extern "C" void LLVMAddDereferenceableAttr(LLVMValueRef Fn, unsigned index, uint64_t bytes) { + Function *A = unwrap(Fn); + AttrBuilder B; + B.addDereferenceableAttr(bytes); + A->addAttributes(index, AttributeSet::get(A->getContext(), index, B)); +} + extern "C" void LLVMAddFunctionAttrString(LLVMValueRef Fn, unsigned index, const char *Name) { Function *F = unwrap(Fn); AttrBuilder B;