escape analysis: fixed some bugs regarding imprecise local

escape-analysis
pca006132 2022-04-08 20:16:48 +08:00
parent fb79b47b38
commit ea5a8c95dc
2 changed files with 36 additions and 18 deletions

View File

@ -37,7 +37,7 @@ pub struct BasicBlockId(usize);
pub enum LifetimeIR { pub enum LifetimeIR {
VarAssign { var: StrRef, lifetime: LifetimeId }, VarAssign { var: StrRef, lifetime: LifetimeId },
VarAccess { var: StrRef }, VarAccess { var: StrRef },
FieldAssign { obj: LifetimeId, field: StrRef, new: LifetimeId }, FieldAssign { obj: LifetimeId, field: StrRef, new: LifetimeId, is_init: bool },
FieldAccess { obj: LifetimeId, field: StrRef }, FieldAccess { obj: LifetimeId, field: StrRef },
CreateLifetime { kind: LifetimeKind }, CreateLifetime { kind: LifetimeKind },
PassedToFunc { param_lifetimes: Vec<LifetimeId> }, PassedToFunc { param_lifetimes: Vec<LifetimeId> },
@ -123,7 +123,7 @@ impl LifetimeIRBuilder {
LifetimeIR::Branch { targets } => { LifetimeIR::Branch { targets } => {
destination_mapping.insert(i, targets); destination_mapping.insert(i, targets);
} }
_ => () _ => (),
} }
} }
} }
@ -339,14 +339,23 @@ impl<'a> LifetimeAnalyzer<'a> {
self.lifetime_stores.remove(rhs_id); self.lifetime_stores.remove(rhs_id);
} }
fn get_field_lifetime(&self, obj: LifetimeId, field: StrRef) -> LifetimeId { fn get_field_lifetime(&mut self, obj: LifetimeId, field: StrRef) -> LifetimeId {
use LifetimeKind::*; use LifetimeKind::*;
let id = *self.lifetime_to_id.get(&obj).unwrap(); let id = *self.lifetime_to_id.get(&obj).unwrap();
let store = &self.lifetime_stores.get(id).unwrap(); let store = self.lifetime_stores.get(id).unwrap();
if let Some(lifetime) = store.fields.get(&field) { if matches!(store.kind, PreciseLocal | ImpreciseLocal) {
*lifetime if let Some(&lifetime) = store.fields.get(&field) {
} else if matches!(store.kind, PreciseLocal | ImpreciseLocal) { let field_lifetime_kind = self.get_lifetime_kind(lifetime);
LifetimeId(0) if field_lifetime_kind == PreciseLocal
&& (store.kind == ImpreciseLocal || field == "$elem".into())
{
let id = *self.lifetime_to_id.get(&lifetime).unwrap();
self.lifetime_stores.get_mut(id).unwrap().to_mut().kind = ImpreciseLocal;
}
lifetime
} else {
LifetimeId(0)
}
} else { } else {
obj obj
} }
@ -357,6 +366,7 @@ impl<'a> LifetimeAnalyzer<'a> {
obj: LifetimeId, obj: LifetimeId,
field: StrRef, field: StrRef,
field_lifetime: LifetimeId, field_lifetime: LifetimeId,
is_init: bool,
) -> Result<(), String> { ) -> Result<(), String> {
use LifetimeKind::*; use LifetimeKind::*;
let obj_id = *self.lifetime_to_id.get(&obj).unwrap(); let obj_id = *self.lifetime_to_id.get(&obj).unwrap();
@ -377,15 +387,15 @@ impl<'a> LifetimeAnalyzer<'a> {
} }
PreciseLocal | ImpreciseLocal => { PreciseLocal | ImpreciseLocal => {
// weak update // weak update
let old_lifetime = obj_store let old_lifetime = obj_store.to_mut().fields.get(&field).copied();
.to_mut()
.fields
.get(&field)
.copied();
if let Some(old_lifetime) = old_lifetime { if let Some(old_lifetime) = old_lifetime {
self.unify(old_lifetime, field_lifetime); self.unify(old_lifetime, field_lifetime);
} else { } else {
obj_store.to_mut().fields.insert(field, field_lifetime); obj_store.to_mut().fields.insert(field, field_lifetime);
if !is_init {
// unify with unknown lifetime
self.unify(LifetimeId(0), field_lifetime);
}
} }
} }
_ => (), _ => (),
@ -455,8 +465,8 @@ impl<'a> LifetimeAnalyzer<'a> {
self.add_lifetime(id, LifetimeKind::Static) self.add_lifetime(id, LifetimeKind::Static)
} }
} }
FieldAssign { obj, field, new } => { FieldAssign { obj, field, new, is_init } => {
self.set_field_lifetime(*obj, *field, *new) self.set_field_lifetime(*obj, *field, *new, *is_init)
.map_err(|e| format!("{} in {}", e, loc))?; .map_err(|e| format!("{} in {}", e, loc))?;
} }
FieldAccess { obj, field } => { FieldAccess { obj, field } => {
@ -490,7 +500,7 @@ impl<'a> LifetimeAnalyzer<'a> {
} }
return Ok(None); return Ok(None);
} }
Branch { targets } => return Ok(Some(targets)) Branch { targets } => return Ok(Some(targets)),
} }
} }
Ok(None) Ok(None)

