Skip to content

Commit 38d4f48

Browse files
committed
auto merge of #9109 : thestinger/rust/function, r=alexcrichton
2 parents bc89ade + 1afaf0b commit 38d4f48

File tree

8 files changed

+172
-112
lines changed

8 files changed

+172
-112
lines changed

src/librustc/middle/trans/base.rs

Lines changed: 109 additions & 62 deletions
Original file line numberDiff line numberDiff line change
@@ -174,6 +174,7 @@ impl<'self> Drop for StatRecorder<'self> {
174174
}
175175
}
176176

177+
// only use this for foreign function ABIs and glue, use `decl_rust_fn` for Rust functions
177178
pub fn decl_fn(llmod: ModuleRef, name: &str, cc: lib::llvm::CallConv, ty: Type) -> ValueRef {
178179
let llfn: ValueRef = do name.with_c_str |buf| {
179180
unsafe {
@@ -185,18 +186,12 @@ pub fn decl_fn(llmod: ModuleRef, name: &str, cc: lib::llvm::CallConv, ty: Type)
185186
return llfn;
186187
}
187188

189+
// only use this for foreign function ABIs and glue, use `decl_rust_fn` for Rust functions
188190
pub fn decl_cdecl_fn(llmod: ModuleRef, name: &str, ty: Type) -> ValueRef {
189191
return decl_fn(llmod, name, lib::llvm::CCallConv, ty);
190192
}
191193

192-
// Only use this if you are going to actually define the function. It's
193-
// not valid to simply declare a function as internal.
194-
pub fn decl_internal_cdecl_fn(llmod: ModuleRef, name: &str, ty: Type) -> ValueRef {
195-
let llfn = decl_cdecl_fn(llmod, name, ty);
196-
lib::llvm::SetLinkage(llfn, lib::llvm::InternalLinkage);
197-
return llfn;
198-
}
199-
194+
// only use this for foreign function ABIs and glue, use `get_extern_rust_fn` for Rust functions
200195
pub fn get_extern_fn(externs: &mut ExternMap, llmod: ModuleRef, name: &str,
201196
cc: lib::llvm::CallConv, ty: Type) -> ValueRef {
202197
match externs.find_equiv(&name) {
@@ -205,7 +200,73 @@ pub fn get_extern_fn(externs: &mut ExternMap, llmod: ModuleRef, name: &str,
205200
}
206201
let f = decl_fn(llmod, name, cc, ty);
207202
externs.insert(name.to_owned(), f);
208-
return f;
203+
f
204+
}
205+
206+
pub fn get_extern_rust_fn(ccx: &mut CrateContext, inputs: &[ty::t], output: ty::t,
207+
name: &str) -> ValueRef {
208+
match ccx.externs.find_equiv(&name) {
209+
Some(n) => return *n,
210+
None => ()
211+
}
212+
let f = decl_rust_fn(ccx, inputs, output, name);
213+
ccx.externs.insert(name.to_owned(), f);
214+
f
215+
}
216+
217+
pub fn decl_rust_fn(ccx: &mut CrateContext, inputs: &[ty::t], output: ty::t,
218+
name: &str) -> ValueRef {
219+
let llfty = type_of_rust_fn(ccx, inputs, output);
220+
let llfn = decl_cdecl_fn(ccx.llmod, name, llfty);
221+
222+
match ty::get(output).sty {
223+
// `~` pointer return values never alias because ownership is transferred
224+
ty::ty_uniq(*) |
225+
ty::ty_evec(_, ty::vstore_uniq) => {
226+
unsafe {
227+
llvm::LLVMAddReturnAttribute(llfn, lib::llvm::NoAliasAttribute as c_uint);
228+
}
229+
}
230+
_ => ()
231+
}
232+
233+
let uses_outptr = type_of::return_uses_outptr(ccx.tcx, output);
234+
let offset = if uses_outptr { 2 } else { 1 };
235+
236+
for (i, &arg_ty) in inputs.iter().enumerate() {
237+
let llarg = unsafe { llvm::LLVMGetParam(llfn, (offset + i) as c_uint) };
238+
match ty::get(arg_ty).sty {
239+
// `~` pointer parameters never alias because ownership is transferred
240+
ty::ty_uniq(*) |
241+
ty::ty_evec(_, ty::vstore_uniq) |
242+
ty::ty_closure(ty::ClosureTy {sigil: ast::OwnedSigil, _}) => {
243+
unsafe {
244+
llvm::LLVMAddAttribute(llarg, lib::llvm::NoAliasAttribute as c_uint);
245+
}
246+
}
247+
_ => ()
248+
}
249+
}
250+
251+
// The out pointer will never alias with any other pointers, as the object only exists at a
252+
// language level after the call. It can also be tagged with SRet to indicate that it is
253+
// guaranteed to point to a usable block of memory for the type.
254+
if uses_outptr {
255+
unsafe {
256+
let outptr = llvm::LLVMGetParam(llfn, 0);
257+
llvm::LLVMAddAttribute(outptr, lib::llvm::StructRetAttribute as c_uint);
258+
llvm::LLVMAddAttribute(outptr, lib::llvm::NoAliasAttribute as c_uint);
259+
}
260+
}
261+
262+
llfn
263+
}
264+
265+
pub fn decl_internal_rust_fn(ccx: &mut CrateContext, inputs: &[ty::t], output: ty::t,
266+
name: &str) -> ValueRef {
267+
let llfn = decl_rust_fn(ccx, inputs, output, name);
268+
lib::llvm::SetLinkage(llfn, lib::llvm::InternalLinkage);
269+
llfn
209270
}
210271

211272
pub fn get_extern_const(externs: &mut ExternMap, llmod: ModuleRef,
@@ -809,33 +870,30 @@ pub fn null_env_ptr(ccx: &CrateContext) -> ValueRef {
809870
C_null(Type::opaque_box(ccx).ptr_to())
810871
}
811872
812-
pub fn trans_external_path(ccx: &mut CrateContext, did: ast::DefId, t: ty::t)
813-
-> ValueRef {
873+
pub fn trans_external_path(ccx: &mut CrateContext, did: ast::DefId, t: ty::t) -> ValueRef {
814874
let name = csearch::get_symbol(ccx.sess.cstore, did);
815875
match ty::get(t).sty {
816876
ty::ty_bare_fn(ref fn_ty) => {
817-
// Currently llvm_calling_convention triggers unimpl/bug on
818-
// Rust/RustIntrinsic, so those two are handled specially here.
819-
let cconv = match fn_ty.abis.for_arch(ccx.sess.targ_cfg.arch) {
820-
Some(Rust) | Some(RustIntrinsic) => lib::llvm::CCallConv,
877+
match fn_ty.abis.for_arch(ccx.sess.targ_cfg.arch) {
878+
Some(Rust) | Some(RustIntrinsic) => {
879+
get_extern_rust_fn(ccx, fn_ty.sig.inputs, fn_ty.sig.output, name)
880+
}
821881
Some(*) | None => {
822882
let c = foreign::llvm_calling_convention(ccx, fn_ty.abis);
823-
c.unwrap_or(lib::llvm::CCallConv)
883+
let cconv = c.unwrap_or(lib::llvm::CCallConv);
884+
let llty = type_of_fn_from_ty(ccx, t);
885+
get_extern_fn(&mut ccx.externs, ccx.llmod, name, cconv, llty)
824886
}
825-
};
826-
let llty = type_of_fn_from_ty(ccx, t);
827-
return get_extern_fn(&mut ccx.externs, ccx.llmod, name, cconv, llty);
887+
}
828888
}
829-
ty::ty_closure(_) => {
830-
let llty = type_of_fn_from_ty(ccx, t);
831-
return get_extern_fn(&mut ccx.externs, ccx.llmod, name,
832-
lib::llvm::CCallConv, llty);
889+
ty::ty_closure(ref f) => {
890+
get_extern_rust_fn(ccx, f.sig.inputs, f.sig.output, name)
833891
}
834892
_ => {
835893
let llty = type_of(ccx, t);
836-
return get_extern_const(&mut ccx.externs, ccx.llmod, name, llty);
894+
get_extern_const(&mut ccx.externs, ccx.llmod, name, llty)
837895
}
838-
};
896+
}
839897
}
840898
841899
pub fn invoke(bcx: @mut Block, llfn: ValueRef, llargs: ~[ValueRef],
@@ -868,7 +926,8 @@ pub fn invoke(bcx: @mut Block, llfn: ValueRef, llargs: ~[ValueRef],
868926
llfn,
869927
llargs,
870928
normal_bcx.llbb,
871-
get_landing_pad(bcx));
929+
get_landing_pad(bcx),
930+
attributes);
872931
return (llresult, normal_bcx);
873932
} else {
874933
unsafe {
@@ -1707,8 +1766,7 @@ pub fn new_fn_ctxt(ccx: @mut CrateContext,
17071766
// field of the fn_ctxt with
17081767
pub fn create_llargs_for_fn_args(cx: @mut FunctionContext,
17091768
self_arg: self_arg,
1710-
args: &[ast::arg],
1711-
arg_tys: &[ty::t])
1769+
args: &[ast::arg])
17121770
-> ~[ValueRef] {
17131771
let _icx = push_ctxt("create_llargs_for_fn_args");
17141772

@@ -1726,23 +1784,7 @@ pub fn create_llargs_for_fn_args(cx: @mut FunctionContext,
17261784
// Return an array containing the ValueRefs that we get from
17271785
// llvm::LLVMGetParam for each argument.
17281786
do vec::from_fn(args.len()) |i| {
1729-
let arg_n = cx.arg_pos(i);
1730-
let arg_ty = arg_tys[i];
1731-
let llarg = unsafe {llvm::LLVMGetParam(cx.llfn, arg_n as c_uint) };
1732-
1733-
match ty::get(arg_ty).sty {
1734-
// `~` pointer parameters never alias because ownership is transferred
1735-
ty::ty_uniq(*) |
1736-
ty::ty_evec(_, ty::vstore_uniq) |
1737-
ty::ty_closure(ty::ClosureTy {sigil: ast::OwnedSigil, _}) => {
1738-
unsafe {
1739-
llvm::LLVMAddAttribute(llarg, lib::llvm::NoAliasAttribute as c_uint);
1740-
}
1741-
}
1742-
_ => ()
1743-
}
1744-
1745-
llarg
1787+
unsafe { llvm::LLVMGetParam(cx.llfn, cx.arg_pos(i) as c_uint) }
17461788
}
17471789
}
17481790

@@ -1896,8 +1938,7 @@ pub fn trans_closure(ccx: @mut CrateContext,
18961938

18971939
// Set up arguments to the function.
18981940
let arg_tys = ty::ty_fn_args(node_id_type(bcx, id));
1899-
let raw_llargs = create_llargs_for_fn_args(fcx, self_arg,
1900-
decl.inputs, arg_tys);
1941+
let raw_llargs = create_llargs_for_fn_args(fcx, self_arg, decl.inputs);
19011942

19021943
// Set the fixed stack segment flag if necessary.
19031944
if attr::contains_name(attributes, "fixed_stack_segment") {
@@ -1961,18 +2002,6 @@ pub fn trans_fn(ccx: @mut CrateContext,
19612002
param_substs.repr(ccx.tcx));
19622003
let _icx = push_ctxt("trans_fn");
19632004
let output_type = ty::ty_fn_ret(ty::node_id_to_type(ccx.tcx, id));
1964-
1965-
match ty::get(output_type).sty {
1966-
// `~` pointer return values never alias because ownership is transferred
1967-
ty::ty_uniq(*) |
1968-
ty::ty_evec(_, ty::vstore_uniq) => {
1969-
unsafe {
1970-
llvm::LLVMAddReturnAttribute(llfndecl, lib::llvm::NoAliasAttribute as c_uint);
1971-
}
1972-
}
1973-
_ => ()
1974-
}
1975-
19762005
trans_closure(ccx,
19772006
path.clone(),
19782007
decl,
@@ -2120,7 +2149,7 @@ pub fn trans_enum_variant_or_tuple_like_struct<A:IdAndTy>(
21202149

21212150
let arg_tys = ty::ty_fn_args(ctor_ty);
21222151

2123-
let raw_llargs = create_llargs_for_fn_args(fcx, no_self, fn_args, arg_tys);
2152+
let raw_llargs = create_llargs_for_fn_args(fcx, no_self, fn_args);
21242153

21252154
let bcx = fcx.entry_bcx.unwrap();
21262155

@@ -2298,10 +2327,28 @@ pub fn register_fn(ccx: @mut CrateContext,
22982327
node_id: ast::NodeId,
22992328
node_type: ty::t)
23002329
-> ValueRef {
2301-
let llfty = type_of_fn_from_ty(ccx, node_type);
2302-
register_fn_llvmty(ccx, sp, sym, node_id, lib::llvm::CCallConv, llfty)
2330+
let f = match ty::get(node_type).sty {
2331+
ty::ty_bare_fn(ref f) => {
2332+
assert!(f.abis.is_rust() || f.abis.is_intrinsic());
2333+
f
2334+
}
2335+
_ => fail!("expected bare rust fn or an intrinsic")
2336+
};
2337+
2338+
let llfn = decl_rust_fn(ccx, f.sig.inputs, f.sig.output, sym);
2339+
ccx.item_symbols.insert(node_id, sym);
2340+
2341+
// FIXME #4404 android JNI hacks
2342+
let is_entry = is_entry_fn(&ccx.sess, node_id) && (!*ccx.sess.building_library ||
2343+
(*ccx.sess.building_library &&
2344+
ccx.sess.targ_cfg.os == session::OsAndroid));
2345+
if is_entry {
2346+
create_entry_wrapper(ccx, sp, llfn);
2347+
}
2348+
llfn
23032349
}
23042350

2351+
// only use this for foreign function ABIs and glue, use `register_fn` for Rust functions
23052352
pub fn register_fn_llvmty(ccx: @mut CrateContext,
23062353
sp: Span,
23072354
sym: ~str,

src/librustc/middle/trans/build.rs

Lines changed: 3 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -109,7 +109,8 @@ pub fn Invoke(cx: @mut Block,
109109
Fn: ValueRef,
110110
Args: &[ValueRef],
111111
Then: BasicBlockRef,
112-
Catch: BasicBlockRef)
112+
Catch: BasicBlockRef,
113+
attributes: &[(uint, lib::llvm::Attribute)])
113114
-> ValueRef {
114115
if cx.unreachable {
115116
return C_null(Type::i8());
@@ -119,15 +120,7 @@ pub fn Invoke(cx: @mut Block,
119120
debug!("Invoke(%s with arguments (%s))",
120121
cx.val_to_str(Fn),
121122
Args.map(|a| cx.val_to_str(*a)).connect(", "));
122-
B(cx).invoke(Fn, Args, Then, Catch)
123-
}
124-
125-
pub fn FastInvoke(cx: @mut Block, Fn: ValueRef, Args: &[ValueRef],
126-
Then: BasicBlockRef, Catch: BasicBlockRef) {
127-
if cx.unreachable { return; }
128-
check_not_terminated(cx);
129-
terminate(cx, "FastInvoke");
130-
B(cx).fast_invoke(Fn, Args, Then, Catch);
123+
B(cx).invoke(Fn, Args, Then, Catch, attributes)
131124
}
132125

133126
pub fn Unreachable(cx: @mut Block) {

src/librustc/middle/trans/builder.rs

Lines changed: 13 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -154,30 +154,25 @@ impl Builder {
154154
llfn: ValueRef,
155155
args: &[ValueRef],
156156
then: BasicBlockRef,
157-
catch: BasicBlockRef)
157+
catch: BasicBlockRef,
158+
attributes: &[(uint, lib::llvm::Attribute)])
158159
-> ValueRef {
159160
self.count_insn("invoke");
160161
unsafe {
161-
llvm::LLVMBuildInvoke(self.llbuilder,
162-
llfn,
163-
vec::raw::to_ptr(args),
164-
args.len() as c_uint,
165-
then,
166-
catch,
167-
noname())
162+
let v = llvm::LLVMBuildInvoke(self.llbuilder,
163+
llfn,
164+
vec::raw::to_ptr(args),
165+
args.len() as c_uint,
166+
then,
167+
catch,
168+
noname());
169+
for &(idx, attr) in attributes.iter() {
170+
llvm::LLVMAddInstrAttribute(v, idx as c_uint, attr as c_uint);
171+
}
172+
v
168173
}
169174
}
170175

171-
pub fn fast_invoke(&self,
172-
llfn: ValueRef,
173-
args: &[ValueRef],
174-
then: BasicBlockRef,
175-
catch: BasicBlockRef) {
176-
self.count_insn("fastinvoke");
177-
let v = self.invoke(llfn, args, then, catch);
178-
lib::llvm::SetInstructionCallConv(v, lib::llvm::FastCallConv);
179-
}
180-
181176
pub fn unreachable(&self) {
182177
self.count_insn("unreachable");
183178
unsafe {

src/librustc/middle/trans/callee.rs

Lines changed: 20 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ use std::vec;
2020

2121
use back::abi;
2222
use driver::session;
23-
use lib::llvm::ValueRef;
23+
use lib::llvm::{ValueRef, NoAliasAttribute, StructRetAttribute};
2424
use lib::llvm::llvm;
2525
use metadata::csearch;
2626
use middle::trans::base;
@@ -706,8 +706,26 @@ pub fn trans_call_inner(in_cx: @mut Block,
706706
_ => {}
707707
}
708708

709+
// A function pointer is called without the declaration available, so we have to apply
710+
// any attributes with ABI implications directly to the call instruction. Right now, the
711+
// only attribute we need to worry about is `sret`.
712+
let mut attrs = ~[];
713+
if type_of::return_uses_outptr(in_cx.tcx(), ret_ty) {
714+
attrs.push((1, StructRetAttribute));
715+
}
716+
717+
// The `noalias` attribute on the return value is useful to a function ptr caller.
718+
match ty::get(ret_ty).sty {
719+
// `~` pointer return values never alias because ownership is transferred
720+
ty::ty_uniq(*) |
721+
ty::ty_evec(_, ty::vstore_uniq) => {
722+
attrs.push((0, NoAliasAttribute));
723+
}
724+
_ => ()
725+
}
726+
709727
// Invoke the actual rust fn and update bcx/llresult.
710-
let (llret, b) = base::invoke(bcx, llfn, llargs, []);
728+
let (llret, b) = base::invoke(bcx, llfn, llargs, attrs);
711729
bcx = b;
712730
llresult = llret;
713731

src/librustc/middle/trans/closure.rs

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -381,16 +381,18 @@ pub fn trans_expr_fn(bcx: @mut Block,
381381

382382
let ccx = bcx.ccx();
383383
let fty = node_id_type(bcx, outer_id);
384-
385-
let llfnty = type_of_fn_from_ty(ccx, fty);
384+
let f = match ty::get(fty).sty {
385+
ty::ty_closure(ref f) => f,
386+
_ => fail!("expected closure")
387+
};
386388

387389
let sub_path = vec::append_one(bcx.fcx.path.clone(),
388390
path_name(special_idents::anon));
389391
// XXX: Bad copy.
390392
let s = mangle_internal_name_by_path_and_seq(ccx,
391393
sub_path.clone(),
392394
"expr_fn");
393-
let llfn = decl_internal_cdecl_fn(ccx.llmod, s, llfnty);
395+
let llfn = decl_internal_rust_fn(ccx, f.sig.inputs, f.sig.output, s);
394396

395397
// set an inline hint for all closures
396398
set_inline_hint(llfn);

0 commit comments

Comments
 (0)