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:
Jakob Stoklund Olesen
2016-07-05 14:44:21 -07:00
parent cbf78c294b
commit 473e708dce
4 changed files with 170 additions and 10 deletions

View File

@@ -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(())
}
}

View File

@@ -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!();

View 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)
}

View 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)
}