From 4525929df26f9ad29a663e2ce7eda70968a30c20 Mon Sep 17 00:00:00 2001 From: Angus Holder Date: Fri, 3 Mar 2017 21:30:33 +0000 Subject: [PATCH] Added tests, some refactoring, fixed a parsing bug. --- .../parser/instruction_encoding.cton | 25 +++++++++++ lib/reader/src/isaspec.rs | 12 ++++++ lib/reader/src/parser.rs | 41 ++++++++++--------- 3 files changed, 58 insertions(+), 20 deletions(-) create mode 100644 cranelift/filetests/parser/instruction_encoding.cton diff --git a/cranelift/filetests/parser/instruction_encoding.cton b/cranelift/filetests/parser/instruction_encoding.cton new file mode 100644 index 0000000000..49c1913bcf --- /dev/null +++ b/cranelift/filetests/parser/instruction_encoding.cton @@ -0,0 +1,25 @@ +test cat + +isa riscv + +; regex: WS=[ \t]* + +function foo(i32, i32) { +ebb1(v0: i32, v1: i32): + [-,-] v2 = iadd v0, v1 + [-] trap + [R#1234, %x5, %x11] v6, v7 = iadd_cout v2, v0 + [Rshamt#beef, %x25] v8 = ishl_imm v6, 2 + v9 = iadd v8, v7 + [Iret#5] return v0, v8 +} +; sameln: function foo(i32, i32) { +; nextln: $ebb1($v0: i32, $v1: i32): +; nextln: [-]$WS $v2 = iadd $v0, $v1 +; nextln: [-]$WS trap +; nextln: [0#1234]$WS $v6, $v7 = iadd_cout $v2, $v0 +; TODO Add the full encoding information available: instruction recipe name and architectural registers if specified +; nextln: [2#beef]$WS $v8 = ishl_imm $v6, 2 +; nextln: [-]$WS $v9 = iadd $v8, $v7 +; nextln: [3#05]$WS return $v0, $v8 +; nextln: } \ No newline at end of file diff --git a/lib/reader/src/isaspec.rs b/lib/reader/src/isaspec.rs index 706c081e3a..b7884bc42c 100644 --- a/lib/reader/src/isaspec.rs +++ b/lib/reader/src/isaspec.rs @@ -22,6 +22,18 @@ pub enum IsaSpec { Some(Vec>), } +impl IsaSpec { + /// If the `IsaSpec` contains exactly 1 `TargetIsa` we return a reference to it + pub fn unique_isa(&self) -> Option<&TargetIsa> { + if let &IsaSpec::Some(ref isa_vec) = self { + if isa_vec.len() == 1 { + return Some(&*isa_vec[0]); + } + } + None + } +} + /// Parse an iterator of command line options and apply them to `config`. pub fn parse_options<'a, I>(iter: I, config: &mut Configurable, loc: &Location) -> Result<()> where I: Iterator diff --git a/lib/reader/src/parser.rs b/lib/reader/src/parser.rs index f2061afec7..1c71f9f4f5 100644 --- a/lib/reader/src/parser.rs +++ b/lib/reader/src/parser.rs @@ -44,16 +44,7 @@ pub fn parse_test<'a>(text: &'a str) -> Result> { let commands = parser.parse_test_commands(); let isa_spec = parser.parse_isa_specs()?; let preamble_comments = parser.take_comments(); - - let functions = { - let mut unique_isa = None; - if let isaspec::IsaSpec::Some(ref isa_vec) = isa_spec { - if isa_vec.len() == 1 { - unique_isa = Some(&*isa_vec[0]); - } - } - parser.parse_function_list(unique_isa)? - }; + let functions = parser.parse_function_list(isa_spec.unique_isa())?; Ok(TestFile { commands: commands, @@ -102,7 +93,7 @@ impl<'a> Context<'a> { Context { function: f, map: SourceMap::new(), - unique_isa: unique_isa + unique_isa: unique_isa, } } @@ -592,8 +583,9 @@ impl<'a> Parser<'a> { /// Parse a list of function definitions. /// /// This is the top-level parse function matching the whole contents of a file. - pub fn parse_function_list(&mut self, unique_isa: Option<&TargetIsa>) - -> Result)>> { + pub fn parse_function_list(&mut self, + unique_isa: Option<&TargetIsa>) + -> Result)>> { let mut list = Vec::new(); while self.token().is_some() { list.push(self.parse_function(unique_isa)?); @@ -605,7 +597,9 @@ impl<'a> Parser<'a> { // // function ::= * function-spec "{" preamble function-body "}" // - fn parse_function(&mut self, unique_isa: Option<&TargetIsa>) -> Result<(Function, Details<'a>)> { + fn parse_function(&mut self, + unique_isa: Option<&TargetIsa>) + -> Result<(Function, Details<'a>)> { // Begin gathering comments. // Make sure we don't include any comments before the `function` keyword. self.token(); @@ -916,6 +910,7 @@ impl<'a> Parser<'a> { while match self.token() { Some(Token::Value(_)) => true, Some(Token::Identifier(_)) => true, + Some(Token::LBracket) => true, _ => false, } { self.parse_instruction(ctx, ebb)?; @@ -964,8 +959,9 @@ impl<'a> Parser<'a> { ctx.map.def_value(vx, value, &vx_location) } - fn parse_instruction_encoding(&mut self, ctx: &Context) - -> Result<(Option, Option>)> { + fn parse_instruction_encoding(&mut self, + ctx: &Context) + -> Result<(Option, Option>)> { let (mut encoding, mut result_registers) = (None, None); // encoding ::= "[" encoding_literal result_registers "]" @@ -977,6 +973,11 @@ impl<'a> Parser<'a> { if let Some(recipe_index) = ctx.find_recipe_index(recipe) { encoding = Some(Encoding::new(recipe_index, bits)); + } else if ctx.unique_isa.is_some() { + return err!(self.loc, "invalid instruction recipe"); + } else { + return err!(self.loc, + "provided instruction encoding for unspecified ISA"); } } @@ -1525,7 +1526,7 @@ mod tests { ss3 = stack_slot 13 ss1 = stack_slot 1 }") - .parse_function() + .parse_function(None) .unwrap(); assert_eq!(func.name.to_string(), "foo"); let mut iter = func.stack_slots.keys(); @@ -1542,7 +1543,7 @@ mod tests { ss1 = stack_slot 13 ss1 = stack_slot 1 }") - .parse_function() + .parse_function(None) .unwrap_err() .to_string(), "3: duplicate stack slot: ss1"); @@ -1554,7 +1555,7 @@ mod tests { ebb0: ebb4(vx3: i32): }") - .parse_function() + .parse_function(None) .unwrap(); assert_eq!(func.name.to_string(), "ebbs"); @@ -1583,7 +1584,7 @@ mod tests { trap ; Instruction } ; Trailing. ; More trailing.") - .parse_function() + .parse_function(None) .unwrap(); assert_eq!(func.name.to_string(), "comment"); assert_eq!(comments.len(), 8); // no 'before' comment.