Skip to content

Commit d7c8cac

Browse files
committed
rustc: Extract native function generation into trans::native
1 parent 4cc1e31 commit d7c8cac

File tree

3 files changed

+194
-183
lines changed

3 files changed

+194
-183
lines changed

src/comp/middle/trans/base.rs

Lines changed: 2 additions & 183 deletions
Original file line numberDiff line numberDiff line change
@@ -4458,180 +4458,6 @@ fn trans_const(cx: @crate_ctxt, e: @ast::expr, id: ast::node_id) {
44584458
}
44594459
}
44604460

4461-
type c_stack_tys = {
4462-
arg_tys: [TypeRef],
4463-
ret_ty: TypeRef,
4464-
ret_def: bool,
4465-
base_fn_ty: TypeRef,
4466-
bundle_ty: TypeRef,
4467-
shim_fn_ty: TypeRef
4468-
};
4469-
4470-
fn c_stack_tys(ccx: @crate_ctxt,
4471-
id: ast::node_id) -> @c_stack_tys {
4472-
alt ty::get(ty::node_id_to_type(ccx.tcx, id)).struct {
4473-
ty::ty_fn({inputs: arg_tys, output: ret_ty, _}) {
4474-
let llargtys = type_of_explicit_args(ccx, arg_tys);
4475-
let llretty = type_of(ccx, ret_ty);
4476-
let bundle_ty = T_struct(llargtys + [T_ptr(llretty)]);
4477-
ret @{
4478-
arg_tys: llargtys,
4479-
ret_ty: llretty,
4480-
ret_def: !ty::type_is_bot(ret_ty) && !ty::type_is_nil(ret_ty),
4481-
base_fn_ty: T_fn(llargtys, llretty),
4482-
bundle_ty: bundle_ty,
4483-
shim_fn_ty: T_fn([T_ptr(bundle_ty)], T_void())
4484-
};
4485-
}
4486-
_ {
4487-
// Precondition?
4488-
ccx.tcx.sess.bug("c_stack_tys called on non-function type");
4489-
}
4490-
}
4491-
}
4492-
4493-
// For each native function F, we generate a wrapper function W and a shim
4494-
// function S that all work together. The wrapper function W is the function
4495-
// that other rust code actually invokes. Its job is to marshall the
4496-
// arguments into a struct. It then uses a small bit of assembly to switch
4497-
// over to the C stack and invoke the shim function. The shim function S then
4498-
// unpacks the arguments from the struct and invokes the actual function F
4499-
// according to its specified calling convention.
4500-
//
4501-
// Example: Given a native c-stack function F(x: X, y: Y) -> Z,
4502-
// we generate a wrapper function W that looks like:
4503-
//
4504-
// void W(Z* dest, void *env, X x, Y y) {
4505-
// struct { X x; Y y; Z *z; } args = { x, y, z };
4506-
// call_on_c_stack_shim(S, &args);
4507-
// }
4508-
//
4509-
// The shim function S then looks something like:
4510-
//
4511-
// void S(struct { X x; Y y; Z *z; } *args) {
4512-
// *args->z = F(args->x, args->y);
4513-
// }
4514-
//
4515-
// However, if the return type of F is dynamically sized or of aggregate type,
4516-
// the shim function looks like:
4517-
//
4518-
// void S(struct { X x; Y y; Z *z; } *args) {
4519-
// F(args->z, args->x, args->y);
4520-
// }
4521-
//
4522-
// Note: on i386, the layout of the args struct is generally the same as the
4523-
// desired layout of the arguments on the C stack. Therefore, we could use
4524-
// upcall_alloc_c_stack() to allocate the `args` structure and switch the
4525-
// stack pointer appropriately to avoid a round of copies. (In fact, the shim
4526-
// function itself is unnecessary). We used to do this, in fact, and will
4527-
// perhaps do so in the future.
4528-
fn trans_native_mod(ccx: @crate_ctxt,
4529-
native_mod: ast::native_mod, abi: ast::native_abi) {
4530-
fn build_shim_fn(ccx: @crate_ctxt,
4531-
native_item: @ast::native_item,
4532-
tys: @c_stack_tys,
4533-
cc: lib::llvm::CallConv) -> ValueRef {
4534-
let lname = link_name(native_item);
4535-
4536-
// Declare the "prototype" for the base function F:
4537-
let llbasefn = decl_fn(ccx.llmod, lname, cc, tys.base_fn_ty);
4538-
4539-
// Create the shim function:
4540-
let shim_name = lname + "__c_stack_shim";
4541-
let llshimfn = decl_internal_cdecl_fn(
4542-
ccx.llmod, shim_name, tys.shim_fn_ty);
4543-
4544-
// Declare the body of the shim function:
4545-
let fcx = new_fn_ctxt(ccx, [], llshimfn, none);
4546-
let bcx = new_top_block_ctxt(fcx, none);
4547-
let lltop = bcx.llbb;
4548-
let llargbundle = llvm::LLVMGetParam(llshimfn, 0 as c_uint);
4549-
let i = 0u, n = tys.arg_tys.len();
4550-
let llargvals = [];
4551-
while i < n {
4552-
let llargval = load_inbounds(bcx, llargbundle, [0, i as int]);
4553-
llargvals += [llargval];
4554-
i += 1u;
4555-
}
4556-
4557-
// Create the call itself and store the return value:
4558-
let llretval = CallWithConv(bcx, llbasefn,
4559-
llargvals, cc); // r
4560-
if tys.ret_def {
4561-
// R** llretptr = &args->r;
4562-
let llretptr = GEPi(bcx, llargbundle, [0, n as int]);
4563-
// R* llretloc = *llretptr; /* (args->r) */
4564-
let llretloc = Load(bcx, llretptr);
4565-
// *args->r = r;
4566-
Store(bcx, llretval, llretloc);
4567-
}
4568-
4569-
// Finish up:
4570-
build_return(bcx);
4571-
finish_fn(fcx, lltop);
4572-
4573-
ret llshimfn;
4574-
}
4575-
4576-
fn build_wrap_fn(ccx: @crate_ctxt,
4577-
tys: @c_stack_tys,
4578-
num_tps: uint,
4579-
llshimfn: ValueRef,
4580-
llwrapfn: ValueRef) {
4581-
let fcx = new_fn_ctxt(ccx, [], llwrapfn, none);
4582-
let bcx = new_top_block_ctxt(fcx, none);
4583-
let lltop = bcx.llbb;
4584-
4585-
// Allocate the struct and write the arguments into it.
4586-
let llargbundle = alloca(bcx, tys.bundle_ty);
4587-
let i = 0u, n = tys.arg_tys.len();
4588-
let implicit_args = 2u + num_tps; // ret + env
4589-
while i < n {
4590-
let llargval = llvm::LLVMGetParam(llwrapfn,
4591-
(i + implicit_args) as c_uint);
4592-
store_inbounds(bcx, llargval, llargbundle, [0, i as int]);
4593-
i += 1u;
4594-
}
4595-
let llretptr = llvm::LLVMGetParam(llwrapfn, 0 as c_uint);
4596-
store_inbounds(bcx, llretptr, llargbundle, [0, n as int]);
4597-
4598-
// Create call itself.
4599-
let call_shim_on_c_stack = ccx.upcalls.call_shim_on_c_stack;
4600-
let llshimfnptr = PointerCast(bcx, llshimfn, T_ptr(T_i8()));
4601-
let llrawargbundle = PointerCast(bcx, llargbundle, T_ptr(T_i8()));
4602-
Call(bcx, call_shim_on_c_stack, [llrawargbundle, llshimfnptr]);
4603-
build_return(bcx);
4604-
finish_fn(fcx, lltop);
4605-
}
4606-
4607-
let cc = lib::llvm::CCallConv;
4608-
alt abi {
4609-
ast::native_abi_rust_intrinsic { ret; }
4610-
ast::native_abi_cdecl { cc = lib::llvm::CCallConv; }
4611-
ast::native_abi_stdcall { cc = lib::llvm::X86StdcallCallConv; }
4612-
}
4613-
4614-
for native_item in native_mod.items {
4615-
alt native_item.node {
4616-
ast::native_item_fn(fn_decl, tps) {
4617-
let id = native_item.id;
4618-
let tys = c_stack_tys(ccx, id);
4619-
alt ccx.item_ids.find(id) {
4620-
some(llwrapfn) {
4621-
let llshimfn = build_shim_fn(ccx, native_item, tys, cc);
4622-
build_wrap_fn(ccx, tys, tps.len(), llshimfn, llwrapfn);
4623-
}
4624-
none {
4625-
ccx.sess.span_fatal(
4626-
native_item.span,
4627-
"unbound function item in trans_native_mod");
4628-
}
4629-
}
4630-
}
4631-
}
4632-
}
4633-
}
4634-
46354461
fn trans_item(ccx: @crate_ctxt, item: ast::item) {
46364462
let path = alt ccx.tcx.items.get(item.id) {
46374463
ast_map::node_item(_, p) { p }
@@ -4690,7 +4516,7 @@ fn trans_item(ccx: @crate_ctxt, item: ast::item) {
46904516
either::right(abi_) { abi_ }
46914517
either::left(msg) { ccx.sess.span_fatal(item.span, msg) }
46924518
};
4693-
trans_native_mod(ccx, native_mod, abi);
4519+
native::trans_native_mod(ccx, native_mod, abi);
46944520
}
46954521
_ {/* fall through */ }
46964522
}
@@ -4837,13 +4663,6 @@ fn fill_fn_pair(bcx: @block_ctxt, pair: ValueRef, llfn: ValueRef,
48374663
Store(bcx, llenvblobptr, env_cell);
48384664
}
48394665

4840-
fn link_name(i: @ast::native_item) -> str {
4841-
alt attr::get_meta_item_value_str_by_name(i.attrs, "link_name") {
4842-
none { ret i.ident; }
4843-
option::some(ln) { ret ln; }
4844-
}
4845-
}
4846-
48474666
fn collect_native_item(ccx: @crate_ctxt,
48484667
abi: @mutable option<ast::native_abi>,
48494668
i: @ast::native_item) {
@@ -4872,7 +4691,7 @@ fn collect_native_item(ccx: @crate_ctxt,
48724691
let fn_type = type_of_fn_from_ty(
48734692
ccx, node_type,
48744693
vec::map(tps, {|p| param_bounds(ccx, p)}));
4875-
let ri_name = "rust_intrinsic_" + link_name(i);
4694+
let ri_name = "rust_intrinsic_" + native::link_name(i);
48764695
let llnativefn = get_extern_fn(
48774696
ccx.externs, ccx.llmod, ri_name,
48784697
lib::llvm::CCallConv, fn_type);

0 commit comments

Comments
 (0)