Define control flow instructions.
Rename 'br' to 'jump'. We'll use jump/br to mean unconditional/conditional control transfer respectively.
This commit is contained in:
@@ -262,7 +262,12 @@ class InstDocumenter(sphinx.ext.autodoc.Documenter):
|
|||||||
if len(inst.outs) > 0:
|
if len(inst.outs) > 0:
|
||||||
sig = ', '.join([op.name for op in inst.outs]) + ' = ' + sig
|
sig = ', '.join([op.name for op in inst.outs]) + ' = ' + sig
|
||||||
if len(inst.ins) > 0:
|
if len(inst.ins) > 0:
|
||||||
sig = sig + ' ' + ', '.join([op.name for op in inst.ins])
|
sig = sig + ' ' + inst.ins[0].name
|
||||||
|
for op in inst.ins[1:]:
|
||||||
|
if op.typ.operand_kind().name == 'variable_args':
|
||||||
|
sig += '({}...)'.format(op.name)
|
||||||
|
else:
|
||||||
|
sig += ', ' + op.name
|
||||||
return sig
|
return sig
|
||||||
|
|
||||||
def add_directive_header(self, sig):
|
def add_directive_header(self, sig):
|
||||||
|
|||||||
@@ -313,56 +313,10 @@ arguments, if it has any. Conditional branches only take the branch if their
|
|||||||
condition is satisfied, otherwise execution continues at the following
|
condition is satisfied, otherwise execution continues at the following
|
||||||
instruction in the EBB.
|
instruction in the EBB.
|
||||||
|
|
||||||
.. inst:: br EBB(args...)
|
.. autoinst:: jump
|
||||||
|
.. autoinst:: brz
|
||||||
Branch.
|
.. autoinst:: brnz
|
||||||
|
.. autoinst:: br_table
|
||||||
Unconditionally branch to an extended basic block, passing the specified
|
|
||||||
EBB arguments. The number and types of arguments must match the destination
|
|
||||||
EBB.
|
|
||||||
|
|
||||||
:arg EBB: Destination extended basic block.
|
|
||||||
:arg args...: Zero or more arguments passed to EBB.
|
|
||||||
:result: None. This is a terminator instruction.
|
|
||||||
|
|
||||||
.. inst:: brz x, EBB(args...)
|
|
||||||
|
|
||||||
Branch when zero.
|
|
||||||
|
|
||||||
If ``x`` is a :type:`b1` value, take the branch when ``x`` is false. If
|
|
||||||
``x`` is an integer value, take the branch when ``x = 0``.
|
|
||||||
|
|
||||||
:arg Testable x: Value to test.
|
|
||||||
:arg EBB: Destination extended basic block.
|
|
||||||
:arg args...: Arguments passed to EBB.
|
|
||||||
:result: None.
|
|
||||||
|
|
||||||
.. inst:: brnz x, EBB(args...)
|
|
||||||
|
|
||||||
Branch when non-zero.
|
|
||||||
|
|
||||||
If ``x`` is a :type:`b1` value, take the branch when ``x`` is true. If
|
|
||||||
``x`` is an integer value, take the branch when ``x != 0``.
|
|
||||||
|
|
||||||
:arg Testable x: Value to test.
|
|
||||||
:arg EBB: Destination extended basic block.
|
|
||||||
:arg args...: Zero or more arguments passed to EBB.
|
|
||||||
:result: None.
|
|
||||||
|
|
||||||
.. inst:: br_table x, JT
|
|
||||||
|
|
||||||
Jump table branch.
|
|
||||||
|
|
||||||
Use ``x`` as an unsigned index into the jump table ``JT``. If a jump table
|
|
||||||
entry is found, branch to the corresponding EBB. If no entry was found fall
|
|
||||||
through to the next instruction.
|
|
||||||
|
|
||||||
Note that this branch instruction can't pass arguments to the targeted
|
|
||||||
blocks. Split critical edges as needed to work around this.
|
|
||||||
|
|
||||||
:arg iN x: Integer index into jump table.
|
|
||||||
:arg JT: Jump table which was declared in the preamble.
|
|
||||||
:result: None.
|
|
||||||
|
|
||||||
.. inst:: JT = jump_table EBB0, EBB1, ..., EBBn
|
.. inst:: JT = jump_table EBB0, EBB1, ..., EBBn
|
||||||
|
|
||||||
@@ -386,29 +340,9 @@ explicit trap instructions defined below, but some instructions may also cause
|
|||||||
traps for certain input value. For example, :inst:`udiv` traps when the divisor
|
traps for certain input value. For example, :inst:`udiv` traps when the divisor
|
||||||
is zero.
|
is zero.
|
||||||
|
|
||||||
.. inst:: trap
|
.. autoinst:: trap
|
||||||
|
.. autoinst:: trapz
|
||||||
Terminate execution unconditionally.
|
.. autoinst:: trapnz
|
||||||
|
|
||||||
:result: None. This is a terminator instruction.
|
|
||||||
|
|
||||||
.. inst:: trapz x
|
|
||||||
|
|
||||||
Trap when zero.
|
|
||||||
|
|
||||||
if ``x`` is non-zero, execution continues at the following instruction.
|
|
||||||
|
|
||||||
:arg Testable x: Value to test.
|
|
||||||
:result: None.
|
|
||||||
|
|
||||||
.. inst:: trapnz x
|
|
||||||
|
|
||||||
Trap when non-zero.
|
|
||||||
|
|
||||||
if ``x`` is zero, execution continues at the following instruction.
|
|
||||||
|
|
||||||
:arg Testable x: Value to test.
|
|
||||||
:result: None.
|
|
||||||
|
|
||||||
|
|
||||||
Function calls
|
Function calls
|
||||||
|
|||||||
@@ -450,6 +450,8 @@ class Instruction(object):
|
|||||||
operands and other operand kinds.
|
operands and other operand kinds.
|
||||||
:param outs: Tuple of output operands. The output operands must be SSA
|
:param outs: Tuple of output operands. The output operands must be SSA
|
||||||
values.
|
values.
|
||||||
|
:param is_terminator: This is a terminator instruction.
|
||||||
|
:param is_branch: This is a branch instruction.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def __init__(self, name, doc, ins=(), outs=(), **kwargs):
|
def __init__(self, name, doc, ins=(), outs=(), **kwargs):
|
||||||
|
|||||||
@@ -4,18 +4,94 @@ Cretonne base instruction set.
|
|||||||
This module defines the basic Cretonne instruction set that all targets
|
This module defines the basic Cretonne instruction set that all targets
|
||||||
support.
|
support.
|
||||||
"""
|
"""
|
||||||
from . import TypeVar, Operand, Instruction, InstructionGroup
|
from . import TypeVar, Operand, Instruction, InstructionGroup, variable_args
|
||||||
from types import i8, f32, f64
|
from types import i8, f32, f64
|
||||||
from immediates import imm64, ieee32, ieee64, immvector
|
from immediates import imm64, ieee32, ieee64, immvector
|
||||||
|
import entities
|
||||||
|
|
||||||
instructions = InstructionGroup("base", "Shared base instruction set")
|
instructions = InstructionGroup("base", "Shared base instruction set")
|
||||||
|
|
||||||
Int = TypeVar('Int', 'A scalar or vector integer type', ints=True, simd=True)
|
Int = TypeVar('Int', 'A scalar or vector integer type', ints=True, simd=True)
|
||||||
iB = TypeVar('iB', 'A scalar integer type', ints=True)
|
iB = TypeVar('iB', 'A scalar integer type', ints=True)
|
||||||
|
Testable = TypeVar(
|
||||||
|
'Testable', 'A scalar boolean or integer type',
|
||||||
|
ints=True, bools=True)
|
||||||
TxN = TypeVar(
|
TxN = TypeVar(
|
||||||
'%Tx%N', 'A SIMD vector type',
|
'%Tx%N', 'A SIMD vector type',
|
||||||
ints=True, floats=True, bools=True, scalars=False, simd=True)
|
ints=True, floats=True, bools=True, scalars=False, simd=True)
|
||||||
|
|
||||||
|
#
|
||||||
|
# Control flow
|
||||||
|
#
|
||||||
|
c = Operand('c', Testable, doc='Controlling value to test')
|
||||||
|
EBB = Operand('EBB', entities.ebb, doc='Destination extended basic block')
|
||||||
|
args = Operand('args', variable_args, doc='EBB arguments')
|
||||||
|
|
||||||
|
jump = Instruction(
|
||||||
|
'jump', r"""
|
||||||
|
Jump.
|
||||||
|
|
||||||
|
Unconditionally jump to an extended basic block, passing the specified
|
||||||
|
EBB arguments. The number and types of arguments must match the
|
||||||
|
destination EBB.
|
||||||
|
""",
|
||||||
|
ins=(EBB, args), is_terminator=True)
|
||||||
|
|
||||||
|
brz = Instruction(
|
||||||
|
'brz', r"""
|
||||||
|
Branch when zero.
|
||||||
|
|
||||||
|
If ``c`` is a :type:`b1` value, take the branch when ``c`` is false. If
|
||||||
|
``c`` is an integer value, take the branch when ``c = 0``.
|
||||||
|
""",
|
||||||
|
ins=(c, EBB, args), is_branch=True)
|
||||||
|
|
||||||
|
brnz = Instruction(
|
||||||
|
'brnz', r"""
|
||||||
|
Branch when non-zero.
|
||||||
|
|
||||||
|
If ``c`` is a :type:`b1` value, take the branch when ``c`` is true. If
|
||||||
|
``c`` is an integer value, take the branch when ``c != 0``.
|
||||||
|
""",
|
||||||
|
ins=(c, EBB, args), is_branch=True)
|
||||||
|
|
||||||
|
x = Operand('x', iB, doc='index into jump table')
|
||||||
|
JT = Operand('JT', entities.jump_table)
|
||||||
|
br_table = Instruction(
|
||||||
|
'br_table', r"""
|
||||||
|
Indirect branch via jump table.
|
||||||
|
|
||||||
|
Use ``x`` as an unsigned index into the jump table ``JT``. If a jump table
|
||||||
|
entry is found, branch to the corresponding EBB. If no entry was found fall
|
||||||
|
through to the next instruction.
|
||||||
|
|
||||||
|
Note that this branch instruction can't pass arguments to the targeted
|
||||||
|
blocks. Split critical edges as needed to work around this.
|
||||||
|
""",
|
||||||
|
ins=(x, JT), is_branch=True)
|
||||||
|
|
||||||
|
trap = Instruction(
|
||||||
|
'trap', r"""
|
||||||
|
Terminate execution unconditionally.
|
||||||
|
""",
|
||||||
|
is_terminator=True)
|
||||||
|
|
||||||
|
trapz = Instruction(
|
||||||
|
'trapz', r"""
|
||||||
|
Trap when zero.
|
||||||
|
|
||||||
|
if ``c`` is non-zero, execution continues at the following instruction.
|
||||||
|
""",
|
||||||
|
ins=c)
|
||||||
|
|
||||||
|
trapnz = Instruction(
|
||||||
|
'trapnz', r"""
|
||||||
|
Trap when non-zero.
|
||||||
|
|
||||||
|
if ``c`` is zero, execution continues at the following instruction.
|
||||||
|
""",
|
||||||
|
ins=c)
|
||||||
|
|
||||||
#
|
#
|
||||||
# Materializing constants.
|
# Materializing constants.
|
||||||
#
|
#
|
||||||
|
|||||||
@@ -21,3 +21,6 @@ signature = EntityRefKind('signature', 'A function signature.')
|
|||||||
#: A reference to an external function declared in the function preamble.
|
#: A reference to an external function declared in the function preamble.
|
||||||
#: This is used to provide the callee and signature in a call instruction.
|
#: This is used to provide the callee and signature in a call instruction.
|
||||||
function = EntityRefKind('function', 'An external function.')
|
function = EntityRefKind('function', 'An external function.')
|
||||||
|
|
||||||
|
#: A reference to a jump table declared in the function preamble.
|
||||||
|
jump_table = EntityRefKind('jump_table', 'A jump table.')
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ in this module.
|
|||||||
|
|
||||||
from . import InstructionFormat, value, variable_args
|
from . import InstructionFormat, value, variable_args
|
||||||
from immediates import imm64, ieee32, ieee64, immvector
|
from immediates import imm64, ieee32, ieee64, immvector
|
||||||
from entities import function
|
from entities import ebb, function, jump_table
|
||||||
|
|
||||||
Nullary = InstructionFormat()
|
Nullary = InstructionFormat()
|
||||||
|
|
||||||
@@ -23,6 +23,10 @@ Binary = InstructionFormat(value, value)
|
|||||||
BinaryImm = InstructionFormat(value, imm64)
|
BinaryImm = InstructionFormat(value, imm64)
|
||||||
BinaryImmRev = InstructionFormat(imm64, value)
|
BinaryImmRev = InstructionFormat(imm64, value)
|
||||||
|
|
||||||
|
Jump = InstructionFormat(ebb, variable_args)
|
||||||
|
Branch = InstructionFormat(value, ebb, variable_args)
|
||||||
|
BranchTable = InstructionFormat(value, jump_table)
|
||||||
|
|
||||||
Call = InstructionFormat(function, variable_args, multiple_results=True)
|
Call = InstructionFormat(function, variable_args, multiple_results=True)
|
||||||
|
|
||||||
# Finally extract the names of global variables in this module.
|
# Finally extract the names of global variables in this module.
|
||||||
|
|||||||
@@ -189,3 +189,34 @@ impl Default for StackSlot {
|
|||||||
NO_STACK_SLOT
|
NO_STACK_SLOT
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// An opaque reference to a jump table.
|
||||||
|
#[derive(Copy, Clone, PartialEq, Eq, Debug)]
|
||||||
|
pub struct JumpTable(u32);
|
||||||
|
|
||||||
|
impl JumpTable {
|
||||||
|
pub fn new(index: usize) -> JumpTable {
|
||||||
|
assert!(index < (u32::MAX as usize));
|
||||||
|
JumpTable(index as u32)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn index(&self) -> usize {
|
||||||
|
self.0 as usize
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Display a `JumpTable` reference as "jt12".
|
||||||
|
impl Display for JumpTable {
|
||||||
|
fn fmt(&self, fmt: &mut Formatter) -> fmt::Result {
|
||||||
|
write!(fmt, "jt{}", self.0)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// A guaranteed invalid jump table reference.
|
||||||
|
pub const NO_JUMP_TABLE: JumpTable = JumpTable(u32::MAX);
|
||||||
|
|
||||||
|
impl Default for JumpTable {
|
||||||
|
fn default() -> JumpTable {
|
||||||
|
NO_JUMP_TABLE
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -140,6 +140,22 @@ pub enum InstructionData {
|
|||||||
rhs: Value,
|
rhs: Value,
|
||||||
lhs: Imm64,
|
lhs: Imm64,
|
||||||
},
|
},
|
||||||
|
Jump {
|
||||||
|
opcode: Opcode,
|
||||||
|
ty: Type,
|
||||||
|
data: Box<JumpData>,
|
||||||
|
},
|
||||||
|
Branch {
|
||||||
|
opcode: Opcode,
|
||||||
|
ty: Type,
|
||||||
|
data: Box<BranchData>,
|
||||||
|
},
|
||||||
|
BranchTable {
|
||||||
|
opcode: Opcode,
|
||||||
|
ty: Type,
|
||||||
|
arg: Value,
|
||||||
|
table: JumpTable,
|
||||||
|
},
|
||||||
Call {
|
Call {
|
||||||
opcode: Opcode,
|
opcode: Opcode,
|
||||||
ty: Type,
|
ty: Type,
|
||||||
@@ -147,6 +163,66 @@ pub enum InstructionData {
|
|||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// A variable list of `Value` operands used for function call arguments and passing arguments to
|
||||||
|
/// basic blocks.
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct VariableArgs(Vec<Value>);
|
||||||
|
|
||||||
|
impl VariableArgs {
|
||||||
|
pub fn new() -> VariableArgs {
|
||||||
|
VariableArgs(Vec::new())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Display for VariableArgs {
|
||||||
|
fn fmt(&self, fmt: &mut Formatter) -> fmt::Result {
|
||||||
|
try!(write!(fmt, "("));
|
||||||
|
for (i, val) in self.0.iter().enumerate() {
|
||||||
|
if i == 0 {
|
||||||
|
try!(write!(fmt, "{}", val));
|
||||||
|
} else {
|
||||||
|
try!(write!(fmt, ", {}", val));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
write!(fmt, ")")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Default for VariableArgs {
|
||||||
|
fn default() -> VariableArgs {
|
||||||
|
VariableArgs::new()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Payload data for jump instructions. These need to carry lists of EBB arguments that won't fit
|
||||||
|
/// in the allowed InstructionData size.
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct JumpData {
|
||||||
|
destination: Ebb,
|
||||||
|
arguments: VariableArgs,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Display for JumpData {
|
||||||
|
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
|
||||||
|
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,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Display for BranchData {
|
||||||
|
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
|
||||||
|
write!(f, "{}, {}{}", self.arg, self.destination, self.arguments)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Payload of a call instruction.
|
/// Payload of a call instruction.
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct CallData {
|
pub struct CallData {
|
||||||
@@ -154,9 +230,14 @@ pub struct CallData {
|
|||||||
second_result: Value,
|
second_result: Value,
|
||||||
|
|
||||||
// Dynamically sized array containing call argument values.
|
// Dynamically sized array containing call argument values.
|
||||||
arguments: Vec<Value>,
|
arguments: VariableArgs,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl Display for CallData {
|
||||||
|
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
|
||||||
|
write!(f, "TBD{}", self.arguments)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl InstructionData {
|
impl InstructionData {
|
||||||
/// Create data for a call instruction.
|
/// Create data for a call instruction.
|
||||||
@@ -166,7 +247,7 @@ impl InstructionData {
|
|||||||
ty: return_type,
|
ty: return_type,
|
||||||
data: Box::new(CallData {
|
data: Box::new(CallData {
|
||||||
second_result: NO_VALUE,
|
second_result: NO_VALUE,
|
||||||
arguments: Vec::new(),
|
arguments: VariableArgs::new(),
|
||||||
}),
|
}),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -184,6 +265,9 @@ impl InstructionData {
|
|||||||
Binary { opcode, .. } => opcode,
|
Binary { opcode, .. } => opcode,
|
||||||
BinaryImm { opcode, .. } => opcode,
|
BinaryImm { opcode, .. } => opcode,
|
||||||
BinaryImmRev { opcode, .. } => opcode,
|
BinaryImmRev { opcode, .. } => opcode,
|
||||||
|
Jump { opcode, .. } => opcode,
|
||||||
|
Branch { opcode, .. } => opcode,
|
||||||
|
BranchTable { opcode, .. } => opcode,
|
||||||
Call { opcode, .. } => opcode,
|
Call { opcode, .. } => opcode,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -201,6 +285,9 @@ impl InstructionData {
|
|||||||
Binary { ty, .. } => ty,
|
Binary { ty, .. } => ty,
|
||||||
BinaryImm { ty, .. } => ty,
|
BinaryImm { ty, .. } => ty,
|
||||||
BinaryImmRev { ty, .. } => ty,
|
BinaryImmRev { ty, .. } => ty,
|
||||||
|
Jump { ty, .. } => ty,
|
||||||
|
Branch { ty, .. } => ty,
|
||||||
|
BranchTable { ty, .. } => ty,
|
||||||
Call { ty, .. } => ty,
|
Call { ty, .. } => ty,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -218,6 +305,9 @@ impl InstructionData {
|
|||||||
Binary { .. } => None,
|
Binary { .. } => None,
|
||||||
BinaryImm { .. } => None,
|
BinaryImm { .. } => None,
|
||||||
BinaryImmRev { .. } => None,
|
BinaryImmRev { .. } => None,
|
||||||
|
Jump { .. } => None,
|
||||||
|
Branch { .. } => None,
|
||||||
|
BranchTable { .. } => None,
|
||||||
Call { ref data, .. } => Some(data.second_result),
|
Call { ref data, .. } => Some(data.second_result),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -234,6 +324,9 @@ impl InstructionData {
|
|||||||
Binary { .. } => None,
|
Binary { .. } => None,
|
||||||
BinaryImm { .. } => None,
|
BinaryImm { .. } => None,
|
||||||
BinaryImmRev { .. } => None,
|
BinaryImmRev { .. } => None,
|
||||||
|
Jump { .. } => None,
|
||||||
|
Branch { .. } => None,
|
||||||
|
BranchTable { .. } => None,
|
||||||
Call { ref mut data, .. } => Some(&mut data.second_result),
|
Call { ref mut data, .. } => Some(&mut data.second_result),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -263,4 +356,15 @@ mod tests {
|
|||||||
assert_eq!("".parse::<Opcode>(), Err("Unknown opcode"));
|
assert_eq!("".parse::<Opcode>(), Err("Unknown opcode"));
|
||||||
assert_eq!("\0".parse::<Opcode>(), Err("Unknown opcode"));
|
assert_eq!("\0".parse::<Opcode>(), Err("Unknown opcode"));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn instruction_data() {
|
||||||
|
use std::mem;
|
||||||
|
// The size of the InstructionData enum is important for performance. It should not exceed
|
||||||
|
// 16 bytes. Use `Box<FooData>` out-of-line payloads for instruction formats that require
|
||||||
|
// more space than that.
|
||||||
|
// It would be fine with a data structure smaller than 16 bytes, but what are the odds of
|
||||||
|
// that?
|
||||||
|
assert_eq!(mem::size_of::<InstructionData>(), 16);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -155,7 +155,10 @@ pub fn write_instruction(w: &mut Write, func: &Function, inst: Inst) -> Result {
|
|||||||
Binary { opcode, args, .. } => writeln!(w, "{} {}, {}", opcode, args[0], args[1]),
|
Binary { opcode, args, .. } => writeln!(w, "{} {}, {}", opcode, args[0], args[1]),
|
||||||
BinaryImm { opcode, lhs, rhs, .. } => writeln!(w, "{} {}, {}", opcode, lhs, rhs),
|
BinaryImm { opcode, lhs, rhs, .. } => writeln!(w, "{} {}, {}", opcode, lhs, rhs),
|
||||||
BinaryImmRev { opcode, lhs, rhs, .. } => writeln!(w, "{} {}, {}", opcode, lhs, rhs),
|
BinaryImmRev { opcode, lhs, rhs, .. } => writeln!(w, "{} {}, {}", opcode, lhs, rhs),
|
||||||
Call { opcode, .. } => writeln!(w, "{} [...]", opcode),
|
Jump { opcode, ref data, .. } => writeln!(w, "{} {}", opcode, data),
|
||||||
|
Branch { opcode, ref data, .. } => writeln!(w, "{} {}", opcode, data),
|
||||||
|
BranchTable { opcode, arg, table, .. } => writeln!(w, "{} {}, {}", opcode, arg, table),
|
||||||
|
Call { opcode, ref data, .. } => writeln!(w, "{} {}", opcode, data),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -657,6 +657,9 @@ impl<'a> Parser<'a> {
|
|||||||
rhs: rhs,
|
rhs: rhs,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
InstructionFormat::Jump |
|
||||||
|
InstructionFormat::Branch |
|
||||||
|
InstructionFormat::BranchTable |
|
||||||
InstructionFormat::Call => {
|
InstructionFormat::Call => {
|
||||||
unimplemented!();
|
unimplemented!();
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user