Make trans pass responsible for pulling in inlined functions

This makes the logic for finding the inlinable items much easier --
they are simply pulled in lazily when encountered.
This commit is contained in:
Marijn Haverbeke 2012-03-06 11:33:25 +01:00
parent 9b88219723
commit 19508c7d53
6 changed files with 75 additions and 209 deletions

View File

@ -6,7 +6,7 @@ import syntax::parse::{parser};
import syntax::{ast, codemap};
import front::attr;
import middle::{trans, resolve, freevars, kind, ty, typeck, fn_usage,
last_use, lint, inline};
last_use, lint};
import syntax::print::{pp, pprust};
import util::{ppaux, filesearch};
import back::link;
@ -177,16 +177,11 @@ fn compile_upto(sess: session, cfg: ast::crate_cfg,
last_uses: last_uses, impl_map: impl_map,
method_map: method_map, dict_map: dict_map};
let ienbld = sess.opts.inline;
let inline_map =
time(time_passes, "inline",
bind inline::instantiate_inlines(ienbld, ty_cx, maps, crate));
let (llmod, link_meta) =
time(time_passes, "translation",
bind trans::base::trans_crate(
sess, crate, ty_cx, outputs.obj_filename,
exp_map, maps, inline_map));
exp_map, maps));
time(time_passes, "LLVM passes",
bind link::write::run_passes(sess, llmod, outputs.obj_filename));

View File

@ -1,100 +0,0 @@
import std::map::hashmap;
import syntax::ast;
import syntax::ast_util;
import syntax::ast_util::inlined_item_methods;
import syntax::visit;
import middle::typeck::method_map;
import middle::trans::common::maps;
import metadata::csearch;
export inline_map;
export instantiate_inlines;
type inline_map = hashmap<ast::def_id, ast::inlined_item>;
enum ctxt = {
tcx: ty::ctxt,
maps: maps,
inline_map: inline_map,
mut to_process: [ast::inlined_item]
};
fn instantiate_inlines(enabled: bool,
tcx: ty::ctxt,
maps: maps,
crate: @ast::crate) -> inline_map {
let vt = visit::mk_vt(@{
visit_expr: fn@(e: @ast::expr, cx: ctxt, vt: visit::vt<ctxt>) {
visit::visit_expr(e, cx, vt);
cx.visit_expr(e);
}
with *visit::default_visitor::<ctxt>()
});
let inline_map = ast_util::new_def_id_hash();
let cx = ctxt({tcx: tcx, maps: maps,
inline_map: inline_map, mutable to_process: []});
if enabled { visit::visit_crate(*crate, cx, vt); }
while !vec::is_empty(cx.to_process) {
let to_process = [];
to_process <-> cx.to_process;
#debug["Recursively looking at inlined items"];
vec::iter(to_process) {|ii|
ii.accept(cx, vt);
}
}
ret inline_map;
}
impl methods for ctxt {
fn visit_expr(e: @ast::expr) {
// Look for fn items or methods that are referenced which
// ought to be inlined.
alt e.node {
ast::expr_path(_) {
alt self.tcx.def_map.get(e.id) {
ast::def_fn(did, _) {
self.maybe_enqueue_fn(did);
}
_ { /* not a fn item, fallthrough */ }
}
}
ast::expr_field(_, _, _) {
alt self.maps.method_map.find(e.id) {
some(origin) {
self.maybe_enqueue_impl_method(origin);
}
_ { /* not an impl method, fallthrough */ }
}
}
_ { /* fallthrough */ }
}
}
fn maybe_enqueue_fn(did: ast::def_id) {
if did.crate == ast::local_crate { ret; }
if self.inline_map.contains_key(did) { ret; }
alt csearch::maybe_get_item_ast(self.tcx, self.maps, did) {
none {
/* no AST attached, do not inline */
#debug["No AST attached to def %s",
ty::item_path_str(self.tcx, did)];
}
some(ii) { /* Found an AST, add to table: */
#debug["Inlining def %s", ty::item_path_str(self.tcx, did)];
self.to_process += [ii];
self.inline_map.insert(did, ii);
}
}
}
fn maybe_enqueue_impl_method(method_origin: typeck::method_origin) {
alt method_origin {
typeck::method_static(did) { self.maybe_enqueue_fn(did); }
typeck::method_param(_, _, _, _) | typeck::method_iface(_, _) {
/* fallthrough */
}
}
}
}

