From 19508c7d531910c309cd63e9ade2fe1be80ff71b Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Tue, 6 Mar 2012 11:33:25 +0100 Subject: [PATCH] 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. --- src/rustc/driver/driver.rs | 9 +- src/rustc/middle/inline.rs | 100 ------------------- src/rustc/middle/trans/base.rs | 164 +++++++++++++------------------ src/rustc/middle/trans/common.rs | 5 +- src/rustc/middle/trans/native.rs | 5 +- src/rustc/rustc.rc | 1 - 6 files changed, 75 insertions(+), 209 deletions(-) delete mode 100644 src/rustc/middle/inline.rs diff --git a/src/rustc/driver/driver.rs b/src/rustc/driver/driver.rs index 55dcd2daf75..eed65357449 100644 --- a/src/rustc/driver/driver.rs +++ b/src/rustc/driver/driver.rs @@ -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)); diff --git a/src/rustc/middle/inline.rs b/src/rustc/middle/inline.rs deleted file mode 100644 index 91d69168faf..00000000000 --- a/src/rustc/middle/inline.rs +++ /dev/null @@ -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; - -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) { - visit::visit_expr(e, cx, vt); - cx.visit_expr(e); - } - with *visit::default_visitor::() - }); - 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 */ - } - } - } -} diff --git a/src/rustc/middle/trans/base.rs b/src/rustc/middle/trans/base.rs index 9baae720f47..5d36d077edf 100644 --- a/src/rustc/middle/trans/base.rs +++ b/src/rustc/middle/trans/base.rs @@ -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::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, } fn collect_items(ccx: crate_ctxt, crate: @ast::crate) { - let abi = @mutable none::; + 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::; - 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::(), 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::(), 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); diff --git a/src/rustc/middle/trans/common.rs b/src/rustc/middle/trans/common.rs index 7b42ca61699..5bb2dfb885f 100644 --- a/src/rustc/middle/trans/common.rs +++ b/src/rustc/middle/trans/common.rs @@ -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, tydescs: hashmap, dicts: hashmap, + // Track mapping of external ids to local items imported for inlining + external: hashmap>, + // Cache instances of monomorphized functions monomorphized: hashmap, module_data: hashmap, lltypes: hashmap, @@ -102,7 +104,6 @@ type crate_ctxt = @{ type_short_names: hashmap, tcx: ty::ctxt, maps: maps, - inline_map: inline_map, stats: stats, upcalls: @upcall::upcalls, tydesc_type: TypeRef, diff --git a/src/rustc/middle/trans/native.rs b/src/rustc/middle/trans/native.rs index 9753ef6bd33..26621158f77 100644 --- a/src/rustc/middle/trans/native.rs +++ b/src/rustc/middle/trans/native.rs @@ -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) } \ No newline at end of file diff --git a/src/rustc/rustc.rc b/src/rustc/rustc.rc index 8102e4d8cd8..a8b398066ec 100644 --- a/src/rustc/rustc.rc +++ b/src/rustc/rustc.rc @@ -28,7 +28,6 @@ mod middle { mod shape; mod debuginfo; } - mod inline; mod ty; mod ast_map; mod resolve;