Tighten up the parser's verification of value aliases.

This prevents uses of undefined values from passsing through
unnoticed, and ensures that all aliases are ultimately resolved,
regardless of where they are defined.
This commit is contained in:
Dan Gohman
2018-03-28 13:28:59 -07:00
parent e5ec7242cc
commit 592db1de7a
2 changed files with 112 additions and 7 deletions

View File

@@ -121,8 +121,9 @@ impl DataFlowGraph {
/// Resolve value aliases.
///
/// Find the original SSA value that `value` aliases.
fn resolve_aliases(values: &PrimaryMap<Value, ValueData>, value: Value) -> Value {
/// Find the original SSA value that `value` aliases, or None if an
/// alias cycle is detected.
fn maybe_resolve_aliases(values: &PrimaryMap<Value, ValueData>, value: Value) -> Option<Value> {
let mut v = value;
// Note that values may be empty here.
@@ -130,10 +131,22 @@ fn resolve_aliases(values: &PrimaryMap<Value, ValueData>, value: Value) -> Value
if let ValueData::Alias { original, .. } = values[v] {
v = original;
} else {
return v;
return Some(v);
}
}
panic!("Value alias loop detected for {}", value);
None
}
/// Resolve value aliases.
///
/// Find the original SSA value that `value` aliases.
fn resolve_aliases(values: &PrimaryMap<Value, ValueData>, value: Value) -> Value {
if let Some(v) = maybe_resolve_aliases(values, value) {
v
} else {
panic!("Value alias loop detected for {}", value);
}
}
/// Handling values.
@@ -238,6 +251,7 @@ impl DataFlowGraph {
self.value_type(dest),
ty
);
debug_assert_ne!(ty, types::VOID);
self.values[dest] = ValueData::Alias { ty, original };
}
@@ -282,6 +296,7 @@ impl DataFlowGraph {
self.value_type(dest),
ty
);
debug_assert_ne!(ty, types::VOID);
self.values[dest] = ValueData::Alias { ty, original };
}
@@ -865,8 +880,9 @@ impl DataFlowGraph {
/// to create invalid values for index padding which may be reassigned later.
#[cold]
fn set_value_type_for_parser(&mut self, v: Value, t: Type) {
assert!(
self.value_type(v) == types::VOID,
assert_eq!(
self.value_type(v),
types::VOID,
"this function is only for assigning types to previously invalid values"
);
match self.values[v] {
@@ -926,12 +942,38 @@ impl DataFlowGraph {
/// aliases with specific values.
#[cold]
pub fn make_value_alias_for_parser(&mut self, src: Value, dest: Value) {
let ty = self.value_type(src);
assert_ne!(src, Value::reserved_value());
assert_ne!(dest, Value::reserved_value());
let ty = if self.values.is_valid(src) {
self.value_type(src)
} else {
// As a special case, if we can't resolve the aliasee yet, use VOID
// temporarily. It will be resolved later in parsing.
types::VOID
};
let data = ValueData::Alias { ty, original: src };
self.values[dest] = data;
}
/// Compute the type of an alias. This is only for use in the parser.
/// Returns false if an alias cycle was encountered.
#[cold]
pub fn set_alias_type_for_parser(&mut self, v: Value) -> bool {
if let Some(resolved) = maybe_resolve_aliases(&self.values, v) {
let old_ty = self.value_type(v);
let new_ty = self.value_type(resolved);
if old_ty == types::VOID {
self.set_value_type_for_parser(v, new_ty);
} else {
assert_eq!(old_ty, new_ty);
}
true
} else {
false
}
}
/// Create an invalid value, to pad the index space. This is only for use by
/// the parser to pad out the value index space.
#[cold]
@@ -942,6 +984,20 @@ impl DataFlowGraph {
};
self.make_value(data);
}
/// Check if a value reference is valid, while being aware of aliases which
/// may be unresolved while parsing.
#[cold]
pub fn value_is_valid_for_parser(&self, v: Value) -> bool {
if !self.value_is_valid(v) {
return false;
}
if let ValueData::Alias { ty, .. } = self.values[v] {
ty != types::VOID
} else {
true
}
}
}
#[cfg(test)]