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:
Daniel Micay 2013-09-10 18:42:01 -04:00
parent 6bc48b63f3
commit 3c31cf25b1
5 changed files with 119 additions and 80 deletions

View File

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

View File

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

View File

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

View File

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

View File

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