Added tests, some refactoring, fixed a parsing bug.
This commit is contained in:
committed by
Jakob Stoklund Olesen
parent
a58ccb1125
commit
4525929df2
25
cranelift/filetests/parser/instruction_encoding.cton
Normal file
25
cranelift/filetests/parser/instruction_encoding.cton
Normal file
@@ -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: }
|
||||||
@@ -22,6 +22,18 @@ pub enum IsaSpec {
|
|||||||
Some(Vec<Box<TargetIsa>>),
|
Some(Vec<Box<TargetIsa>>),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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`.
|
/// 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<()>
|
pub fn parse_options<'a, I>(iter: I, config: &mut Configurable, loc: &Location) -> Result<()>
|
||||||
where I: Iterator<Item = &'a str>
|
where I: Iterator<Item = &'a str>
|
||||||
|
|||||||
@@ -44,16 +44,7 @@ pub fn parse_test<'a>(text: &'a str) -> Result<TestFile<'a>> {
|
|||||||
let commands = parser.parse_test_commands();
|
let commands = parser.parse_test_commands();
|
||||||
let isa_spec = parser.parse_isa_specs()?;
|
let isa_spec = parser.parse_isa_specs()?;
|
||||||
let preamble_comments = parser.take_comments();
|
let preamble_comments = parser.take_comments();
|
||||||
|
let functions = parser.parse_function_list(isa_spec.unique_isa())?;
|
||||||
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)?
|
|
||||||
};
|
|
||||||
|
|
||||||
Ok(TestFile {
|
Ok(TestFile {
|
||||||
commands: commands,
|
commands: commands,
|
||||||
@@ -102,7 +93,7 @@ impl<'a> Context<'a> {
|
|||||||
Context {
|
Context {
|
||||||
function: f,
|
function: f,
|
||||||
map: SourceMap::new(),
|
map: SourceMap::new(),
|
||||||
unique_isa: unique_isa
|
unique_isa: unique_isa,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -592,7 +583,8 @@ impl<'a> Parser<'a> {
|
|||||||
/// Parse a list of function definitions.
|
/// Parse a list of function definitions.
|
||||||
///
|
///
|
||||||
/// This is the top-level parse function matching the whole contents of a file.
|
/// 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>)
|
pub fn parse_function_list(&mut self,
|
||||||
|
unique_isa: Option<&TargetIsa>)
|
||||||
-> Result<Vec<(Function, Details<'a>)>> {
|
-> Result<Vec<(Function, Details<'a>)>> {
|
||||||
let mut list = Vec::new();
|
let mut list = Vec::new();
|
||||||
while self.token().is_some() {
|
while self.token().is_some() {
|
||||||
@@ -605,7 +597,9 @@ impl<'a> Parser<'a> {
|
|||||||
//
|
//
|
||||||
// function ::= * function-spec "{" preamble function-body "}"
|
// 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.
|
// Begin gathering comments.
|
||||||
// Make sure we don't include any comments before the `function` keyword.
|
// Make sure we don't include any comments before the `function` keyword.
|
||||||
self.token();
|
self.token();
|
||||||
@@ -916,6 +910,7 @@ impl<'a> Parser<'a> {
|
|||||||
while match self.token() {
|
while match self.token() {
|
||||||
Some(Token::Value(_)) => true,
|
Some(Token::Value(_)) => true,
|
||||||
Some(Token::Identifier(_)) => true,
|
Some(Token::Identifier(_)) => true,
|
||||||
|
Some(Token::LBracket) => true,
|
||||||
_ => false,
|
_ => false,
|
||||||
} {
|
} {
|
||||||
self.parse_instruction(ctx, ebb)?;
|
self.parse_instruction(ctx, ebb)?;
|
||||||
@@ -964,7 +959,8 @@ impl<'a> Parser<'a> {
|
|||||||
ctx.map.def_value(vx, value, &vx_location)
|
ctx.map.def_value(vx, value, &vx_location)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn parse_instruction_encoding(&mut self, ctx: &Context)
|
fn parse_instruction_encoding(&mut self,
|
||||||
|
ctx: &Context)
|
||||||
-> Result<(Option<Encoding>, Option<Vec<&'a str>>)> {
|
-> Result<(Option<Encoding>, Option<Vec<&'a str>>)> {
|
||||||
let (mut encoding, mut result_registers) = (None, None);
|
let (mut encoding, mut result_registers) = (None, None);
|
||||||
|
|
||||||
@@ -977,6 +973,11 @@ impl<'a> Parser<'a> {
|
|||||||
|
|
||||||
if let Some(recipe_index) = ctx.find_recipe_index(recipe) {
|
if let Some(recipe_index) = ctx.find_recipe_index(recipe) {
|
||||||
encoding = Some(Encoding::new(recipe_index, bits));
|
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
|
ss3 = stack_slot 13
|
||||||
ss1 = stack_slot 1
|
ss1 = stack_slot 1
|
||||||
}")
|
}")
|
||||||
.parse_function()
|
.parse_function(None)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
assert_eq!(func.name.to_string(), "foo");
|
assert_eq!(func.name.to_string(), "foo");
|
||||||
let mut iter = func.stack_slots.keys();
|
let mut iter = func.stack_slots.keys();
|
||||||
@@ -1542,7 +1543,7 @@ mod tests {
|
|||||||
ss1 = stack_slot 13
|
ss1 = stack_slot 13
|
||||||
ss1 = stack_slot 1
|
ss1 = stack_slot 1
|
||||||
}")
|
}")
|
||||||
.parse_function()
|
.parse_function(None)
|
||||||
.unwrap_err()
|
.unwrap_err()
|
||||||
.to_string(),
|
.to_string(),
|
||||||
"3: duplicate stack slot: ss1");
|
"3: duplicate stack slot: ss1");
|
||||||
@@ -1554,7 +1555,7 @@ mod tests {
|
|||||||
ebb0:
|
ebb0:
|
||||||
ebb4(vx3: i32):
|
ebb4(vx3: i32):
|
||||||
}")
|
}")
|
||||||
.parse_function()
|
.parse_function(None)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
assert_eq!(func.name.to_string(), "ebbs");
|
assert_eq!(func.name.to_string(), "ebbs");
|
||||||
|
|
||||||
@@ -1583,7 +1584,7 @@ mod tests {
|
|||||||
trap ; Instruction
|
trap ; Instruction
|
||||||
} ; Trailing.
|
} ; Trailing.
|
||||||
; More trailing.")
|
; More trailing.")
|
||||||
.parse_function()
|
.parse_function(None)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
assert_eq!(func.name.to_string(), "comment");
|
assert_eq!(func.name.to_string(), "comment");
|
||||||
assert_eq!(comments.len(), 8); // no 'before' comment.
|
assert_eq!(comments.len(), 8); // no 'before' comment.
|
||||||
|
|||||||
Reference in New Issue
Block a user