Accept redundant alias definitions.

In the text format, allow aliases to be defined multiple times, as long
as they're always aliasing the same value.

write.rs is already emitting redundant aliases, because it emits them at
their uses, so this change allows the parser to be able to parse such
code.
This commit is contained in:
Dan Gohman
2018-06-07 15:56:23 -07:00
parent 00d7d3a774
commit 0daa560368
3 changed files with 70 additions and 5 deletions

View File

@@ -0,0 +1,32 @@
test cat
test verifier
function %basic(i32, i32) -> i32 {
ebb0(v0: i32, v1: i32):
v2 -> v0
v3 -> v1
v4 = iadd.i32 v2, v3
return v4
}
function %transitive() -> i32 {
ebb0:
v0 = iconst.i32 0
v1 -> v0
v2 -> v1
v3 -> v2
v4 -> v3
return v4
}
function %duplicate(i32, i32) -> i32 {
ebb0(v0: i32, v1: i32):
v2 -> v0
v2 -> v0
v2 -> v0
v3 -> v1
v3 -> v1
v3 -> v1
v4 = iadd.i32 v2, v3
return v4
}

View File

@@ -949,6 +949,18 @@ impl DataFlowGraph {
self.values[dest] = data; self.values[dest] = data;
} }
/// If `v` is already defined as an alias, return its destination value.
/// Otherwise return None. This allows the parser to coalesce identical
/// alias definitions.
#[cold]
pub fn value_alias_dest_for_parser(&self, v: Value) -> Option<Value> {
if let ValueData::Alias { original, .. } = self.values[v] {
Some(original)
} else {
None
}
}
/// Compute the type of an alias. This is only for use in the parser. /// Compute the type of an alias. This is only for use in the parser.
/// Returns false if an alias cycle was encountered. /// Returns false if an alias cycle was encountered.
#[cold] #[cold]

View File

@@ -1580,13 +1580,34 @@ impl<'a> Parser<'a> {
if results.len() != 1 { if results.len() != 1 {
return err!(self.loc, "wrong number of aliases"); return err!(self.loc, "wrong number of aliases");
} }
let result = results[0];
let dest = self.match_value("expected value alias")?; let dest = self.match_value("expected value alias")?;
ctx.function // Allow duplicate definitions of aliases, as long as they are identical.
.dfg if ctx.map.contains_value(result) {
.make_value_alias_for_parser(dest, results[0]); if let Some(old) = ctx.function.dfg.value_alias_dest_for_parser(result) {
ctx.map.def_value(results[0], &self.loc)?; if old != dest {
ctx.aliases.push(results[0]); return err!(
self.loc,
"value {} is already defined as an alias with destination {}",
result,
old
);
}
} else {
return err!(self.loc, "value {} is already defined");
}
} else {
ctx.map.def_value(result, &self.loc)?;
}
if !ctx.map.contains_value(dest) {
return err!(self.loc, "value {} is not yet defined", dest);
}
ctx.function.dfg.make_value_alias_for_parser(dest, result);
ctx.aliases.push(result);
Ok(()) Ok(())
} }