auto merge of #14306 : luqmana/rust/up-llvm, r=alexcrichton
We can now mark arguments and returns as `nonnull` in LLVM. It's still somewhat limited by the fact that LLVM loses this information after inlining but it might help in certain cases.
This commit is contained in:
commit
9c870b3d1c
@ -15,7 +15,7 @@
|
||||
use std::c_str::ToCStr;
|
||||
use std::cell::RefCell;
|
||||
use collections::HashMap;
|
||||
use libc::{c_uint, c_ushort, c_void, free};
|
||||
use libc::{c_uint, c_ushort, c_void, free, uint64_t};
|
||||
use std::str::raw::from_c_str;
|
||||
|
||||
use middle::trans::type_::Type;
|
||||
@ -92,6 +92,33 @@ pub enum Attribute {
|
||||
NonLazyBindAttribute = 1 << 31,
|
||||
}
|
||||
|
||||
#[repr(u64)]
|
||||
pub enum OtherAttribute {
|
||||
// The following are not really exposed in
|
||||
// the LLVM c api so instead to add these
|
||||
// we call a wrapper function in RustWrapper
|
||||
// that uses the C++ api.
|
||||
SanitizeAddressAttribute = 1 << 32,
|
||||
MinSizeAttribute = 1 << 33,
|
||||
NoDuplicateAttribute = 1 << 34,
|
||||
StackProtectStrongAttribute = 1 << 35,
|
||||
SanitizeThreadAttribute = 1 << 36,
|
||||
SanitizeMemoryAttribute = 1 << 37,
|
||||
NoBuiltinAttribute = 1 << 38,
|
||||
ReturnedAttribute = 1 << 39,
|
||||
ColdAttribute = 1 << 40,
|
||||
BuiltinAttribute = 1 << 41,
|
||||
OptimizeNoneAttribute = 1 << 42,
|
||||
InAllocaAttribute = 1 << 43,
|
||||
NonNullAttribute = 1 << 44,
|
||||
}
|
||||
|
||||
#[repr(C)]
|
||||
pub enum AttributeSet {
|
||||
ReturnIndex = 0,
|
||||
FunctionIndex = !0
|
||||
}
|
||||
|
||||
// enum for the LLVM IntPredicate type
|
||||
pub enum IntPredicate {
|
||||
IntEQ = 32,
|
||||
@ -308,7 +335,7 @@ pub mod llvm {
|
||||
use super::{CodeGenModel, RelocMode, CodeGenOptLevel};
|
||||
use super::debuginfo::*;
|
||||
use libc::{c_char, c_int, c_longlong, c_ushort, c_uint, c_ulonglong,
|
||||
size_t};
|
||||
size_t, uint64_t};
|
||||
|
||||
// Link to our native llvm bindings (things that we need to use the C++ api
|
||||
// for) and because llvm is written in C++ we need to link against libstdc++
|
||||
@ -706,20 +733,11 @@ pub mod llvm {
|
||||
pub fn LLVMSetFunctionCallConv(Fn: ValueRef, CC: c_uint);
|
||||
pub fn LLVMGetGC(Fn: ValueRef) -> *c_char;
|
||||
pub fn LLVMSetGC(Fn: ValueRef, Name: *c_char);
|
||||
pub fn LLVMAddFunctionAttr(Fn: ValueRef, PA: c_uint);
|
||||
pub fn LLVMAddFunctionAttrString(Fn: ValueRef, Name: *c_char);
|
||||
pub fn LLVMRemoveFunctionAttrString(Fn: ValueRef, Name: *c_char);
|
||||
pub fn LLVMAddFunctionAttribute(Fn: ValueRef, index: c_uint, PA: uint64_t);
|
||||
pub fn LLVMAddFunctionAttrString(Fn: ValueRef, index: c_uint, Name: *c_char);
|
||||
pub fn LLVMRemoveFunctionAttrString(Fn: ValueRef, index: c_uint, Name: *c_char);
|
||||
pub fn LLVMGetFunctionAttr(Fn: ValueRef) -> c_ulonglong;
|
||||
|
||||
pub fn LLVMAddReturnAttribute(Fn: ValueRef, PA: c_uint);
|
||||
pub fn LLVMRemoveReturnAttribute(Fn: ValueRef, PA: c_uint);
|
||||
|
||||
pub fn LLVMAddColdAttribute(Fn: ValueRef);
|
||||
|
||||
pub fn LLVMRemoveFunctionAttr(Fn: ValueRef,
|
||||
PA: c_ulonglong,
|
||||
HighPA: c_ulonglong);
|
||||
|
||||
/* Operations on parameters */
|
||||
pub fn LLVMCountParams(Fn: ValueRef) -> c_uint;
|
||||
pub fn LLVMGetParams(Fn: ValueRef, Params: *ValueRef);
|
||||
@ -783,6 +801,9 @@ pub mod llvm {
|
||||
pub fn LLVMSetInstrParamAlignment(Instr: ValueRef,
|
||||
index: c_uint,
|
||||
align: c_uint);
|
||||
pub fn LLVMAddCallSiteAttribute(Instr: ValueRef,
|
||||
index: c_uint,
|
||||
Val: uint64_t);
|
||||
|
||||
/* Operations on call instructions (only) */
|
||||
pub fn LLVMIsTailCall(CallInst: ValueRef) -> Bool;
|
||||
@ -1835,7 +1856,7 @@ pub fn ConstFCmp(pred: RealPredicate, v1: ValueRef, v2: ValueRef) -> ValueRef {
|
||||
|
||||
pub fn SetFunctionAttribute(fn_: ValueRef, attr: Attribute) {
|
||||
unsafe {
|
||||
llvm::LLVMAddFunctionAttr(fn_, attr as c_uint)
|
||||
llvm::LLVMAddFunctionAttribute(fn_, FunctionIndex as c_uint, attr as uint64_t)
|
||||
}
|
||||
}
|
||||
/* Memory-managed object interface to type handles. */
|
||||
|
@ -73,7 +73,7 @@ use util::sha2::Sha256;
|
||||
use util::nodemap::NodeMap;
|
||||
|
||||
use arena::TypedArena;
|
||||
use libc::c_uint;
|
||||
use libc::{c_uint, uint64_t};
|
||||
use std::c_str::ToCStr;
|
||||
use std::cell::{Cell, RefCell};
|
||||
use std::rc::Rc;
|
||||
@ -167,6 +167,7 @@ impl<'a> Drop for StatRecorder<'a> {
|
||||
// only use this for foreign function ABIs and glue, use `decl_rust_fn` for Rust functions
|
||||
fn decl_fn(llmod: ModuleRef, name: &str, cc: lib::llvm::CallConv,
|
||||
ty: Type, output: ty::t) -> ValueRef {
|
||||
|
||||
let llfn: ValueRef = name.with_c_str(|buf| {
|
||||
unsafe {
|
||||
llvm::LLVMGetOrInsertFunction(llmod, buf, ty.to_ref())
|
||||
@ -177,14 +178,9 @@ fn decl_fn(llmod: ModuleRef, name: &str, cc: lib::llvm::CallConv,
|
||||
// functions returning bottom may unwind, but can never return normally
|
||||
ty::ty_bot => {
|
||||
unsafe {
|
||||
llvm::LLVMAddFunctionAttr(llfn, lib::llvm::NoReturnAttribute as c_uint)
|
||||
}
|
||||
}
|
||||
// `~` pointer return values never alias because ownership is transferred
|
||||
ty::ty_uniq(..) // | ty::ty_trait(_, _, ty::UniqTraitStore, _, _)
|
||||
=> {
|
||||
unsafe {
|
||||
llvm::LLVMAddReturnAttribute(llfn, lib::llvm::NoAliasAttribute as c_uint);
|
||||
llvm::LLVMAddFunctionAttribute(llfn,
|
||||
lib::llvm::FunctionIndex as c_uint,
|
||||
lib::llvm::NoReturnAttribute as uint64_t)
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
@ -207,8 +203,8 @@ pub fn decl_cdecl_fn(llmod: ModuleRef,
|
||||
}
|
||||
|
||||
// only use this for foreign function ABIs and glue, use `get_extern_rust_fn` for Rust functions
|
||||
pub fn get_extern_fn(externs: &mut ExternMap,
|
||||
llmod: ModuleRef,
|
||||
pub fn get_extern_fn(ccx: &CrateContext,
|
||||
externs: &mut ExternMap,
|
||||
name: &str,
|
||||
cc: lib::llvm::CallConv,
|
||||
ty: Type,
|
||||
@ -218,19 +214,19 @@ pub fn get_extern_fn(externs: &mut ExternMap,
|
||||
Some(n) => return *n,
|
||||
None => {}
|
||||
}
|
||||
let f = decl_fn(llmod, name, cc, ty, output);
|
||||
let f = decl_fn(ccx.llmod, name, cc, ty, output);
|
||||
externs.insert(name.to_strbuf(), f);
|
||||
f
|
||||
}
|
||||
|
||||
fn get_extern_rust_fn(ccx: &CrateContext, inputs: &[ty::t], output: ty::t,
|
||||
name: &str, did: ast::DefId) -> ValueRef {
|
||||
fn get_extern_rust_fn(ccx: &CrateContext, fn_ty: ty::t, name: &str, did: ast::DefId) -> ValueRef {
|
||||
match ccx.externs.borrow().find_equiv(&name) {
|
||||
Some(n) => return *n,
|
||||
None => ()
|
||||
}
|
||||
|
||||
let f = decl_rust_fn(ccx, false, inputs, output, name);
|
||||
let f = decl_rust_fn(ccx, fn_ty, name);
|
||||
|
||||
csearch::get_item_attrs(&ccx.sess().cstore, did, |meta_items| {
|
||||
set_llvm_fn_attrs(meta_items.iter().map(|&x| attr::mk_attr_outer(x))
|
||||
.collect::<Vec<_>>().as_slice(), f)
|
||||
@ -240,72 +236,27 @@ fn get_extern_rust_fn(ccx: &CrateContext, inputs: &[ty::t], output: ty::t,
|
||||
f
|
||||
}
|
||||
|
||||
pub fn decl_rust_fn(ccx: &CrateContext, has_env: bool,
|
||||
inputs: &[ty::t], output: ty::t,
|
||||
name: &str) -> ValueRef {
|
||||
use middle::ty::{BrAnon, ReLateBound};
|
||||
pub fn decl_rust_fn(ccx: &CrateContext, fn_ty: ty::t, name: &str) -> ValueRef {
|
||||
let (inputs, output, has_env) = match ty::get(fn_ty).sty {
|
||||
ty::ty_bare_fn(ref f) => (f.sig.inputs.clone(), f.sig.output, false),
|
||||
ty::ty_closure(ref f) => (f.sig.inputs.clone(), f.sig.output, true),
|
||||
_ => fail!("expected closure or fn")
|
||||
};
|
||||
|
||||
let llfty = type_of_rust_fn(ccx, has_env, inputs, output);
|
||||
let llfn = decl_cdecl_fn(ccx.llmod, name, llfty, output);
|
||||
|
||||
let uses_outptr = type_of::return_uses_outptr(ccx, output);
|
||||
let offset = if uses_outptr { 1 } else { 0 };
|
||||
let offset = if has_env { offset + 1 } else { offset };
|
||||
|
||||
for (i, &arg_ty) in inputs.iter().enumerate() {
|
||||
let llarg = unsafe { llvm::LLVMGetParam(llfn, (offset + i) as c_uint) };
|
||||
match ty::get(arg_ty).sty {
|
||||
// `~` pointer parameters never alias because ownership is transferred
|
||||
ty::ty_uniq(..) => {
|
||||
unsafe {
|
||||
llvm::LLVMAddAttribute(llarg, lib::llvm::NoAliasAttribute as c_uint);
|
||||
}
|
||||
}
|
||||
// `&mut` pointer parameters never alias other parameters, or mutable global data
|
||||
ty::ty_rptr(_, mt) if mt.mutbl == ast::MutMutable => {
|
||||
unsafe {
|
||||
llvm::LLVMAddAttribute(llarg, lib::llvm::NoAliasAttribute as c_uint);
|
||||
}
|
||||
}
|
||||
// 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(_)), _) => {
|
||||
debug!("marking argument of {} as nocapture because of anonymous lifetime", name);
|
||||
unsafe {
|
||||
llvm::LLVMAddAttribute(llarg, lib::llvm::NoCaptureAttribute as c_uint);
|
||||
}
|
||||
}
|
||||
_ => {
|
||||
// For non-immediate arguments the callee gets its own copy of
|
||||
// the value on the stack, so there are no aliases
|
||||
if !type_is_immediate(ccx, arg_ty) {
|
||||
unsafe {
|
||||
llvm::LLVMAddAttribute(llarg, lib::llvm::NoAliasAttribute as c_uint);
|
||||
llvm::LLVMAddAttribute(llarg, lib::llvm::NoCaptureAttribute as c_uint);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// The out pointer will never alias with any other pointers, as the object only exists at a
|
||||
// language level after the call. It can also be tagged with SRet to indicate that it is
|
||||
// guaranteed to point to a usable block of memory for the type.
|
||||
if uses_outptr {
|
||||
let llfty = type_of_rust_fn(ccx, has_env, inputs.as_slice(), output);
|
||||
let llfn = decl_fn(ccx.llmod, name, lib::llvm::CCallConv, llfty, output);
|
||||
let attrs = get_fn_llvm_attributes(ccx, fn_ty);
|
||||
for &(idx, attr) in attrs.iter() {
|
||||
unsafe {
|
||||
let outptr = llvm::LLVMGetParam(llfn, 0);
|
||||
llvm::LLVMAddAttribute(outptr, lib::llvm::StructRetAttribute as c_uint);
|
||||
llvm::LLVMAddAttribute(outptr, lib::llvm::NoAliasAttribute as c_uint);
|
||||
llvm::LLVMAddFunctionAttribute(llfn, idx as c_uint, attr);
|
||||
}
|
||||
}
|
||||
|
||||
llfn
|
||||
}
|
||||
|
||||
pub fn decl_internal_rust_fn(ccx: &CrateContext, has_env: bool,
|
||||
inputs: &[ty::t], output: ty::t,
|
||||
name: &str) -> ValueRef {
|
||||
let llfn = decl_rust_fn(ccx, has_env, inputs, output, name);
|
||||
pub fn decl_internal_rust_fn(ccx: &CrateContext, fn_ty: ty::t, name: &str) -> ValueRef {
|
||||
let llfn = decl_rust_fn(ccx, fn_ty, name);
|
||||
lib::llvm::SetLinkage(llfn, lib::llvm::InternalLinkage);
|
||||
llfn
|
||||
}
|
||||
@ -453,7 +404,11 @@ pub fn set_llvm_fn_attrs(attrs: &[ast::Attribute], llfn: ValueRef) {
|
||||
}
|
||||
|
||||
if contains_name(attrs, "cold") {
|
||||
unsafe { llvm::LLVMAddColdAttribute(llfn) }
|
||||
unsafe {
|
||||
llvm::LLVMAddFunctionAttribute(llfn,
|
||||
lib::llvm::FunctionIndex as c_uint,
|
||||
lib::llvm::ColdAttribute as uint64_t)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -463,13 +418,13 @@ pub fn set_always_inline(f: ValueRef) {
|
||||
|
||||
pub fn set_split_stack(f: ValueRef) {
|
||||
"split-stack".with_c_str(|buf| {
|
||||
unsafe { llvm::LLVMAddFunctionAttrString(f, buf); }
|
||||
unsafe { llvm::LLVMAddFunctionAttrString(f, lib::llvm::FunctionIndex as c_uint, buf); }
|
||||
})
|
||||
}
|
||||
|
||||
pub fn unset_split_stack(f: ValueRef) {
|
||||
"split-stack".with_c_str(|buf| {
|
||||
unsafe { llvm::LLVMRemoveFunctionAttrString(f, buf); }
|
||||
unsafe { llvm::LLVMRemoveFunctionAttrString(f, lib::llvm::FunctionIndex as c_uint, buf); }
|
||||
})
|
||||
}
|
||||
|
||||
@ -485,6 +440,7 @@ pub fn note_unique_llvm_symbol(ccx: &CrateContext, sym: StrBuf) {
|
||||
|
||||
pub fn get_res_dtor(ccx: &CrateContext,
|
||||
did: ast::DefId,
|
||||
t: ty::t,
|
||||
parent_id: ast::DefId,
|
||||
substs: &ty::substs)
|
||||
-> ValueRef {
|
||||
@ -510,13 +466,14 @@ pub fn get_res_dtor(ccx: &CrateContext,
|
||||
let class_ty = ty::subst(tcx, substs,
|
||||
ty::lookup_item_type(tcx, parent_id).ty);
|
||||
let llty = type_of_dtor(ccx, class_ty);
|
||||
|
||||
get_extern_fn(&mut *ccx.externs.borrow_mut(),
|
||||
ccx.llmod,
|
||||
let dtor_ty = ty::mk_ctor_fn(ccx.tcx(), ast::DUMMY_NODE_ID,
|
||||
[glue::get_drop_glue_type(ccx, t)], ty::mk_nil());
|
||||
get_extern_fn(ccx,
|
||||
&mut *ccx.externs.borrow_mut(),
|
||||
name.as_slice(),
|
||||
lib::llvm::CCallConv,
|
||||
llty,
|
||||
ty::mk_nil())
|
||||
dtor_ty)
|
||||
}
|
||||
}
|
||||
|
||||
@ -858,11 +815,7 @@ pub fn trans_external_path(ccx: &CrateContext, did: ast::DefId, t: ty::t) -> Val
|
||||
match fn_ty.abi.for_target(ccx.sess().targ_cfg.os,
|
||||
ccx.sess().targ_cfg.arch) {
|
||||
Some(Rust) | Some(RustIntrinsic) => {
|
||||
get_extern_rust_fn(ccx,
|
||||
fn_ty.sig.inputs.as_slice(),
|
||||
fn_ty.sig.output,
|
||||
name.as_slice(),
|
||||
did)
|
||||
get_extern_rust_fn(ccx, t, name.as_slice(), did)
|
||||
}
|
||||
Some(..) | None => {
|
||||
foreign::register_foreign_item_fn(ccx, fn_ty.abi, t,
|
||||
@ -870,12 +823,8 @@ pub fn trans_external_path(ccx: &CrateContext, did: ast::DefId, t: ty::t) -> Val
|
||||
}
|
||||
}
|
||||
}
|
||||
ty::ty_closure(ref f) => {
|
||||
get_extern_rust_fn(ccx,
|
||||
f.sig.inputs.as_slice(),
|
||||
f.sig.output,
|
||||
name.as_slice(),
|
||||
did)
|
||||
ty::ty_closure(_) => {
|
||||
get_extern_rust_fn(ccx, t, name.as_slice(), did)
|
||||
}
|
||||
_ => {
|
||||
let llty = type_of(ccx, t);
|
||||
@ -891,7 +840,7 @@ pub fn invoke<'a>(
|
||||
bcx: &'a Block<'a>,
|
||||
llfn: ValueRef,
|
||||
llargs: Vec<ValueRef> ,
|
||||
attributes: &[(uint, lib::llvm::Attribute)],
|
||||
fn_ty: ty::t,
|
||||
call_info: Option<NodeInfo>)
|
||||
-> (ValueRef, &'a Block<'a>) {
|
||||
let _icx = push_ctxt("invoke_");
|
||||
@ -899,6 +848,8 @@ pub fn invoke<'a>(
|
||||
return (C_null(Type::i8(bcx.ccx())), bcx);
|
||||
}
|
||||
|
||||
let attributes = get_fn_llvm_attributes(bcx.ccx(), fn_ty);
|
||||
|
||||
match bcx.opt_node_id {
|
||||
None => {
|
||||
debug!("invoke at ???");
|
||||
@ -926,7 +877,7 @@ pub fn invoke<'a>(
|
||||
llargs.as_slice(),
|
||||
normal_bcx.llbb,
|
||||
landing_pad,
|
||||
attributes);
|
||||
attributes.as_slice());
|
||||
return (llresult, normal_bcx);
|
||||
} else {
|
||||
debug!("calling {} at {}", llfn, bcx.llbb);
|
||||
@ -939,7 +890,7 @@ pub fn invoke<'a>(
|
||||
None => debuginfo::clear_source_location(bcx.fcx)
|
||||
};
|
||||
|
||||
let llresult = Call(bcx, llfn, llargs.as_slice(), attributes);
|
||||
let llresult = Call(bcx, llfn, llargs.as_slice(), attributes.as_slice());
|
||||
return (llresult, bcx);
|
||||
}
|
||||
}
|
||||
@ -1708,34 +1659,132 @@ fn register_fn(ccx: &CrateContext,
|
||||
node_id: ast::NodeId,
|
||||
node_type: ty::t)
|
||||
-> ValueRef {
|
||||
let f = match ty::get(node_type).sty {
|
||||
match ty::get(node_type).sty {
|
||||
ty::ty_bare_fn(ref f) => {
|
||||
assert!(f.abi == Rust || f.abi == RustIntrinsic);
|
||||
f
|
||||
}
|
||||
_ => fail!("expected bare rust fn or an intrinsic")
|
||||
};
|
||||
|
||||
let llfn = decl_rust_fn(ccx,
|
||||
false,
|
||||
f.sig.inputs.as_slice(),
|
||||
f.sig.output,
|
||||
sym.as_slice());
|
||||
let llfn = decl_rust_fn(ccx, node_type, sym.as_slice());
|
||||
finish_register_fn(ccx, sp, sym, node_id, llfn);
|
||||
llfn
|
||||
}
|
||||
|
||||
pub fn get_fn_llvm_attributes(ccx: &CrateContext, fn_ty: ty::t) -> Vec<(uint, u64)> {
|
||||
use middle::ty::{BrAnon, ReLateBound};
|
||||
|
||||
let (fn_sig, has_env) = match ty::get(fn_ty).sty {
|
||||
ty::ty_closure(ref f) => (f.sig.clone(), true),
|
||||
ty::ty_bare_fn(ref f) => (f.sig.clone(), false),
|
||||
_ => 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 = 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, lib::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, lib::llvm::NoAliasAttribute as u64));
|
||||
attrs.push((1, lib::llvm::NoCaptureAttribute as u64));
|
||||
attrs.push((1, lib::llvm::NonNullAttribute as u64));
|
||||
|
||||
// Add one more since there's an outptr
|
||||
first_arg_offset += 1;
|
||||
} else {
|
||||
// The `noalias` attribute on the return value is useful to a
|
||||
// function ptr caller.
|
||||
match ty::get(ret_ty).sty {
|
||||
// `~` pointer return values never alias because ownership
|
||||
// is transferred
|
||||
ty::ty_uniq(_) => {
|
||||
attrs.push((lib::llvm::ReturnIndex as uint, lib::llvm::NoAliasAttribute as u64));
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
|
||||
// We can also mark the return value as `nonnull` in certain cases
|
||||
match ty::get(ret_ty).sty {
|
||||
// These are not really pointers but pairs, (pointer, len)
|
||||
ty::ty_rptr(_, ty::mt { ty: it, .. }) |
|
||||
ty::ty_rptr(_, ty::mt { ty: it, .. }) if match ty::get(it).sty {
|
||||
ty::ty_str | ty::ty_vec(..) => true, _ => false
|
||||
} => {}
|
||||
ty::ty_uniq(_) | ty::ty_rptr(_, _) => {
|
||||
attrs.push((lib::llvm::ReturnIndex as uint, lib::llvm::NonNullAttribute as u64));
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
|
||||
for (idx, &t) in fn_sig.inputs.iter().enumerate().map(|(i, v)| (i + first_arg_offset, v)) {
|
||||
match ty::get(t).sty {
|
||||
// `~` pointer parameters never alias because ownership is transferred
|
||||
ty::ty_uniq(_) => {
|
||||
attrs.push((idx, lib::llvm::NoAliasAttribute as u64));
|
||||
attrs.push((idx, lib::llvm::NonNullAttribute as u64));
|
||||
}
|
||||
// These are not really pointers but pairs, (pointer, len)
|
||||
ty::ty_rptr(_, ty::mt { ty: it, .. }) |
|
||||
ty::ty_rptr(_, ty::mt { ty: it, .. }) if match ty::get(it).sty {
|
||||
ty::ty_str | ty::ty_vec(..) => true, _ => false
|
||||
} => {}
|
||||
// `&mut` pointer parameters never alias other parameters, or mutable global data
|
||||
ty::ty_rptr(b, mt) if mt.mutbl == ast::MutMutable => {
|
||||
attrs.push((idx, lib::llvm::NoAliasAttribute as u64));
|
||||
attrs.push((idx, lib::llvm::NonNullAttribute as u64));
|
||||
match b {
|
||||
ReLateBound(_, BrAnon(_)) => {
|
||||
attrs.push((idx, lib::llvm::NoCaptureAttribute as u64));
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
// 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, lib::llvm::NoCaptureAttribute as u64));
|
||||
attrs.push((idx, lib::llvm::NonNullAttribute as u64));
|
||||
}
|
||||
// & pointer parameters are never null
|
||||
ty::ty_rptr(_, _) => {
|
||||
attrs.push((idx, lib::llvm::NonNullAttribute as u64));
|
||||
}
|
||||
_ => {
|
||||
// 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
|
||||
if !type_is_immediate(ccx, t) {
|
||||
attrs.push((idx, lib::llvm::NoAliasAttribute as u64));
|
||||
attrs.push((idx, lib::llvm::NoCaptureAttribute as u64));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
attrs
|
||||
}
|
||||
|
||||
// only use this for foreign function ABIs and glue, use `register_fn` for Rust functions
|
||||
pub fn register_fn_llvmty(ccx: &CrateContext,
|
||||
sp: Span,
|
||||
sym: StrBuf,
|
||||
node_id: ast::NodeId,
|
||||
cc: lib::llvm::CallConv,
|
||||
fn_ty: Type,
|
||||
output: ty::t) -> ValueRef {
|
||||
llfty: Type) -> ValueRef {
|
||||
debug!("register_fn_llvmty id={} sym={}", node_id, sym);
|
||||
|
||||
let llfn = decl_fn(ccx.llmod, sym.as_slice(), cc, fn_ty, output);
|
||||
let llfn = decl_fn(ccx.llmod, sym.as_slice(), cc, llfty, ty::mk_nil());
|
||||
finish_register_fn(ccx, sp, sym, node_id, llfn);
|
||||
llfn
|
||||
}
|
||||
|
@ -113,7 +113,7 @@ pub fn Invoke(cx: &Block,
|
||||
args: &[ValueRef],
|
||||
then: BasicBlockRef,
|
||||
catch: BasicBlockRef,
|
||||
attributes: &[(uint, lib::llvm::Attribute)])
|
||||
attributes: &[(uint, u64)])
|
||||
-> ValueRef {
|
||||
if cx.unreachable.get() {
|
||||
return C_null(Type::i8(cx.ccx()));
|
||||
@ -679,13 +679,13 @@ pub fn InlineAsmCall(cx: &Block, asm: *c_char, cons: *c_char,
|
||||
}
|
||||
|
||||
pub fn Call(cx: &Block, fn_: ValueRef, args: &[ValueRef],
|
||||
attributes: &[(uint, lib::llvm::Attribute)]) -> ValueRef {
|
||||
attributes: &[(uint, u64)]) -> 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, lib::llvm::Attribute)]) -> ValueRef {
|
||||
attributes: &[(uint, u64)]) -> ValueRef {
|
||||
if cx.unreachable.get() { return _UndefReturn(cx, fn_); }
|
||||
B(cx).call_with_conv(fn_, args, conv, attributes)
|
||||
}
|
||||
|
@ -156,7 +156,7 @@ impl<'a> Builder<'a> {
|
||||
args: &[ValueRef],
|
||||
then: BasicBlockRef,
|
||||
catch: BasicBlockRef,
|
||||
attributes: &[(uint, lib::llvm::Attribute)])
|
||||
attributes: &[(uint, u64)])
|
||||
-> ValueRef {
|
||||
self.count_insn("invoke");
|
||||
unsafe {
|
||||
@ -168,7 +168,7 @@ impl<'a> Builder<'a> {
|
||||
catch,
|
||||
noname());
|
||||
for &(idx, attr) in attributes.iter() {
|
||||
llvm::LLVMAddInstrAttribute(v, idx as c_uint, attr as c_uint);
|
||||
llvm::LLVMAddCallSiteAttribute(v, idx as c_uint, attr);
|
||||
}
|
||||
v
|
||||
}
|
||||
@ -799,7 +799,7 @@ impl<'a> Builder<'a> {
|
||||
}
|
||||
|
||||
pub fn call(&self, llfn: ValueRef, args: &[ValueRef],
|
||||
attributes: &[(uint, lib::llvm::Attribute)]) -> ValueRef {
|
||||
attributes: &[(uint, u64)]) -> ValueRef {
|
||||
self.count_insn("call");
|
||||
|
||||
debug!("Call {} with args ({})",
|
||||
@ -813,14 +813,14 @@ impl<'a> Builder<'a> {
|
||||
let v = llvm::LLVMBuildCall(self.llbuilder, llfn, args.as_ptr(),
|
||||
args.len() as c_uint, noname());
|
||||
for &(idx, attr) in attributes.iter() {
|
||||
llvm::LLVMAddInstrAttribute(v, idx as c_uint, attr as c_uint);
|
||||
llvm::LLVMAddCallSiteAttribute(v, idx as c_uint, attr);
|
||||
}
|
||||
v
|
||||
}
|
||||
}
|
||||
|
||||
pub fn call_with_conv(&self, llfn: ValueRef, args: &[ValueRef],
|
||||
conv: CallConv, attributes: &[(uint, lib::llvm::Attribute)]) -> ValueRef {
|
||||
conv: CallConv, attributes: &[(uint, u64)]) -> ValueRef {
|
||||
self.count_insn("callwithconv");
|
||||
let v = self.call(llfn, args, attributes);
|
||||
lib::llvm::SetInstructionCallConv(v, conv);
|
||||
|
@ -18,7 +18,7 @@
|
||||
|
||||
use back::abi;
|
||||
use driver::session;
|
||||
use lib::llvm::{ValueRef, NoAliasAttribute, StructRetAttribute, NoCaptureAttribute};
|
||||
use lib::llvm::ValueRef;
|
||||
use lib::llvm::llvm;
|
||||
use metadata::csearch;
|
||||
use middle::trans::base;
|
||||
@ -614,13 +614,9 @@ pub fn trans_call_inner<'a>(
|
||||
llargs.push(opt_llretslot.unwrap());
|
||||
}
|
||||
|
||||
// start at 1, because index 0 is the return value of the llvm func
|
||||
let mut first_arg_offset = 1;
|
||||
|
||||
// Push the environment (or a trait object's self).
|
||||
match (llenv, llself) {
|
||||
(Some(llenv), None) => {
|
||||
first_arg_offset += 1;
|
||||
llargs.push(llenv)
|
||||
},
|
||||
(None, Some(llself)) => llargs.push(llself),
|
||||
@ -634,61 +630,11 @@ pub fn trans_call_inner<'a>(
|
||||
|
||||
fcx.pop_custom_cleanup_scope(arg_cleanup_scope);
|
||||
|
||||
// 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`.
|
||||
let mut attrs = Vec::new();
|
||||
if type_of::return_uses_outptr(ccx, ret_ty) {
|
||||
attrs.push((1, StructRetAttribute));
|
||||
// The outptr can be noalias and nocapture because it's entirely
|
||||
// invisible to the program.
|
||||
attrs.push((1, NoAliasAttribute));
|
||||
attrs.push((1, NoCaptureAttribute));
|
||||
first_arg_offset += 1;
|
||||
}
|
||||
|
||||
// The `noalias` attribute on the return value is useful to a
|
||||
// function ptr caller.
|
||||
match ty::get(ret_ty).sty {
|
||||
// `~` pointer return values never alias because ownership
|
||||
// is transferred
|
||||
ty::ty_uniq(ty) => match ty::get(ty).sty {
|
||||
ty::ty_str => {}
|
||||
_ => attrs.push((0, NoAliasAttribute)),
|
||||
},
|
||||
_ => {}
|
||||
}
|
||||
|
||||
debug!("trans_callee_inner: first_arg_offset={}", first_arg_offset);
|
||||
|
||||
for (idx, &t) in ty::ty_fn_args(callee_ty).iter().enumerate()
|
||||
.map(|(i, v)| (i+first_arg_offset, v)) {
|
||||
use middle::ty::{BrAnon, ReLateBound};
|
||||
if !type_is_immediate(ccx, t) {
|
||||
// if it's not immediate, we have a program-invisible pointer,
|
||||
// which it can't possibly capture
|
||||
attrs.push((idx, NoCaptureAttribute));
|
||||
debug!("trans_callee_inner: argument {} nocapture because it's non-immediate", idx);
|
||||
continue;
|
||||
}
|
||||
|
||||
let t_ = ty::get(t);
|
||||
match t_.sty {
|
||||
ty::ty_rptr(ReLateBound(_, BrAnon(_)), _) => {
|
||||
debug!("trans_callee_inner: argument {} nocapture because \
|
||||
of anonymous lifetime", idx);
|
||||
attrs.push((idx, NoCaptureAttribute));
|
||||
},
|
||||
_ => { }
|
||||
}
|
||||
}
|
||||
|
||||
// Invoke the actual rust fn and update bcx/llresult.
|
||||
let (llret, b) = base::invoke(bcx,
|
||||
llfn,
|
||||
llargs,
|
||||
attrs.as_slice(),
|
||||
callee_ty,
|
||||
call_info);
|
||||
bcx = b;
|
||||
llresult = llret;
|
||||
|
@ -340,21 +340,12 @@ pub fn trans_expr_fn<'a>(
|
||||
};
|
||||
|
||||
let ccx = bcx.ccx();
|
||||
let fty = node_id_type(bcx, id);
|
||||
let f = match ty::get(fty).sty {
|
||||
ty::ty_closure(ref f) => f,
|
||||
_ => fail!("expected closure")
|
||||
};
|
||||
|
||||
let tcx = bcx.tcx();
|
||||
let fty = node_id_type(bcx, id);
|
||||
let s = tcx.map.with_path(id, |path| {
|
||||
mangle_internal_name_by_path_and_seq(path, "closure")
|
||||
});
|
||||
let llfn = decl_internal_rust_fn(ccx,
|
||||
true,
|
||||
f.sig.inputs.as_slice(),
|
||||
f.sig.output,
|
||||
s.as_slice());
|
||||
let llfn = decl_internal_rust_fn(ccx, fty, s.as_slice());
|
||||
|
||||
// set an inline hint for all closures
|
||||
set_inline_hint(llfn);
|
||||
@ -414,17 +405,9 @@ pub fn get_wrapper_for_bare_fn(ccx: &CrateContext,
|
||||
mangle_internal_name_by_path_and_seq(path, "as_closure")
|
||||
});
|
||||
let llfn = if is_local {
|
||||
decl_internal_rust_fn(ccx,
|
||||
true,
|
||||
f.sig.inputs.as_slice(),
|
||||
f.sig.output,
|
||||
name.as_slice())
|
||||
decl_internal_rust_fn(ccx, closure_ty, name.as_slice())
|
||||
} else {
|
||||
decl_rust_fn(ccx,
|
||||
true,
|
||||
f.sig.inputs.as_slice(),
|
||||
f.sig.output,
|
||||
name.as_slice())
|
||||
decl_rust_fn(ccx, closure_ty, name.as_slice())
|
||||
};
|
||||
|
||||
ccx.closure_bare_wrapper_cache.borrow_mut().insert(fn_ptr, llfn);
|
||||
|
@ -227,12 +227,12 @@ pub fn register_foreign_item_fn(ccx: &CrateContext, abi: Abi, fty: ty::t,
|
||||
// Create the LLVM value for the C extern fn
|
||||
let llfn_ty = lltype_for_fn_from_foreign_types(ccx, &tys);
|
||||
|
||||
let llfn = base::get_extern_fn(&mut *ccx.externs.borrow_mut(),
|
||||
ccx.llmod,
|
||||
let llfn = base::get_extern_fn(ccx,
|
||||
&mut *ccx.externs.borrow_mut(),
|
||||
name,
|
||||
cc,
|
||||
llfn_ty,
|
||||
tys.fn_sig.output);
|
||||
fty);
|
||||
add_argument_attributes(&tys, llfn);
|
||||
|
||||
llfn
|
||||
@ -378,17 +378,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. Right now, the
|
||||
// only attribute we need to worry about is `sret`.
|
||||
let sret_attr = if fn_type.ret_ty.is_indirect() {
|
||||
Some((1, StructRetAttribute))
|
||||
} else {
|
||||
None
|
||||
let mut attrs = Vec::new();
|
||||
if fn_type.ret_ty.is_indirect() {
|
||||
attrs.push((1, lib::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, lib::llvm::NoAliasAttribute as u64));
|
||||
attrs.push((1, lib::llvm::NoCaptureAttribute as u64));
|
||||
attrs.push((1, lib::llvm::NonNullAttribute as u64));
|
||||
};
|
||||
let attrs = sret_attr.as_slice();
|
||||
let llforeign_retval = CallWithConv(bcx,
|
||||
llfn,
|
||||
llargs_foreign.as_slice(),
|
||||
cc,
|
||||
attrs);
|
||||
attrs.as_slice());
|
||||
|
||||
// If the function we just called does not use an outpointer,
|
||||
// store the result into the rust outpointer. Cast the outpointer
|
||||
@ -500,14 +504,14 @@ pub fn register_rust_fn_with_foreign_abi(ccx: &CrateContext,
|
||||
let tys = foreign_types_for_id(ccx, node_id);
|
||||
let llfn_ty = lltype_for_fn_from_foreign_types(ccx, &tys);
|
||||
let t = ty::node_id_to_type(ccx.tcx(), node_id);
|
||||
let (cconv, output) = match ty::get(t).sty {
|
||||
let cconv = match ty::get(t).sty {
|
||||
ty::ty_bare_fn(ref fn_ty) => {
|
||||
let c = llvm_calling_convention(ccx, fn_ty.abi);
|
||||
(c.unwrap_or(lib::llvm::CCallConv), fn_ty.sig.output)
|
||||
c.unwrap_or(lib::llvm::CCallConv)
|
||||
}
|
||||
_ => fail!("expected bare fn in register_rust_fn_with_foreign_abi")
|
||||
};
|
||||
let llfn = base::register_fn_llvmty(ccx, sp, sym, node_id, cconv, llfn_ty, output);
|
||||
let llfn = base::register_fn_llvmty(ccx, sp, sym, node_id, cconv, llfn_ty);
|
||||
add_argument_attributes(&tys, llfn);
|
||||
debug!("register_rust_fn_with_foreign_abi(node_id={:?}, llfn_ty={}, llfn={})",
|
||||
node_id, ccx.tn.type_to_str(llfn_ty), ccx.tn.val_to_str(llfn));
|
||||
@ -528,7 +532,7 @@ pub fn trans_rust_fn_with_foreign_abi(ccx: &CrateContext,
|
||||
let llrustfn = build_rust_fn(ccx, decl, body, attrs, id);
|
||||
|
||||
// Build up the foreign wrapper (`foo` above).
|
||||
return build_wrap_fn(ccx, llrustfn, llwrapfn, &tys);
|
||||
return build_wrap_fn(ccx, llrustfn, llwrapfn, &tys, id);
|
||||
}
|
||||
|
||||
fn build_rust_fn(ccx: &CrateContext,
|
||||
@ -548,10 +552,9 @@ pub fn trans_rust_fn_with_foreign_abi(ccx: &CrateContext,
|
||||
|
||||
// Compute the type that the function would have if it were just a
|
||||
// normal Rust function. This will be the type of the wrappee fn.
|
||||
let f = match ty::get(t).sty {
|
||||
match ty::get(t).sty {
|
||||
ty::ty_bare_fn(ref f) => {
|
||||
assert!(f.abi != Rust && f.abi != RustIntrinsic);
|
||||
f
|
||||
}
|
||||
_ => {
|
||||
ccx.sess().bug(format!("build_rust_fn: extern fn {} has ty {}, \
|
||||
@ -565,11 +568,7 @@ pub fn trans_rust_fn_with_foreign_abi(ccx: &CrateContext,
|
||||
ccx.tcx.map.path_to_str(id),
|
||||
id, t.repr(tcx));
|
||||
|
||||
let llfn = base::decl_internal_rust_fn(ccx,
|
||||
false,
|
||||
f.sig.inputs.as_slice(),
|
||||
f.sig.output,
|
||||
ps.as_slice());
|
||||
let llfn = base::decl_internal_rust_fn(ccx, t, ps.as_slice());
|
||||
base::set_llvm_fn_attrs(attrs, llfn);
|
||||
base::trans_fn(ccx, decl, body, llfn, None, id, []);
|
||||
llfn
|
||||
@ -578,14 +577,18 @@ pub fn trans_rust_fn_with_foreign_abi(ccx: &CrateContext,
|
||||
unsafe fn build_wrap_fn(ccx: &CrateContext,
|
||||
llrustfn: ValueRef,
|
||||
llwrapfn: ValueRef,
|
||||
tys: &ForeignTypes) {
|
||||
tys: &ForeignTypes,
|
||||
id: ast::NodeId) {
|
||||
let _icx = push_ctxt(
|
||||
"foreign::trans_rust_fn_with_foreign_abi::build_wrap_fn");
|
||||
let tcx = ccx.tcx();
|
||||
|
||||
debug!("build_wrap_fn(llrustfn={}, llwrapfn={})",
|
||||
let t = ty::node_id_to_type(tcx, id);
|
||||
|
||||
debug!("build_wrap_fn(llrustfn={}, llwrapfn={}, t={})",
|
||||
ccx.tn.val_to_str(llrustfn),
|
||||
ccx.tn.val_to_str(llwrapfn));
|
||||
ccx.tn.val_to_str(llwrapfn),
|
||||
t.repr(ccx.tcx()));
|
||||
|
||||
// Avoid all the Rust generation stuff and just generate raw
|
||||
// LLVM here.
|
||||
@ -731,10 +734,15 @@ pub fn trans_rust_fn_with_foreign_abi(ccx: &CrateContext,
|
||||
}
|
||||
|
||||
// Perform the call itself
|
||||
debug!("calling llrustfn = {}", ccx.tn.val_to_str(llrustfn));
|
||||
debug!("calling llrustfn = {}, t = {}", ccx.tn.val_to_str(llrustfn), t.repr(ccx.tcx()));
|
||||
let llrust_ret_val = llvm::LLVMBuildCall(builder, llrustfn, llrust_args.as_ptr(),
|
||||
llrust_args.len() as c_uint, noname());
|
||||
|
||||
let attributes = base::get_fn_llvm_attributes(ccx, t);
|
||||
for &(idx, attr) in attributes.iter() {
|
||||
llvm::LLVMAddCallSiteAttribute(llrust_ret_val, idx as c_uint, attr);
|
||||
}
|
||||
|
||||
// Get the return value where the foreign fn expects it.
|
||||
let llforeign_ret_ty = match tys.fn_ty.ret_ty.cast {
|
||||
Some(ty) => ty,
|
||||
|
@ -88,7 +88,7 @@ pub fn take_ty<'a>(bcx: &'a Block<'a>, v: ValueRef, t: ty::t)
|
||||
}
|
||||
}
|
||||
|
||||
fn get_drop_glue_type(ccx: &CrateContext, t: ty::t) -> ty::t {
|
||||
pub fn get_drop_glue_type(ccx: &CrateContext, t: ty::t) -> ty::t {
|
||||
let tcx = ccx.tcx();
|
||||
if !ty::type_needs_drop(tcx, t) {
|
||||
return ty::mk_i8();
|
||||
@ -248,7 +248,7 @@ fn trans_struct_drop<'a>(bcx: &'a Block<'a>,
|
||||
let repr = adt::represent_type(bcx.ccx(), t);
|
||||
|
||||
// Find and call the actual destructor
|
||||
let dtor_addr = get_res_dtor(bcx.ccx(), dtor_did,
|
||||
let dtor_addr = get_res_dtor(bcx.ccx(), dtor_did, t,
|
||||
class_did, substs);
|
||||
|
||||
// The second argument is the "self" argument for drop
|
||||
@ -279,7 +279,9 @@ fn trans_struct_drop<'a>(bcx: &'a Block<'a>,
|
||||
fld.mt.ty);
|
||||
}
|
||||
|
||||
let (_, bcx) = invoke(bcx, dtor_addr, args, [], None);
|
||||
let dtor_ty = ty::mk_ctor_fn(bcx.tcx(), ast::DUMMY_NODE_ID,
|
||||
[get_drop_glue_type(bcx.ccx(), t)], ty::mk_nil());
|
||||
let (_, bcx) = invoke(bcx, dtor_addr, args, dtor_ty, None);
|
||||
|
||||
bcx.fcx.pop_and_trans_custom_cleanup_scope(bcx, field_scope)
|
||||
}
|
||||
@ -459,10 +461,7 @@ fn declare_generic_glue(ccx: &CrateContext, t: ty::t, llfnty: Type,
|
||||
t,
|
||||
format!("glue_{}", name).as_slice());
|
||||
debug!("{} is for type {}", fn_nm, ppaux::ty_to_str(ccx.tcx(), t));
|
||||
let llfn = decl_cdecl_fn(ccx.llmod,
|
||||
fn_nm.as_slice(),
|
||||
llfnty,
|
||||
ty::mk_nil());
|
||||
let llfn = decl_cdecl_fn(ccx.llmod, fn_nm.as_slice(), llfnty, ty::mk_nil());
|
||||
note_unique_llvm_symbol(ccx, fn_nm);
|
||||
return llfn;
|
||||
}
|
||||
|
@ -172,14 +172,6 @@ pub fn monomorphic_fn(ccx: &CrateContext,
|
||||
}
|
||||
};
|
||||
|
||||
let f = match ty::get(mono_ty).sty {
|
||||
ty::ty_bare_fn(ref f) => {
|
||||
assert!(f.abi == abi::Rust || f.abi == abi::RustIntrinsic);
|
||||
f
|
||||
}
|
||||
_ => fail!("expected bare rust fn or an intrinsic")
|
||||
};
|
||||
|
||||
ccx.stats.n_monos.set(ccx.stats.n_monos.get() + 1);
|
||||
|
||||
let depth;
|
||||
@ -214,11 +206,7 @@ pub fn monomorphic_fn(ccx: &CrateContext,
|
||||
// This shouldn't need to option dance.
|
||||
let mut hash_id = Some(hash_id);
|
||||
let mk_lldecl = || {
|
||||
let lldecl = decl_internal_rust_fn(ccx,
|
||||
false,
|
||||
f.sig.inputs.as_slice(),
|
||||
f.sig.output,
|
||||
s.as_slice());
|
||||
let lldecl = decl_internal_rust_fn(ccx, mono_ty, s.as_slice());
|
||||
ccx.monomorphized.borrow_mut().insert(hash_id.take_unwrap(), lldecl);
|
||||
lldecl
|
||||
};
|
||||
|
@ -291,10 +291,10 @@ impl<'a, 'b> Reflector<'a, 'b> {
|
||||
let sym = mangle_internal_name_by_path_and_seq(
|
||||
ast_map::Values([].iter()).chain(None), "get_disr");
|
||||
|
||||
let fn_ty = ty::mk_ctor_fn(&ccx.tcx, ast::DUMMY_NODE_ID,
|
||||
[opaqueptrty], ty::mk_u64());
|
||||
let llfdecl = decl_internal_rust_fn(ccx,
|
||||
false,
|
||||
[opaqueptrty],
|
||||
ty::mk_u64(),
|
||||
fn_ty,
|
||||
sym.as_slice());
|
||||
let arena = TypedArena::new();
|
||||
let fcx = new_fn_ctxt(ccx, llfdecl, -1, false,
|
||||
|
2
src/llvm
2
src/llvm
@ -1 +1 @@
|
||||
Subproject commit 4b4d0533b4f76cc3fbba31bd9e7ac02e0c738b1d
|
||||
Subproject commit 0a894645cf120539876e9eb4eb0d7b572dfa9d14
|
@ -13,6 +13,7 @@
|
||||
#include "rustllvm.h"
|
||||
|
||||
#include "llvm/Support/CBindingWrapping.h"
|
||||
#include "llvm/Support/FileSystem.h"
|
||||
#include "llvm/Target/TargetLibraryInfo.h"
|
||||
#include "llvm/Transforms/IPO/PassManagerBuilder.h"
|
||||
|
||||
|
@ -12,6 +12,12 @@
|
||||
#include "llvm/Object/Archive.h"
|
||||
#include "llvm/Object/ObjectFile.h"
|
||||
|
||||
#if LLVM_VERSION_MINOR >= 5
|
||||
#include "llvm/IR/CallSite.h"
|
||||
#else
|
||||
#include "llvm/Support/CallSite.h"
|
||||
#endif
|
||||
|
||||
//===----------------------------------------------------------------------===
|
||||
//
|
||||
// This file defines alternate interfaces to core functions that are more
|
||||
@ -83,46 +89,43 @@ extern "C" LLVMTypeRef LLVMMetadataTypeInContext(LLVMContextRef C) {
|
||||
return wrap(Type::getMetadataTy(*unwrap(C)));
|
||||
}
|
||||
|
||||
extern "C" void LLVMAddFunctionAttrString(LLVMValueRef fn, const char *Name) {
|
||||
unwrap<Function>(fn)->addFnAttr(Name);
|
||||
extern "C" void LLVMAddCallSiteAttribute(LLVMValueRef Instr, unsigned index, uint64_t Val) {
|
||||
CallSite Call = CallSite(unwrap<Instruction>(Instr));
|
||||
AttrBuilder B;
|
||||
B.addRawValue(Val);
|
||||
Call.setAttributes(
|
||||
Call.getAttributes().addAttributes(Call->getContext(), index,
|
||||
AttributeSet::get(Call->getContext(),
|
||||
index, B)));
|
||||
}
|
||||
|
||||
extern "C" void LLVMRemoveFunctionAttrString(LLVMValueRef fn, const char *Name) {
|
||||
extern "C" void LLVMAddFunctionAttribute(LLVMValueRef Fn, unsigned index, uint64_t Val) {
|
||||
Function *A = unwrap<Function>(Fn);
|
||||
AttrBuilder B;
|
||||
B.addRawValue(Val);
|
||||
A->addAttributes(index, AttributeSet::get(A->getContext(), index, B));
|
||||
}
|
||||
|
||||
extern "C" void LLVMAddFunctionAttrString(LLVMValueRef Fn, unsigned index, const char *Name) {
|
||||
Function *F = unwrap<Function>(Fn);
|
||||
AttrBuilder B;
|
||||
B.addAttribute(Name);
|
||||
F->addAttributes(index, AttributeSet::get(F->getContext(), index, B));
|
||||
}
|
||||
|
||||
extern "C" void LLVMRemoveFunctionAttrString(LLVMValueRef fn, unsigned index, const char *Name) {
|
||||
Function *f = unwrap<Function>(fn);
|
||||
LLVMContext &C = f->getContext();
|
||||
AttrBuilder B;
|
||||
B.addAttribute(Name);
|
||||
AttributeSet to_remove = AttributeSet::get(C, AttributeSet::FunctionIndex, B);
|
||||
AttributeSet to_remove = AttributeSet::get(C, index, B);
|
||||
|
||||
AttributeSet attrs = f->getAttributes();
|
||||
f->setAttributes(attrs.removeAttributes(f->getContext(),
|
||||
AttributeSet::FunctionIndex,
|
||||
index,
|
||||
to_remove));
|
||||
}
|
||||
|
||||
extern "C" void LLVMAddReturnAttribute(LLVMValueRef Fn, LLVMAttribute PA) {
|
||||
Function *A = unwrap<Function>(Fn);
|
||||
AttrBuilder B(PA);
|
||||
A->addAttributes(AttributeSet::ReturnIndex,
|
||||
AttributeSet::get(A->getContext(), AttributeSet::ReturnIndex, B));
|
||||
}
|
||||
|
||||
extern "C" void LLVMRemoveReturnAttribute(LLVMValueRef Fn, LLVMAttribute PA) {
|
||||
Function *A = unwrap<Function>(Fn);
|
||||
AttrBuilder B(PA);
|
||||
A->removeAttributes(AttributeSet::ReturnIndex,
|
||||
AttributeSet::get(A->getContext(), AttributeSet::ReturnIndex, B));
|
||||
}
|
||||
|
||||
#if LLVM_VERSION_MINOR >= 5
|
||||
extern "C" void LLVMAddColdAttribute(LLVMValueRef Fn) {
|
||||
Function *A = unwrap<Function>(Fn);
|
||||
A->addAttribute(AttributeSet::FunctionIndex, Attribute::Cold);
|
||||
}
|
||||
#else
|
||||
extern "C" void LLVMAddColdAttribute(LLVMValueRef Fn) {}
|
||||
#endif
|
||||
|
||||
extern "C" LLVMValueRef LLVMBuildAtomicLoad(LLVMBuilderRef B,
|
||||
LLVMValueRef source,
|
||||
const char* Name,
|
||||
|
@ -1,4 +1,4 @@
|
||||
# If this file is modified, then llvm will be forcibly cleaned and then rebuilt.
|
||||
# The actual contents of this file do not matter, but to trigger a change on the
|
||||
# build bots then the contents should be changed so git updates the mtime.
|
||||
2014-04-14
|
||||
2014-05-20
|
||||
|
Loading…
x
Reference in New Issue
Block a user