From 473e708dce64b3e244bc59db67f4ff90dc9cfe28 Mon Sep 17 00:00:00 2001 From: Jakob Stoklund Olesen Date: Tue, 5 Jul 2016 14:44:21 -0700 Subject: [PATCH] Parse branch and jump instructions. These instruction formats take EBB references with lists of argument values. For EBBs with no arguments, the argument value list may be omitted. --- cranelift/src/libcretonne/instructions.rs | 30 ++++++++--- cranelift/src/libreader/parser.rs | 66 +++++++++++++++++++++-- cranelift/tests/parser/branch.cton | 45 ++++++++++++++++ cranelift/tests/parser/branch.cton.ref | 39 ++++++++++++++ 4 files changed, 170 insertions(+), 10 deletions(-) create mode 100644 cranelift/tests/parser/branch.cton create mode 100644 cranelift/tests/parser/branch.cton.ref diff --git a/cranelift/src/libcretonne/instructions.rs b/cranelift/src/libcretonne/instructions.rs index 9ac3ac7220..d8880c28ed 100644 --- a/cranelift/src/libcretonne/instructions.rs +++ b/cranelift/src/libcretonne/instructions.rs @@ -207,6 +207,14 @@ impl VariableArgs { pub fn new() -> VariableArgs { VariableArgs(Vec::new()) } + + pub fn push(&mut self, v: Value) { + self.0.push(v) + } + + pub fn is_empty(&self) -> bool { + self.0.is_empty() + } } impl Display for VariableArgs { @@ -233,13 +241,17 @@ impl Default for VariableArgs { /// in the allowed InstructionData size. #[derive(Debug)] pub struct JumpData { - destination: Ebb, - arguments: VariableArgs, + pub destination: Ebb, + pub arguments: VariableArgs, } impl Display for JumpData { fn fmt(&self, f: &mut Formatter) -> fmt::Result { - write!(f, "{}{}", self.destination, self.arguments) + if self.arguments.is_empty() { + write!(f, "{}", self.destination) + } else { + write!(f, "{}{}", self.destination, self.arguments) + } } } @@ -247,14 +259,18 @@ impl Display for JumpData { /// in the allowed InstructionData size. #[derive(Debug)] pub struct BranchData { - arg: Value, - destination: Ebb, - arguments: VariableArgs, + pub arg: Value, + pub destination: Ebb, + pub arguments: VariableArgs, } impl Display for BranchData { fn fmt(&self, f: &mut Formatter) -> fmt::Result { - write!(f, "{}, {}{}", self.arg, self.destination, self.arguments) + try!(write!(f, "{}, {}", self.arg, self.destination)); + if !self.arguments.is_empty() { + try!(write!(f, "{}", self.arguments)); + } + Ok(()) } } diff --git a/cranelift/src/libreader/parser.rs b/cranelift/src/libreader/parser.rs index ec584cdcaa..eb57504a6f 100644 --- a/cranelift/src/libreader/parser.rs +++ b/cranelift/src/libreader/parser.rs @@ -13,7 +13,8 @@ use lexer::{self, Lexer, Token}; use cretonne::types::{Type, VOID, FunctionName, Signature, ArgumentType, ArgumentExtension}; use cretonne::immediates::{Imm64, Ieee32, Ieee64}; use cretonne::entities::*; -use cretonne::instructions::{Opcode, InstructionFormat, InstructionData}; +use cretonne::instructions::{Opcode, InstructionFormat, InstructionData, VariableArgs, JumpData, + BranchData}; use cretonne::repr::{Function, StackSlotData}; pub use lexer::Location; @@ -672,6 +673,39 @@ impl<'a> Parser<'a> { Ok(()) } + // Parse comma-separated value list into a VariableArgs struct. + // + // value_list ::= [ value { "," value } ] + // + fn parse_value_list(&mut self) -> Result { + let mut args = VariableArgs::new(); + + if let Some(Token::Value(v)) = self.token() { + args.push(v); + self.consume(); + } else { + return Ok(args); + } + + while self.optional(Token::Comma) { + args.push(try!(self.match_value("expected value in argument list"))); + } + + Ok(args) + } + + // Parse an optional value list enclosed in parantheses. + fn parse_opt_value_list(&mut self) -> Result { + if !self.optional(Token::LPar) { + return Ok(VariableArgs::new()); + } + + let args = try!(self.parse_value_list()); + + try!(self.match_token(Token::RPar, "expected ')' after arguments")); + + Ok(args) + } // Parse the operands following the instruction opcode. // This depends on the format of the opcode. @@ -757,11 +791,37 @@ impl<'a> Parser<'a> { args: [lhs, rhs], } } + InstructionFormat::Jump => { + // Parse the destination EBB number. Don't translate source to local numbers yet. + let ebb_num = try!(self.match_ebb("expected jump destination EBB")); + let args = try!(self.parse_opt_value_list()); + InstructionData::Jump { + opcode: opcode, + ty: VOID, + data: Box::new(JumpData { + destination: ebb_num, + arguments: args, + }), + } + } + InstructionFormat::Branch => { + let ctrl_arg = try!(self.match_value("expected SSA value control operand")); + try!(self.match_token(Token::Comma, "expected ',' between operands")); + let ebb_num = try!(self.match_ebb("expected branch destination EBB")); + let args = try!(self.parse_opt_value_list()); + InstructionData::Branch { + opcode: opcode, + ty: VOID, + data: Box::new(BranchData { + arg: ctrl_arg, + destination: ebb_num, + arguments: args, + }), + } + } InstructionFormat::Select | InstructionFormat::InsertLane | InstructionFormat::ExtractLane | - InstructionFormat::Jump | - InstructionFormat::Branch | InstructionFormat::BranchTable | InstructionFormat::Call => { unimplemented!(); diff --git a/cranelift/tests/parser/branch.cton b/cranelift/tests/parser/branch.cton new file mode 100644 index 0000000000..bf49ba8a9f --- /dev/null +++ b/cranelift/tests/parser/branch.cton @@ -0,0 +1,45 @@ +; Parsing branches and jumps. + +; Jumps with no arguments. The '()' empty argument list is optional. +function minimal() { +ebb0: + jump ebb1 + +ebb1: + jump ebb0() +} + +; Jumps with 1 arg. +function onearg(i32) { +ebb0(vx0: i32): + jump ebb1(vx0) + +ebb1(vx1: i32): + jump ebb0(vx1) +} + +; Jumps with 2 args. +function twoargs(i32, f32) { +ebb0(vx0: i32, vx1: f32): + jump ebb1(vx0, vx1) + +ebb1(vx2: i32, vx3: f32): + jump ebb0(vx2, vx3) +} + +; Branches with no arguments. The '()' empty argument list is optional. +function minimal(i32) { +ebb0(vx0: i32): + brz vx0, ebb1 + +ebb1: + brnz vx0, ebb1() +} + +function twoargs(i32, f32) { +ebb0(vx0: i32, vx1: f32): + brz vx0, ebb1(vx0, vx1) + +ebb1(vx2: i32, vx3: f32): + brnz vx0, ebb0(vx2, vx3) +} diff --git a/cranelift/tests/parser/branch.cton.ref b/cranelift/tests/parser/branch.cton.ref new file mode 100644 index 0000000000..02444326b1 --- /dev/null +++ b/cranelift/tests/parser/branch.cton.ref @@ -0,0 +1,39 @@ +function minimal() { +ebb0: + jump ebb1 + +ebb1: + jump ebb0 +} + +function onearg(i32) { +ebb0(vx0: i32): + jump ebb1(vx0) + +ebb1(vx1: i32): + jump ebb0(vx1) +} + +function twoargs(i32, f32) { +ebb0(vx0: i32, vx1: f32): + jump ebb1(vx0, vx1) + +ebb1(vx2: i32, vx3: f32): + jump ebb0(vx2, vx3) +} + +function minimal(i32) { +ebb0(vx0: i32): + brz vx0, ebb1 + +ebb1: + brnz vx0, ebb1 +} + +function twoargs(i32, f32) { +ebb0(vx0: i32, vx1: f32): + brz vx0, ebb1(vx0, vx1) + +ebb1(vx2: i32, vx3: f32): + brnz vx0, ebb0(vx2, vx3) +}