fix handling of function attributes
The `noalias` attributes were being set only on function definitions, not on all declarations. This is harmless for `noalias`, but prevented some optimization opportunities and is *not* harmless for other attributes like `sret` with ABI implications. Closes #9104
This commit is contained in:
parent
6bc48b63f3
commit
3c31cf25b1
@ -174,6 +174,7 @@ impl<'self> Drop for StatRecorder<'self> {
|
||||
}
|
||||
}
|
||||
|
||||
// only use this for foreign function ABIs and glue, use `decl_rust_fn` for Rust functions
|
||||
pub fn decl_fn(llmod: ModuleRef, name: &str, cc: lib::llvm::CallConv, ty: Type) -> ValueRef {
|
||||
let llfn: ValueRef = do name.with_c_str |buf| {
|
||||
unsafe {
|
||||
@ -185,18 +186,12 @@ pub fn decl_fn(llmod: ModuleRef, name: &str, cc: lib::llvm::CallConv, ty: Type)
|
||||
return llfn;
|
||||
}
|
||||
|
||||
// only use this for foreign function ABIs and glue, use `decl_rust_fn` for Rust functions
|
||||
pub fn decl_cdecl_fn(llmod: ModuleRef, name: &str, ty: Type) -> ValueRef {
|
||||
return decl_fn(llmod, name, lib::llvm::CCallConv, ty);
|
||||
}
|
||||
|
||||
// Only use this if you are going to actually define the function. It's
|
||||
// not valid to simply declare a function as internal.
|
||||
pub fn decl_internal_cdecl_fn(llmod: ModuleRef, name: &str, ty: Type) -> ValueRef {
|
||||
let llfn = decl_cdecl_fn(llmod, name, ty);
|
||||
lib::llvm::SetLinkage(llfn, lib::llvm::InternalLinkage);
|
||||
return llfn;
|
||||
}
|
||||
|
||||
// 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, name: &str,
|
||||
cc: lib::llvm::CallConv, ty: Type) -> ValueRef {
|
||||
match externs.find_equiv(&name) {
|
||||
@ -205,7 +200,62 @@ pub fn get_extern_fn(externs: &mut ExternMap, llmod: ModuleRef, name: &str,
|
||||
}
|
||||
let f = decl_fn(llmod, name, cc, ty);
|
||||
externs.insert(name.to_owned(), f);
|
||||
return f;
|
||||
f
|
||||
}
|
||||
|
||||
pub fn get_extern_rust_fn(ccx: &mut CrateContext, inputs: &[ty::t], output: ty::t,
|
||||
name: &str) -> ValueRef {
|
||||
match ccx.externs.find_equiv(&name) {
|
||||
Some(n) => return *n,
|
||||
None => ()
|
||||
}
|
||||
let f = decl_rust_fn(ccx, inputs, output, name);
|
||||
ccx.externs.insert(name.to_owned(), f);
|
||||
f
|
||||
}
|
||||
|
||||
pub fn decl_rust_fn(ccx: &mut CrateContext, inputs: &[ty::t], output: ty::t,
|
||||
name: &str) -> ValueRef {
|
||||
let llfty = type_of_rust_fn(ccx, inputs, output);
|
||||
let llfn = decl_cdecl_fn(ccx.llmod, name, llfty);
|
||||
|
||||
match ty::get(output).sty {
|
||||
// `~` pointer return values never alias because ownership is transferred
|
||||
ty::ty_uniq(*) |
|
||||
ty::ty_evec(_, ty::vstore_uniq) => {
|
||||
unsafe {
|
||||
llvm::LLVMAddReturnAttribute(llfn, lib::llvm::NoAliasAttribute as c_uint);
|
||||
}
|
||||
}
|
||||
_ => ()
|
||||
}
|
||||
|
||||
let uses_outptr = type_of::return_uses_outptr(ccx.tcx, output);
|
||||
let offset = if uses_outptr { 2 } else { 1 };
|
||||
|
||||
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(*) |
|
||||
ty::ty_evec(_, ty::vstore_uniq) |
|
||||
ty::ty_closure(ty::ClosureTy {sigil: ast::OwnedSigil, _}) => {
|
||||
unsafe {
|
||||
llvm::LLVMAddAttribute(llarg, lib::llvm::NoAliasAttribute as c_uint);
|
||||
}
|
||||
}
|
||||
_ => ()
|
||||
}
|
||||
}
|
||||
|
||||
llfn
|
||||
}
|
||||
|
||||
pub fn decl_internal_rust_fn(ccx: &mut CrateContext, inputs: &[ty::t], output: ty::t,
|
||||
name: &str) -> ValueRef {
|
||||
let llfn = decl_rust_fn(ccx, inputs, output, name);
|
||||
lib::llvm::SetLinkage(llfn, lib::llvm::InternalLinkage);
|
||||
llfn
|
||||
}
|
||||
|
||||
pub fn get_extern_const(externs: &mut ExternMap, llmod: ModuleRef,
|
||||
@ -809,33 +859,30 @@ pub fn null_env_ptr(ccx: &CrateContext) -> ValueRef {
|
||||
C_null(Type::opaque_box(ccx).ptr_to())
|
||||
}
|
||||
|
||||
pub fn trans_external_path(ccx: &mut CrateContext, did: ast::DefId, t: ty::t)
|
||||
-> ValueRef {
|
||||
pub fn trans_external_path(ccx: &mut CrateContext, did: ast::DefId, t: ty::t) -> ValueRef {
|
||||
let name = csearch::get_symbol(ccx.sess.cstore, did);
|
||||
match ty::get(t).sty {
|
||||
ty::ty_bare_fn(ref fn_ty) => {
|
||||
// Currently llvm_calling_convention triggers unimpl/bug on
|
||||
// Rust/RustIntrinsic, so those two are handled specially here.
|
||||
let cconv = match fn_ty.abis.for_arch(ccx.sess.targ_cfg.arch) {
|
||||
Some(Rust) | Some(RustIntrinsic) => lib::llvm::CCallConv,
|
||||
match fn_ty.abis.for_arch(ccx.sess.targ_cfg.arch) {
|
||||
Some(Rust) | Some(RustIntrinsic) => {
|
||||
get_extern_rust_fn(ccx, fn_ty.sig.inputs, fn_ty.sig.output, name)
|
||||
}
|
||||
Some(*) | None => {
|
||||
let c = foreign::llvm_calling_convention(ccx, fn_ty.abis);
|
||||
c.unwrap_or(lib::llvm::CCallConv)
|
||||
let cconv = c.unwrap_or(lib::llvm::CCallConv);
|
||||
let llty = type_of_fn_from_ty(ccx, t);
|
||||
get_extern_fn(&mut ccx.externs, ccx.llmod, name, cconv, llty)
|
||||
}
|
||||
};
|
||||
let llty = type_of_fn_from_ty(ccx, t);
|
||||
return get_extern_fn(&mut ccx.externs, ccx.llmod, name, cconv, llty);
|
||||
}
|
||||
}
|
||||
ty::ty_closure(_) => {
|
||||
let llty = type_of_fn_from_ty(ccx, t);
|
||||
return get_extern_fn(&mut ccx.externs, ccx.llmod, name,
|
||||
lib::llvm::CCallConv, llty);
|
||||
ty::ty_closure(ref f) => {
|
||||
get_extern_rust_fn(ccx, f.sig.inputs, f.sig.output, name)
|
||||
}
|
||||
_ => {
|
||||
let llty = type_of(ccx, t);
|
||||
return get_extern_const(&mut ccx.externs, ccx.llmod, name, llty);
|
||||
get_extern_const(&mut ccx.externs, ccx.llmod, name, llty)
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
pub fn invoke(bcx: @mut Block, llfn: ValueRef, llargs: ~[ValueRef],
|
||||
@ -1707,8 +1754,7 @@ pub fn new_fn_ctxt(ccx: @mut CrateContext,
|
||||
// field of the fn_ctxt with
|
||||
pub fn create_llargs_for_fn_args(cx: @mut FunctionContext,
|
||||
self_arg: self_arg,
|
||||
args: &[ast::arg],
|
||||
arg_tys: &[ty::t])
|
||||
args: &[ast::arg])
|
||||
-> ~[ValueRef] {
|
||||
let _icx = push_ctxt("create_llargs_for_fn_args");
|
||||
|
||||
@ -1726,23 +1772,7 @@ pub fn create_llargs_for_fn_args(cx: @mut FunctionContext,
|
||||
// Return an array containing the ValueRefs that we get from
|
||||
// llvm::LLVMGetParam for each argument.
|
||||
do vec::from_fn(args.len()) |i| {
|
||||
let arg_n = cx.arg_pos(i);
|
||||
let arg_ty = arg_tys[i];
|
||||
let llarg = unsafe {llvm::LLVMGetParam(cx.llfn, arg_n as c_uint) };
|
||||
|
||||
match ty::get(arg_ty).sty {
|
||||
// `~` pointer parameters never alias because ownership is transferred
|
||||
ty::ty_uniq(*) |
|
||||
ty::ty_evec(_, ty::vstore_uniq) |
|
||||
ty::ty_closure(ty::ClosureTy {sigil: ast::OwnedSigil, _}) => {
|
||||
unsafe {
|
||||
llvm::LLVMAddAttribute(llarg, lib::llvm::NoAliasAttribute as c_uint);
|
||||
}
|
||||
}
|
||||
_ => ()
|
||||
}
|
||||
|
||||
llarg
|
||||
unsafe { llvm::LLVMGetParam(cx.llfn, cx.arg_pos(i) as c_uint) }
|
||||
}
|
||||
}
|
||||
|
||||
@ -1896,8 +1926,7 @@ pub fn trans_closure(ccx: @mut CrateContext,
|
||||
|
||||
// Set up arguments to the function.
|
||||
let arg_tys = ty::ty_fn_args(node_id_type(bcx, id));
|
||||
let raw_llargs = create_llargs_for_fn_args(fcx, self_arg,
|
||||
decl.inputs, arg_tys);
|
||||
let raw_llargs = create_llargs_for_fn_args(fcx, self_arg, decl.inputs);
|
||||
|
||||
// Set the fixed stack segment flag if necessary.
|
||||
if attr::contains_name(attributes, "fixed_stack_segment") {
|
||||
@ -1961,18 +1990,6 @@ pub fn trans_fn(ccx: @mut CrateContext,
|
||||
param_substs.repr(ccx.tcx));
|
||||
let _icx = push_ctxt("trans_fn");
|
||||
let output_type = ty::ty_fn_ret(ty::node_id_to_type(ccx.tcx, id));
|
||||
|
||||
match ty::get(output_type).sty {
|
||||
// `~` pointer return values never alias because ownership is transferred
|
||||
ty::ty_uniq(*) |
|
||||
ty::ty_evec(_, ty::vstore_uniq) => {
|
||||
unsafe {
|
||||
llvm::LLVMAddReturnAttribute(llfndecl, lib::llvm::NoAliasAttribute as c_uint);
|
||||
}
|
||||
}
|
||||
_ => ()
|
||||
}
|
||||
|
||||
trans_closure(ccx,
|
||||
path.clone(),
|
||||
decl,
|
||||
@ -2120,7 +2137,7 @@ pub fn trans_enum_variant_or_tuple_like_struct<A:IdAndTy>(
|
||||
|
||||
let arg_tys = ty::ty_fn_args(ctor_ty);
|
||||
|
||||
let raw_llargs = create_llargs_for_fn_args(fcx, no_self, fn_args, arg_tys);
|
||||
let raw_llargs = create_llargs_for_fn_args(fcx, no_self, fn_args);
|
||||
|
||||
let bcx = fcx.entry_bcx.unwrap();
|
||||
|
||||
@ -2298,10 +2315,28 @@ pub fn register_fn(ccx: @mut CrateContext,
|
||||
node_id: ast::NodeId,
|
||||
node_type: ty::t)
|
||||
-> ValueRef {
|
||||
let llfty = type_of_fn_from_ty(ccx, node_type);
|
||||
register_fn_llvmty(ccx, sp, sym, node_id, lib::llvm::CCallConv, llfty)
|
||||
let f = match ty::get(node_type).sty {
|
||||
ty::ty_bare_fn(ref f) => {
|
||||
assert!(f.abis.is_rust() || f.abis.is_intrinsic());
|
||||
f
|
||||
}
|
||||
_ => fail!("expected bare rust fn or an intrinsic")
|
||||
};
|
||||
|
||||
let llfn = decl_rust_fn(ccx, f.sig.inputs, f.sig.output, sym);
|
||||
ccx.item_symbols.insert(node_id, sym);
|
||||
|
||||
// FIXME #4404 android JNI hacks
|
||||
let is_entry = is_entry_fn(&ccx.sess, node_id) && (!*ccx.sess.building_library ||
|
||||
(*ccx.sess.building_library &&
|
||||
ccx.sess.targ_cfg.os == session::OsAndroid));
|
||||
if is_entry {
|
||||
create_entry_wrapper(ccx, sp, llfn);
|
||||
}
|
||||
llfn
|
||||
}
|
||||
|
||||
// only use this for foreign function ABIs and glue, use `register_fn` for Rust functions
|
||||
pub fn register_fn_llvmty(ccx: @mut CrateContext,
|
||||
sp: Span,
|
||||
sym: ~str,
|
||||
|
@ -381,8 +381,10 @@ pub fn trans_expr_fn(bcx: @mut Block,
|
||||
|
||||
let ccx = bcx.ccx();
|
||||
let fty = node_id_type(bcx, outer_id);
|
||||
|
||||
let llfnty = type_of_fn_from_ty(ccx, fty);
|
||||
let f = match ty::get(fty).sty {
|
||||
ty::ty_closure(ref f) => f,
|
||||
_ => fail!("expected closure")
|
||||
};
|
||||
|
||||
let sub_path = vec::append_one(bcx.fcx.path.clone(),
|
||||
path_name(special_idents::anon));
|
||||
@ -390,7 +392,7 @@ pub fn trans_expr_fn(bcx: @mut Block,
|
||||
let s = mangle_internal_name_by_path_and_seq(ccx,
|
||||
sub_path.clone(),
|
||||
"expr_fn");
|
||||
let llfn = decl_internal_cdecl_fn(ccx.llmod, s, llfnty);
|
||||
let llfn = decl_internal_rust_fn(ccx, f.sig.inputs, f.sig.output, s);
|
||||
|
||||
// set an inline hint for all closures
|
||||
set_inline_hint(llfn);
|
||||
|
@ -21,7 +21,6 @@ use middle::trans::cabi;
|
||||
use middle::trans::build::*;
|
||||
use middle::trans::builder::noname;
|
||||
use middle::trans::common::*;
|
||||
use middle::trans::llrepr::LlvmRepr;
|
||||
use middle::trans::type_of::*;
|
||||
use middle::trans::type_of;
|
||||
use middle::ty;
|
||||
@ -406,13 +405,12 @@ pub fn trans_rust_fn_with_foreign_abi(ccx: @mut CrateContext,
|
||||
special_idents::clownshoe_abi
|
||||
)));
|
||||
|
||||
// Compute the LLVM type that the function would have if it
|
||||
// were just a normal Rust function. This will be the type of
|
||||
// the wrappee fn.
|
||||
let llty = match ty::get(t).sty {
|
||||
// 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 {
|
||||
ty::ty_bare_fn(ref f) => {
|
||||
assert!(!f.abis.is_rust() && !f.abis.is_intrinsic());
|
||||
type_of_rust_fn(ccx, f.sig.inputs, f.sig.output)
|
||||
f
|
||||
}
|
||||
_ => {
|
||||
ccx.sess.bug(fmt!("build_rust_fn: extern fn %s has ty %s, \
|
||||
@ -422,13 +420,12 @@ pub fn trans_rust_fn_with_foreign_abi(ccx: @mut CrateContext,
|
||||
}
|
||||
};
|
||||
|
||||
debug!("build_rust_fn: path=%s id=%? t=%s llty=%s",
|
||||
debug!("build_rust_fn: path=%s id=%? t=%s",
|
||||
path.repr(tcx),
|
||||
id,
|
||||
t.repr(tcx),
|
||||
llty.llrepr(ccx));
|
||||
t.repr(tcx));
|
||||
|
||||
let llfndecl = base::decl_internal_cdecl_fn(ccx.llmod, ps, llty);
|
||||
let llfndecl = base::decl_internal_rust_fn(ccx, f.sig.inputs, f.sig.output, ps);
|
||||
base::trans_fn(ccx,
|
||||
(*path).clone(),
|
||||
decl,
|
||||
|
@ -14,14 +14,13 @@ use driver::session;
|
||||
use lib::llvm::ValueRef;
|
||||
use middle::trans::base::{set_llvm_fn_attrs, set_inline_hint};
|
||||
use middle::trans::base::{trans_enum_variant,push_ctxt};
|
||||
use middle::trans::base::{trans_fn, decl_internal_cdecl_fn};
|
||||
use middle::trans::base::{trans_fn, decl_internal_rust_fn};
|
||||
use middle::trans::base::{get_item_val, no_self};
|
||||
use middle::trans::base;
|
||||
use middle::trans::common::*;
|
||||
use middle::trans::datum;
|
||||
use middle::trans::machine;
|
||||
use middle::trans::meth;
|
||||
use middle::trans::type_of::type_of_fn_from_ty;
|
||||
use middle::trans::type_of;
|
||||
use middle::trans::type_use;
|
||||
use middle::trans::intrinsic;
|
||||
@ -177,7 +176,14 @@ pub fn monomorphic_fn(ccx: @mut CrateContext,
|
||||
ty::subst_tps(ccx.tcx, substs, None, llitem_ty)
|
||||
}
|
||||
};
|
||||
let llfty = type_of_fn_from_ty(ccx, mono_ty);
|
||||
|
||||
let f = match ty::get(mono_ty).sty {
|
||||
ty::ty_bare_fn(ref f) => {
|
||||
assert!(f.abis.is_rust() || f.abis.is_intrinsic());
|
||||
f
|
||||
}
|
||||
_ => fail!("expected bare rust fn or an intrinsic")
|
||||
};
|
||||
|
||||
ccx.stats.n_monos += 1;
|
||||
|
||||
@ -200,7 +206,7 @@ pub fn monomorphic_fn(ccx: @mut CrateContext,
|
||||
debug!("monomorphize_fn mangled to %s", s);
|
||||
|
||||
let mk_lldecl = || {
|
||||
let lldecl = decl_internal_cdecl_fn(ccx.llmod, s, llfty);
|
||||
let lldecl = decl_internal_rust_fn(ccx, f.sig.inputs, f.sig.output, s);
|
||||
ccx.monomorphized.insert(hash_id, lldecl);
|
||||
lldecl
|
||||
};
|
||||
|
@ -293,8 +293,7 @@ impl Reflector {
|
||||
sub_path,
|
||||
"get_disr");
|
||||
|
||||
let llfty = type_of_rust_fn(ccx, [opaqueptrty], ty::mk_int());
|
||||
let llfdecl = decl_internal_cdecl_fn(ccx.llmod, sym, llfty);
|
||||
let llfdecl = decl_internal_rust_fn(ccx, [opaqueptrty], ty::mk_int(), sym);
|
||||
let fcx = new_fn_ctxt(ccx,
|
||||
~[],
|
||||
llfdecl,
|
||||
|
Loading…
x
Reference in New Issue
Block a user