View File

@ -20,7 +20,6 @@ import std::map::{new_int_hash, new_str_hash};
import driver::session;
import session::session;
import front::attr;
import middle::inline::inline_map;
import back::{link, abi, upcall};
import syntax::{ast, ast_util, codemap};
import ast_util::inlined_item_methods;
@ -651,20 +650,11 @@ fn set_inline_hint(f: ValueRef) {
0u as c_uint);
}
fn set_inline_hint_if_appr(ccx: crate_ctxt,
attrs: [ast::attribute],
id: ast::node_id) {
fn set_inline_hint_if_appr(attrs: [ast::attribute],
llfn: ValueRef) {
alt attr::find_inline_attr(attrs) {
attr::ia_hint {
#debug["Setting inline mode for %s to 'hint'",
ty::item_path_str(ccx.tcx, ast_util::local_def(id))];
set_inline_hint(ccx.item_ids.get(id))
}
attr::ia_always {
#debug["Setting inline mode for %s to 'always'",
ty::item_path_str(ccx.tcx, ast_util::local_def(id))];
set_always_inline(ccx.item_ids.get(id))
}
attr::ia_hint { set_inline_hint(llfn); }
attr::ia_always { set_always_inline(llfn); }
attr::ia_none { /* fallthrough */ }
}
}
@ -2152,6 +2142,40 @@ fn monomorphic_fn(ccx: crate_ctxt, fn_id: ast::def_id, substs: [ty::t],
some({llfn: lldecl, fty: mono_ty})
}
// FIXME[mono] Only actually translate things that are not generic
fn maybe_instantiate_inline(ccx: crate_ctxt, fn_id: ast::def_id)
-> ast::def_id {
alt ccx.external.find(fn_id) {
some(some(node_id)) { local_def(node_id) } // Already inline
some(none) { fn_id } // Not inlinable
none { // Not seen yet
alt csearch::maybe_get_item_ast(ccx.tcx, ccx.maps, fn_id) {
none { ccx.external.insert(fn_id, none); fn_id }
some(ast::ii_item(item)) {
ccx.external.insert(fn_id, some(item.id));
collect_item(ccx, @mutable none, item);
trans_item(ccx, *item);
local_def(item.id)
}
some(ast::ii_method(impl_did, mth)) {
ccx.external.insert(fn_id, some(mth.id));
compute_ii_method_info(ccx, impl_did, mth) {|ty, bounds, path|
let mth_ty = ty::node_id_to_type(ccx.tcx, mth.id);
let llfn = register_fn_full(ccx, mth.span, path,
"impl_method", bounds,
mth.id, mth_ty);
set_inline_hint_if_appr(mth.attrs, llfn);
trans_fn(ccx, path, mth.decl, mth.body,
llfn, impl_self(ty), bounds,
none, mth.id, none);
}
local_def(mth.id)
}
}
}
}
}
fn lval_static_fn(bcx: block, fn_id: ast::def_id, id: ast::node_id,
substs: option<([ty::t], typeck::dict_res)>)
-> lval_maybe_callee {
@ -2162,22 +2186,9 @@ fn lval_static_fn(bcx: block, fn_id: ast::def_id, id: ast::node_id,
// Check whether this fn has an inlined copy and, if so, redirect fn_id to
// the local id of the inlined copy.
let fn_id = {
if fn_id.crate == ast::local_crate {
fn_id
} else {
alt ccx.inline_map.find(fn_id) {
none { fn_id }
some(ii) {
#debug["Found inlined version of %s with id %d",
ty::item_path_str(tcx, fn_id),
ii.id()];
{crate: ast::local_crate,
node: ii.id()}
}
}
}
};
let fn_id = if fn_id.crate != ast::local_crate && ccx.sess.opts.inline {
maybe_instantiate_inline(ccx, fn_id)
} else { fn_id };
// The awkwardness below mostly stems from the fact that we're mixing
// monomorphized and non-monomorphized functions at the moment. If
@ -4478,35 +4489,17 @@ fn compute_ii_method_info(ccx: crate_ctxt,
f(impl_ty, m_bounds, m_path);
}
fn trans_inlined_items(ccx: crate_ctxt, inline_map: inline_map) {
inline_map.values {|ii|
alt ii {
ast::ii_item(item) {
trans_item(ccx, *item)
}
ast::ii_method(impl_did, m) {
compute_ii_method_info(ccx, impl_did, m) {
|impl_ty, m_bounds, m_path|
let llfndecl = ccx.item_ids.get(m.id);
trans_fn(ccx, m_path, m.decl, m.body,
llfndecl, impl_self(impl_ty), m_bounds,
none, m.id, none);
}
}
}
}
}
fn get_pair_fn_ty(llpairty: TypeRef) -> TypeRef {
// Bit of a kludge: pick the fn typeref out of the pair.
ret struct_elt(llpairty, 0u);
}
fn register_fn(ccx: crate_ctxt, sp: span, path: path, flav: str,
ty_params: [ast::ty_param], node_id: ast::node_id) {
ty_params: [ast::ty_param], node_id: ast::node_id)
-> ValueRef {
let t = ty::node_id_to_type(ccx.tcx, node_id);
let bnds = param_bounds(ccx, ty_params);
register_fn_full(ccx, sp, path, flav, bnds, node_id, t);
register_fn_full(ccx, sp, path, flav, bnds, node_id, t)
}
fn param_bounds(ccx: crate_ctxt, tps: [ast::ty_param]) -> [ty::param_bounds] {
@ -4515,15 +4508,15 @@ fn param_bounds(ccx: crate_ctxt, tps: [ast::ty_param]) -> [ty::param_bounds] {
fn register_fn_full(ccx: crate_ctxt, sp: span, path: path, flav: str,
bnds: [ty::param_bounds], node_id: ast::node_id,
node_type: ty::t) {
node_type: ty::t) -> ValueRef {
let llfty = type_of_fn_from_ty(ccx, node_type, bnds);
register_fn_fuller(ccx, sp, path, flav, node_id, node_type,
lib::llvm::CCallConv, llfty);
lib::llvm::CCallConv, llfty)
}
fn register_fn_fuller(ccx: crate_ctxt, sp: span, path: path, _flav: str,
node_id: ast::node_id, node_type: ty::t,
cc: lib::llvm::CallConv, llfty: TypeRef) {
cc: lib::llvm::CallConv, llfty: TypeRef) -> ValueRef {
let ps: str = mangle_exported_name(ccx, path, node_type);
let llfn: ValueRef = decl_fn(ccx.llmod, ps, cc, llfty);
ccx.item_ids.insert(node_id, llfn);
@ -4534,6 +4527,7 @@ fn register_fn_fuller(ccx: crate_ctxt, sp: span, path: path, _flav: str,
let is_main = is_main_name(path) && !ccx.sess.building_library;
if is_main { create_main_wrapper(ccx, sp, llfn, node_type); }
llfn
}
// Create a _rust_main(args: [str]) function which will be called from the
@ -4713,39 +4707,39 @@ fn collect_item(ccx: crate_ctxt, abi: @mutable option<ast::native_abi>,
}
}
ast::item_fn(decl, tps, _) {
if decl.purity != ast::crust_fn {
register_fn(ccx, i.span, my_path, "fn", tps,
i.id);
let llfn = if decl.purity != ast::crust_fn {
register_fn(ccx, i.span, my_path, "fn", tps, i.id)
} else {
native::register_crust_fn(ccx, i.span, my_path, i.id);
}
native::register_crust_fn(ccx, i.span, my_path, i.id)
};
set_inline_hint_if_appr(ccx, i.attrs, i.id);
set_inline_hint_if_appr(i.attrs, llfn);
}
ast::item_impl(tps, _, _, methods) {
let path = my_path + [path_name(int::str(i.id))];
for m in methods {
register_fn(ccx, i.span,
path + [path_name(m.ident)],
"impl_method", tps + m.tps, m.id);
set_inline_hint_if_appr(ccx, m.attrs, m.id);
let llm = register_fn(ccx, i.span,
path + [path_name(m.ident)],
"impl_method", tps + m.tps, m.id);
set_inline_hint_if_appr(m.attrs, llm);
}
}
ast::item_res(_, tps, _, dtor_id, ctor_id) {
register_fn(ccx, i.span, my_path, "res_ctor", tps, ctor_id);
let llctor = register_fn(ccx, i.span, my_path, "res_ctor", tps,
ctor_id);
// Note that the destructor is associated with the item's id, not
// the dtor_id. This is a bit counter-intuitive, but simplifies
// ty_res, which would have to carry around two def_ids otherwise
// -- one to identify the type, and one to find the dtor symbol.
let t = ty::node_id_to_type(ccx.tcx, dtor_id);
register_fn_full(ccx, i.span, my_path + [path_name("dtor")],
"res_dtor", param_bounds(ccx, tps), i.id, t);
let lldtor = register_fn_full(ccx, i.span, my_path +
[path_name("dtor")], "res_dtor",
param_bounds(ccx, tps), i.id, t);
// give hints that resource ctors/dtors ought to be inlined
set_inline_hint(ccx.item_ids.get(ctor_id));
set_inline_hint(ccx.item_ids.get(i.id));
set_inline_hint(llctor);
set_inline_hint(lldtor);
}
ast::item_enum(variants, tps) {
for variant in variants {
@ -4767,7 +4761,7 @@ fn collect_item(ccx: crate_ctxt, abi: @mutable option<ast::native_abi>,
}
fn collect_items(ccx: crate_ctxt, crate: @ast::crate) {
let abi = @mutable none::<ast::native_abi>;
let abi = @mutable none;
visit::visit_crate(*crate, (), visit::mk_simple_visitor(@{
visit_native_item: bind collect_native_item(ccx, abi, _),
visit_item: bind collect_item(ccx, abi, _)
@ -4775,27 +4769,6 @@ fn collect_items(ccx: crate_ctxt, crate: @ast::crate) {
}));
}
fn collect_inlined_items(ccx: crate_ctxt, inline_map: inline::inline_map) {
let abi = @mutable none::<ast::native_abi>;
inline_map.values {|ii|
alt ii {
ast::ii_item(item) {
collect_item(ccx, abi, item);
}
ast::ii_method(impl_did, m) {
compute_ii_method_info(ccx, impl_did, m) {
|_impl_ty, m_bounds, m_path|
let mthd_ty = ty::node_id_to_type(ccx.tcx, m.id);
register_fn_full(ccx, m.span, m_path, "impl_method",
m_bounds, m.id, mthd_ty);
set_inline_hint_if_appr(ccx, m.attrs, m.id);
}
}
}
}
}
// The constant translation pass.
fn trans_constant(ccx: crate_ctxt, it: @ast::item) {
alt it.node {
@ -4995,8 +4968,7 @@ fn write_abi_version(ccx: crate_ctxt) {
}
fn trans_crate(sess: session::session, crate: @ast::crate, tcx: ty::ctxt,
output: str, emap: resolve::exp_map, maps: maps,
inline_map: inline::inline_map)
output: str, emap: resolve::exp_map, maps: maps)
-> (ModuleRef, link::link_meta) {
let sha = std::sha1::mk_sha1();
let link_meta = link::build_link_meta(sess, *crate, output, sha);
@ -5063,6 +5035,7 @@ fn trans_crate(sess: session::session, crate: @ast::crate, tcx: ty::ctxt,
consts: new_int_hash::<ValueRef>(),
tydescs: ty::new_ty_hash(),
dicts: map::mk_hashmap(hash_dict_id, {|a, b| a == b}),
external: util::common::new_def_hash(),
monomorphized: map::mk_hashmap(hash_mono_id, {|a, b| a == b}),
module_data: new_str_hash::<ValueRef>(),
lltypes: ty::new_ty_hash(),
@ -5072,7 +5045,6 @@ fn trans_crate(sess: session::session, crate: @ast::crate, tcx: ty::ctxt,
type_short_names: ty::new_ty_hash(),
tcx: tcx,
maps: maps,
inline_map: inline_map,
stats:
{mutable n_static_tydescs: 0u,
mutable n_derived_tydescs: 0u,
@ -5094,10 +5066,8 @@ fn trans_crate(sess: session::session, crate: @ast::crate, tcx: ty::ctxt,
dbg_cx: dbg_cx,
mutable do_not_commit_warning_issued: false};
collect_items(ccx, crate);
collect_inlined_items(ccx, inline_map);
trans_constants(ccx, crate);
trans_mod(ccx, crate.node.module);
trans_inlined_items(ccx, inline_map);
fill_crate_map(ccx, crate_map);
emit_tydescs(ccx);
gen_shape_tables(ccx);

View File

@ -19,7 +19,6 @@ import lib::llvm::{ModuleRef, ValueRef, TypeRef, BasicBlockRef, BuilderRef};
import lib::llvm::{True, False, Bool};
import metadata::csearch;
import ast_map::path;
import middle::inline::inline_map;
type namegen = fn@(str) -> str;
fn new_namegen() -> namegen {
@ -93,6 +92,9 @@ type crate_ctxt = @{
consts: hashmap<ast::node_id, ValueRef>,
tydescs: hashmap<ty::t, @tydesc_info>,
dicts: hashmap<dict_id, ValueRef>,
// Track mapping of external ids to local items imported for inlining
external: hashmap<ast::def_id, option<ast::node_id>>,
// Cache instances of monomorphized functions
monomorphized: hashmap<mono_id, {llfn: ValueRef, fty: ty::t}>,
module_data: hashmap<str, ValueRef>,
lltypes: hashmap<ty::t, TypeRef>,
@ -102,7 +104,6 @@ type crate_ctxt = @{
type_short_names: hashmap<ty::t, str>,
tcx: ty::ctxt,
maps: maps,
inline_map: inline_map,
stats: stats,
upcalls: @upcall::upcalls,
tydesc_type: TypeRef,

View File

@ -351,10 +351,11 @@ fn trans_crust_fn(ccx: crate_ctxt, path: ast_map::path, decl: ast::fn_decl,
}
fn register_crust_fn(ccx: crate_ctxt, sp: span,
path: ast_map::path, node_id: ast::node_id) {
path: ast_map::path, node_id: ast::node_id)
-> ValueRef {
let t = ty::node_id_to_type(ccx.tcx, node_id);
let (llargtys, llretty, _) = c_arg_and_ret_lltys(ccx, node_id);
let llfty = T_fn(llargtys, llretty);
register_fn_fuller(ccx, sp, path, "crust fn", node_id,
t, lib::llvm::CCallConv, llfty);
t, lib::llvm::CCallConv, llfty)
}

View File

@ -28,7 +28,6 @@ mod middle {
mod shape;
mod debuginfo;
}
mod inline;
mod ty;
mod ast_map;
mod resolve;