Skip to content

Commit

Permalink
Add Instruction::into_inner (#27)
Browse files Browse the repository at this point in the history
An instruction, after parsed, will have all its attributes exposed to
the VM. Its convenient to have a canonical `into_inner` so the
underlying fields can be read.

The exposed fields are:

- OpcodeRepr
- RegisterId $ra
- RegisterId $rb
- RegisterId $rc
- RegisterId $rd
- Word immediate value

To achieve that, `OpcodeRepr` must be refactored before its exposed as
public. We should cover all variants of a byte in order to perform
transparent safe conversions from/to `OpcodeRepr`/`u8` in the internal
representation.
  • Loading branch information
vlopes11 authored and xgreenx committed Dec 20, 2022
1 parent 792ad7e commit f4e920f
Show file tree
Hide file tree
Showing 6 changed files with 691 additions and 174 deletions.
2 changes: 1 addition & 1 deletion fuel-asm/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ name = "fuel-asm"
description = "Defines all opcodes available in the FuelVM."
version = "0.1.0"
authors = ["Victor Lopez <victor.lopez@fuel.sh>"]
edition = "2018"
edition = "2021"
repository = "https://github.com/FuelLabs/fuel-asm"
keywords = ["blockchain", "cryptocurrencies", "fuel-vm", "vm"]
categories = ["cryptography::cryptocurrencies", "data-structures", "parsing"]
Expand Down
64 changes: 59 additions & 5 deletions fuel-asm/src/instruction.rs
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
use crate::opcode::OpcodeRepr;

use fuel_types::{Immediate06, Immediate12, Immediate18, Immediate24, RegisterId, Word};

#[cfg(feature = "std")]
use std::{io, iter};

use crate::opcode::consts::OpcodeRepr;

/// A version of Opcode that can used without unnecessary branching
#[derive(Debug, Default, Clone, Copy, PartialEq, Eq)]
#[cfg_attr(
Expand Down Expand Up @@ -128,7 +128,7 @@ impl Instruction {
u32::from(self).to_be_bytes()
}

/// Splits a Word into two [`Instruction`] that can be used to construct [`Opcode`]
/// Splits a Word into two [`Instruction`] that can be used to construct [`crate::Opcode`]
pub const fn parse_word(word: Word) -> (Instruction, Instruction) {
// Assumes Word is u64
// https://doc.rust-lang.org/nightly/reference/expressions/operator-expr.html#numeric-cast4
Expand All @@ -137,6 +137,51 @@ impl Instruction {

(Instruction::new(hi), Instruction::new(lo))
}

/// Convert the instruction into its internal representation
///
/// `(repr, $ra, $rb, $rc, $rd, immediate)`
pub const fn into_inner(
self,
) -> (
OpcodeRepr,
RegisterId,
RegisterId,
RegisterId,
RegisterId,
Word,
) {
let Self {
op,
ra,
rb,
rc,
rd,
imm06,
imm12,
imm18,
imm24,
} = self;

let repr = OpcodeRepr::from_u8(op);

let _ = imm06;
let imm12 = imm12 as Word;
let imm18 = imm18 as Word;
let imm24 = imm24 as Word;

let imm12_mask = (op & 0xf0 == 0x50) || (op & 0xf0 == 0x60);
let imm18_mask = (op & 0xf0 == 0x70) || (op & 0xf0 == 0x80);
let imm24_mask = (op & 0xf0 == 0x90) || (op & 0xf0 == 0xa0);

let imm12_mask = imm12_mask as Word;
let imm18_mask = imm18_mask as Word;
let imm24_mask = imm24_mask as Word;

let imm = imm12 * imm12_mask + imm18 * imm18_mask + imm24 * imm24_mask;

(repr, ra, rb, rc, rd, imm)
}
}

impl From<u32> for Instruction {
Expand All @@ -159,7 +204,9 @@ impl From<Instruction> for u32 {
let imm18 = parsed.imm18 as u32;
let imm24 = parsed.imm24 as u32;

let args = match OpcodeRepr::from_u8(parsed.op) {
let repr = OpcodeRepr::from_u8(parsed.op);

let args = match repr {
OpcodeRepr::ADD
| OpcodeRepr::AND
| OpcodeRepr::DIV
Expand All @@ -184,6 +231,7 @@ impl From<Instruction> for u32 {
| OpcodeRepr::ECR
| OpcodeRepr::K256
| OpcodeRepr::S256 => a | b | c,

OpcodeRepr::ADDI
| OpcodeRepr::ANDI
| OpcodeRepr::DIVI
Expand All @@ -200,6 +248,7 @@ impl From<Instruction> for u32 {
| OpcodeRepr::LW
| OpcodeRepr::SB
| OpcodeRepr::SW => a | b | imm12,

OpcodeRepr::MOVE
| OpcodeRepr::NOT
| OpcodeRepr::CTMV
Expand All @@ -218,6 +267,7 @@ impl From<Instruction> for u32 {
| OpcodeRepr::XOS
| OpcodeRepr::XWL
| OpcodeRepr::XWS => a | b,

OpcodeRepr::RET
| OpcodeRepr::ALOC
| OpcodeRepr::BHEI
Expand All @@ -226,15 +276,19 @@ impl From<Instruction> for u32 {
| OpcodeRepr::MINT
| OpcodeRepr::RVRT
| OpcodeRepr::FLAG => a,

OpcodeRepr::JI | OpcodeRepr::CFEI | OpcodeRepr::CFSI => imm24,

OpcodeRepr::MCLI | OpcodeRepr::GM => a | imm18,

OpcodeRepr::MEQ
| OpcodeRepr::CALL
| OpcodeRepr::CCP
| OpcodeRepr::LOG
| OpcodeRepr::LOGD
| OpcodeRepr::TRO => a | b | c | d,
OpcodeRepr::NOOP | OpcodeRepr::UNDEFINED => 0,

_ => 0,
};

((parsed.op as u32) << 24) | args
Expand Down
2 changes: 1 addition & 1 deletion fuel-asm/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,4 +8,4 @@ mod opcode;

pub use fuel_types::{Immediate06, Immediate12, Immediate18, Immediate24, RegisterId, Word};
pub use instruction::Instruction;
pub use opcode::Opcode;
pub use opcode::{Opcode, OpcodeRepr};
101 changes: 93 additions & 8 deletions fuel-asm/src/opcode.rs
Original file line number Diff line number Diff line change
@@ -1,15 +1,15 @@
use fuel_types::{Immediate12, Immediate18, Immediate24, RegisterId};
use fuel_types::{Immediate12, Immediate18, Immediate24, RegisterId, Word};

use core::convert::TryFrom;

use consts::*;

#[cfg(feature = "std")]
use std::{io, iter};

use crate::Instruction;

pub mod consts;
mod consts;

pub use consts::OpcodeRepr;

#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
#[cfg_attr(
Expand Down Expand Up @@ -945,9 +945,9 @@ pub enum Opcode {
///
/// 1. All [OutputContract](../protocol/tx_format.md#outputcontract) outputs
/// will have the same `amount` and `stateRoot` as on initialization. 1.
/// All [OutputVariable](../protocol/tx_format.md outputs#outputvariable)
/// All OutputVariable (../protocol/tx_format.md outputs#outputvariable)
/// outputs will have `to` and `amount` of zero.
/// 1. All [OutputContractConditional](../protocol/tx_format.md#
/// 1. All OutputContractConditional (../protocol/tx_format.md#
/// outputcontractconditional) outputs will have `contractID`, `amount`, and
/// `stateRoot` of zero.
RVRT(RegisterId),
Expand Down Expand Up @@ -1268,9 +1268,9 @@ impl Opcode {
let imm18 = instruction.imm18();
let imm24 = instruction.imm24();

let op = OpcodeRepr::from_u8(op);
let repr = OpcodeRepr::from_u8(op);

match op {
match repr {
OpcodeRepr::ADD => Opcode::ADD(ra, rb, rc),
OpcodeRepr::ADDI => Opcode::ADDI(ra, rb, imm12),
OpcodeRepr::AND => Opcode::AND(ra, rb, rc),
Expand Down Expand Up @@ -1458,6 +1458,91 @@ impl Opcode {
Self::Undefined => [None; 4],
}
}

/// Return the underlying immediate value, if present
pub const fn immediate(&self) -> Option<Word> {
match self {
Self::ADDI(_, _, imm)
| Self::ANDI(_, _, imm)
| Self::DIVI(_, _, imm)
| Self::EXPI(_, _, imm)
| Self::MODI(_, _, imm)
| Self::MULI(_, _, imm)
| Self::ORI(_, _, imm)
| Self::SLLI(_, _, imm)
| Self::SRLI(_, _, imm)
| Self::SUBI(_, _, imm)
| Self::XORI(_, _, imm)
| Self::JNEI(_, _, imm)
| Self::LB(_, _, imm)
| Self::LW(_, _, imm)
| Self::SB(_, _, imm)
| Self::SW(_, _, imm) => Some(*imm as Word),

Self::MCLI(_, imm) | Self::GM(_, imm) => Some(*imm as Word),

Self::JI(imm) | Self::CFEI(imm) | Self::CFSI(imm) => Some(*imm as Word),

Self::ADD(_, _, _)
| Self::AND(_, _, _)
| Self::DIV(_, _, _)
| Self::EQ(_, _, _)
| Self::EXP(_, _, _)
| Self::GT(_, _, _)
| Self::LT(_, _, _)
| Self::MLOG(_, _, _)
| Self::MROO(_, _, _)
| Self::MOD(_, _, _)
| Self::MOVE(_, _)
| Self::MUL(_, _, _)
| Self::NOT(_, _)
| Self::OR(_, _, _)
| Self::SLL(_, _, _)
| Self::SRL(_, _, _)
| Self::SUB(_, _, _)
| Self::XOR(_, _, _)
| Self::CIMV(_, _, _)
| Self::CTMV(_, _)
| Self::RET(_)
| Self::RETD(_, _)
| Self::ALOC(_)
| Self::MCL(_, _)
| Self::MCP(_, _, _)
| Self::MEQ(_, _, _, _)
| Self::BHSH(_, _)
| Self::BHEI(_)
| Self::BURN(_)
| Self::CALL(_, _, _, _)
| Self::CCP(_, _, _, _)
| Self::CROO(_, _)
| Self::CSIZ(_, _)
| Self::CB(_)
| Self::LDC(_, _, _)
| Self::LOG(_, _, _, _)
| Self::LOGD(_, _, _, _)
| Self::MINT(_)
| Self::RVRT(_)
| Self::SLDC(_, _, _)
| Self::SRW(_, _)
| Self::SRWQ(_, _)
| Self::SWW(_, _)
| Self::SWWQ(_, _)
| Self::TR(_, _, _)
| Self::TRO(_, _, _, _)
| Self::ECR(_, _, _)
| Self::K256(_, _, _)
| Self::S256(_, _, _)
| Self::XIL(_, _)
| Self::XIS(_, _)
| Self::XOL(_, _)
| Self::XOS(_, _)
| Self::XWL(_, _)
| Self::XWS(_, _)
| Self::NOOP
| Self::FLAG(_)
| Self::Undefined => None,
}
}
}

#[cfg(feature = "std")]
Expand Down
Loading

0 comments on commit f4e920f

Please sign in to comment.