Skip to content

Commit 24ed441

Browse files
committed
Reuse monomorphized functions more aggressively
Adds a trans::type_use pass that, given a function body, detects how dependant that function is on properties of its type parameters.
1 parent 3ab9978 commit 24ed441

File tree

9 files changed

+351
-64
lines changed

9 files changed

+351
-64
lines changed

src/rustc/middle/regionck.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ type ctxt = {
2424
fn check_expr(expr: @ast::expr, cx: ctxt, visitor: visit::vt<ctxt>) {
2525
let t = ty::expr_ty(cx.tcx, expr);
2626
if ty::type_has_rptrs(t) {
27-
ty::walk_ty(cx.tcx, t) { |t|
27+
ty::walk_ty(t) { |t|
2828
alt ty::get(t).struct {
2929
ty::ty_rptr(region, _) {
3030
alt region {

src/rustc/middle/trans/base.rs

Lines changed: 90 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1784,22 +1784,98 @@ fn trans_external_path(ccx: @crate_ctxt, did: ast::def_id, t: ty::t)
17841784
ret get_extern_const(ccx.externs, ccx.llmod, name, llty);
17851785
}
17861786

1787-
fn monomorphic_fn(ccx: @crate_ctxt, fn_id: ast::def_id, substs: [ty::t],
1787+
fn normalize_for_monomorphization(tcx: ty::ctxt, ty: ty::t) -> option<ty::t> {
1788+
// FIXME[mono] could do this recursively. is that worthwhile?
1789+
alt ty::get(ty).struct {
1790+
ty::ty_box(mt) { some(ty::mk_opaque_box(tcx)) }
1791+
ty::ty_fn(fty) { some(ty::mk_fn(tcx, {proto: fty.proto,
1792+
inputs: [],
1793+
output: ty::mk_nil(tcx),
1794+
ret_style: ast::return_val,
1795+
constraints: []})) }
1796+
ty::ty_iface(_, _) { some(ty::mk_fn(tcx, {proto: ast::proto_box,
1797+
inputs: [],
1798+
output: ty::mk_nil(tcx),
1799+
ret_style: ast::return_val,
1800+
constraints: []})) }
1801+
ty::ty_ptr(_) { some(ty::mk_uint(tcx)) }
1802+
_ { none }
1803+
}
1804+
}
1805+
1806+
fn make_mono_id(ccx: @crate_ctxt, item: ast::def_id, substs: [ty::t],
1807+
vtables: option<typeck::vtable_res>,
1808+
param_uses: option<[type_use::type_uses]>) -> mono_id {
1809+
let precise_param_ids = alt vtables {
1810+
some(vts) {
1811+
let bounds = ty::lookup_item_type(ccx.tcx, item).bounds;
1812+
let i = 0u;
1813+
vec::map2(*bounds, substs, {|bounds, subst|
1814+
let v = [];
1815+
for bound in *bounds {
1816+
alt bound {
1817+
ty::bound_iface(_) {
1818+
v += [impl::vtable_id(ccx, vts[i])];
1819+
i += 1u;
1820+
}
1821+
_ {}
1822+
}
1823+
}
1824+
mono_precise(subst, if v.len() > 0u { some(v) } else { none })
1825+
})
1826+
}
1827+
none {
1828+
vec::map(substs, {|subst| mono_precise(subst, none)})
1829+
}
1830+
};
1831+
let param_ids = alt param_uses {
1832+
some(uses) {
1833+
vec::map2(precise_param_ids, uses, {|id, uses|
1834+
alt check id {
1835+
mono_precise(_, some(_)) { id }
1836+
mono_precise(subst, none) {
1837+
if uses == 0u { mono_any }
1838+
else if uses == type_use::use_repr &&
1839+
!ty::type_needs_drop(ccx.tcx, subst) {
1840+
let llty = type_of(ccx, subst);
1841+
let size = shape::llsize_of_real(ccx, llty);
1842+
let align = shape::llalign_of_real(ccx, llty);
1843+
// Special value for nil to prevent problems with undef
1844+
// return pointers.
1845+
if size == 1u && ty::type_is_nil(subst) {
1846+
mono_repr(0u, 0u)
1847+
} else { mono_repr(size, align) }
1848+
} else { id }
1849+
}
1850+
}
1851+
})
1852+
}
1853+
none { precise_param_ids }
1854+
};
1855+
@{def: item, params: param_ids}
1856+
}
1857+
1858+
fn monomorphic_fn(ccx: @crate_ctxt, fn_id: ast::def_id, real_substs: [ty::t],
17881859
vtables: option<typeck::vtable_res>)
17891860
-> {val: ValueRef, must_cast: bool, intrinsic: bool} {
17901861
let mut must_cast = false;
1791-
let substs = vec::map(substs, {|t|
1792-
alt ty::get(t).struct {
1793-
ty::ty_box(mt) { must_cast = true; ty::mk_opaque_box(ccx.tcx) }
1794-
_ { t }
1862+
let substs = vec::map(real_substs, {|t|
1863+
alt normalize_for_monomorphization(ccx.tcx, t) {
1864+
some(t) { must_cast = true; t }
1865+
none { t }
17951866
}
17961867
});
1797-
let hash_id = @{def: fn_id, substs: substs, vtables: alt vtables {
1798-
some(os) { some_vts(vec::map(*os, impl::vtable_id)) }
1799-
none { no_vts }
1800-
}};
1868+
1869+
let param_uses = type_use::type_uses_for(ccx, fn_id, substs.len());
1870+
let hash_id = make_mono_id(ccx, fn_id, substs, vtables, some(param_uses));
1871+
if vec::any(hash_id.params,
1872+
{|p| alt p { mono_precise(_, _) { false } _ { true } } }) {
1873+
must_cast = true;
1874+
}
18011875
alt ccx.monomorphized.find(hash_id) {
1802-
some(val) { ret {val: val, must_cast: must_cast, intrinsic: false}; }
1876+
some(val) {
1877+
ret {val: val, must_cast: must_cast, intrinsic: false};
1878+
}
18031879
none {}
18041880
}
18051881

@@ -1867,12 +1943,12 @@ fn monomorphic_fn(ccx: @crate_ctxt, fn_id: ast::def_id, substs: [ty::t],
18671943
impl_self(selfty), psubsts, fn_id.node, none);
18681944
}
18691945
ast_map::node_ctor(i) {
1870-
alt check ccx.tcx.items.get(i.id) {
1871-
ast_map::node_item(@{node: ast::item_res(decl, _, _, _, _), _}, _) {
1946+
alt check i.node {
1947+
ast::item_res(decl, _, _, _, _) {
18721948
set_inline_hint(lldecl);
18731949
trans_res_ctor(ccx, pt, decl, fn_id.node, psubsts, lldecl);
18741950
}
1875-
ast_map::node_item(@{node: ast::item_class(_, _, ctor), _}, _) {
1951+
ast::item_class(_, _, ctor) {
18761952
ccx.sess.unimpl("monomorphic class constructor");
18771953
}
18781954
}
@@ -4606,6 +4682,7 @@ fn trans_crate(sess: session::session, crate: @ast::crate, tcx: ty::ctxt,
46064682
tydescs: ty::new_ty_hash(),
46074683
external: util::common::new_def_hash(),
46084684
monomorphized: map::hashmap(hash_mono_id, {|a, b| a == b}),
4685+
type_use_cache: util::common::new_def_hash(),
46094686
vtables: map::hashmap(hash_mono_id, {|a, b| a == b}),
46104687
module_data: str_hash::<ValueRef>(),
46114688
lltypes: ty::new_ty_hash(),

src/rustc/middle/trans/common.rs

Lines changed: 21 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -90,6 +90,8 @@ type crate_ctxt = {
9090
external: hashmap<ast::def_id, option<ast::node_id>>,
9191
// Cache instances of monomorphized functions
9292
monomorphized: hashmap<mono_id, ValueRef>,
93+
// Cache computed type parameter uses (see type_use.rs)
94+
type_use_cache: hashmap<ast::def_id, [type_use::type_uses]>,
9395
// Cache generated vtables
9496
vtables: hashmap<mono_id, ValueRef>,
9597
module_data: hashmap<str, ValueRef>,
@@ -797,15 +799,27 @@ fn C_shape(ccx: @crate_ctxt, bytes: [u8]) -> ValueRef {
797799
ret llvm::LLVMConstPointerCast(llglobal, T_ptr(T_i8()));
798800
}
799801

800-
// Used to identify cached monomorphized functions
801-
enum mono_vtables { some_vts([mono_id]), no_vts }
802-
type mono_id = @{def: ast::def_id, substs: [ty::t], vtables: mono_vtables};
802+
// Used to identify cached monomorphized functions and vtables
803+
enum mono_param_id {
804+
mono_precise(ty::t, option<[mono_id]>),
805+
mono_any,
806+
mono_repr(uint /* size */, uint /* align */),
807+
}
808+
type mono_id = @{def: ast::def_id, params: [mono_param_id]};
803809
fn hash_mono_id(&&mi: mono_id) -> uint {
804810
let h = syntax::ast_util::hash_def_id(mi.def);
805-
for ty in mi.substs { h = (h << 2u) + ty::type_id(ty); }
806-
alt mi.vtables {
807-
some_vts(ds) { for d in ds { h = (h << 2u) + hash_mono_id(d); } }
808-
no_vts {}
811+
for param in mi.params {
812+
h = h * alt param {
813+
mono_precise(ty, vts) {
814+
let h = ty::type_id(ty);
815+
option::may(vts) {|vts|
816+
for vt in vts { h += hash_mono_id(vt); }
817+
}
818+
h
819+
}
820+
mono_any { 1u }
821+
mono_repr(sz, align) { sz * (align + 2u) }
822+
}
809823
}
810824
h
811825
}

src/rustc/middle/trans/impl.rs

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -187,22 +187,23 @@ fn resolve_vtable_in_fn_ctxt(fcx: fn_ctxt, vt: typeck::vtable_origin)
187187
}
188188
}
189189

190-
fn vtable_id(origin: typeck::vtable_origin) -> mono_id {
190+
fn vtable_id(ccx: @crate_ctxt, origin: typeck::vtable_origin) -> mono_id {
191191
alt check origin {
192192
typeck::vtable_static(impl_id, substs, sub_vtables) {
193-
@{def: impl_id, substs: substs,
194-
vtables: if (*sub_vtables).len() == 0u { no_vts }
195-
else { some_vts(vec::map(*sub_vtables, vtable_id)) } }
193+
make_mono_id(ccx, impl_id, substs,
194+
if (*sub_vtables).len() == 0u { none }
195+
else { some(sub_vtables) }, none)
196196
}
197197
typeck::vtable_iface(iface_id, substs) {
198-
@{def: iface_id, substs: substs, vtables: no_vts}
198+
@{def: iface_id,
199+
params: vec::map(substs, {|t| mono_precise(t, none)})}
199200
}
200201
}
201202
}
202203

203204
fn get_vtable(ccx: @crate_ctxt, origin: typeck::vtable_origin)
204205
-> ValueRef {
205-
let hash_id = vtable_id(origin);
206+
let hash_id = vtable_id(ccx, origin);
206207
alt ccx.vtables.find(hash_id) {
207208
some(val) { val }
208209
none {

0 commit comments

Comments
 (0)