View File

@ -153,6 +153,7 @@ impl<'a> EscapeAnalyzer<'a> {
obj: list_lifetime, obj: list_lifetime,
field: "$elem".into(), field: "$elem".into(),
new: elem_lifetime, new: elem_lifetime,
is_init: true,
}, },
loc, loc,
); );
@ -165,6 +166,7 @@ impl<'a> EscapeAnalyzer<'a> {
obj: list_lifetime, obj: list_lifetime,
field: "$elem".into(), field: "$elem".into(),
new: elem_lifetime, new: elem_lifetime,
is_init: true,
}, },
loc, loc,
); );
@ -183,6 +185,7 @@ impl<'a> EscapeAnalyzer<'a> {
obj: tuple_lifetime, obj: tuple_lifetime,
field: format!("$elem{}", i).into(), field: format!("$elem{}", i).into(),
new: lifetime, new: lifetime,
is_init: true,
}, },
loc, loc,
); );
@ -208,6 +211,7 @@ impl<'a> EscapeAnalyzer<'a> {
obj: slice_lifetime, obj: slice_lifetime,
field: "$elem".into(), field: "$elem".into(),
new: slice_elem, new: slice_elem,
is_init: true
}, },
loc, loc,
); );
@ -249,7 +253,9 @@ impl<'a> EscapeAnalyzer<'a> {
} }
match &func.node { match &func.node {
ExprKind::Name { id, .. } => { ExprKind::Name { id, .. } => {
self.builder.append_ir(PassedToFunc { param_lifetimes: lifetimes }, loc); if !lifetimes.is_empty() {
self.builder.append_ir(PassedToFunc { param_lifetimes: lifetimes }, loc);
}
if need_alloca { if need_alloca {
let id = self let id = self
.resolver .resolver
@ -342,6 +348,7 @@ impl<'a> EscapeAnalyzer<'a> {
obj: list_lifetime, obj: list_lifetime,
field: "$elem".into(), field: "$elem".into(),
new: elem_lifetime, new: elem_lifetime,
is_init: true
}, },
elt.location, elt.location,
); );
@ -365,7 +372,7 @@ impl<'a> EscapeAnalyzer<'a> {
let value_lifetime = self.handle_expr(value)?.unwrap(); let value_lifetime = self.handle_expr(value)?.unwrap();
if let Some(field_lifetime) = rhs_lifetime { if let Some(field_lifetime) = rhs_lifetime {
self.builder.append_ir( self.builder.append_ir(
FieldAssign { obj: value_lifetime, field: *attr, new: field_lifetime }, FieldAssign { obj: value_lifetime, field: *attr, new: field_lifetime, is_init: false },
lhs.location, lhs.location,
); );
} }
@ -396,6 +403,7 @@ impl<'a> EscapeAnalyzer<'a> {
obj: value_lifetime, obj: value_lifetime,
field: "$elem".into(), field: "$elem".into(),
new: elem_lifetime, new: elem_lifetime,
is_init: false
}, },
lhs.location, lhs.location,
); );