diff --git a/cranelift/filetests/parser/alias.cton b/cranelift/filetests/parser/alias.cton new file mode 100644 index 0000000000..4e253bdb03 --- /dev/null +++ b/cranelift/filetests/parser/alias.cton @@ -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 +} diff --git a/lib/codegen/src/ir/dfg.rs b/lib/codegen/src/ir/dfg.rs index 21c3cc9b66..9db7364002 100644 --- a/lib/codegen/src/ir/dfg.rs +++ b/lib/codegen/src/ir/dfg.rs @@ -949,6 +949,18 @@ impl DataFlowGraph { 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 { + 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. /// Returns false if an alias cycle was encountered. #[cold] diff --git a/lib/reader/src/parser.rs b/lib/reader/src/parser.rs index a6586fea74..256ba50847 100644 --- a/lib/reader/src/parser.rs +++ b/lib/reader/src/parser.rs @@ -1580,13 +1580,34 @@ impl<'a> Parser<'a> { if results.len() != 1 { return err!(self.loc, "wrong number of aliases"); } + let result = results[0]; let dest = self.match_value("expected value alias")?; - ctx.function - .dfg - .make_value_alias_for_parser(dest, results[0]); - ctx.map.def_value(results[0], &self.loc)?; - ctx.aliases.push(results[0]); + // Allow duplicate definitions of aliases, as long as they are identical. + if ctx.map.contains_value(result) { + if let Some(old) = ctx.function.dfg.value_alias_dest_for_parser(result) { + if old != dest { + 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(()) }