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.
This commit is contained in:
@@ -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,28 +241,36 @@ 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 {
|
||||
if self.arguments.is_empty() {
|
||||
write!(f, "{}", self.destination)
|
||||
} else {
|
||||
write!(f, "{}{}", self.destination, self.arguments)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Payload data for branch instructions. These need to carry lists of EBB arguments that won't fit
|
||||
/// 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(())
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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<VariableArgs> {
|
||||
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<VariableArgs> {
|
||||
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!();
|
||||
|
||||
45
cranelift/tests/parser/branch.cton
Normal file
45
cranelift/tests/parser/branch.cton
Normal file
@@ -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)
|
||||
}
|
||||
39
cranelift/tests/parser/branch.cton.ref
Normal file
39
cranelift/tests/parser/branch.cton.ref
Normal file
@@ -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)
|
||||
}
|
||||
Reference in New Issue
Block a user