add symbol kinds

Signed-off-by: xermicus <cyrill@parity.io>
This commit is contained in:
xermicus
2023-12-07 22:31:16 +01:00
parent 426ab4b095
commit 80e14f182d
4 changed files with 146 additions and 40 deletions
+1 -5
View File
@@ -6,9 +6,5 @@ fn main() {
let bytecode = hex::decode(hexcode.trim()).unwrap();
let instructions = bytecode.disassemble();
//for instruction in instructions.iter() {
// println!("{instruction:?}");
//}
Program::new(instructions).dot(BasicBlockFormatOption::ByteCode);
Program::new(instructions).dot(BasicBlockFormatOption::Ir);
}
+8
View File
@@ -49,6 +49,14 @@ impl BasicBlock {
writeln!(&mut acc, "{:?}", opcode.instruction).unwrap();
acc
}),
BasicBlockFormatOption::Ir => {
self.instructions
.iter()
.fold(String::new(), |mut acc, instruction| {
writeln!(&mut acc, "{instruction}").unwrap();
acc
})
}
_ => String::new(),
};
+71 -20
View File
@@ -1,5 +1,6 @@
use evmil::bytecode::Instruction as EvmInstruction;
use primitive_types::U256;
use std::fmt::Write;
use crate::symbol::{Global, Symbol, SymbolTable, Type};
@@ -16,8 +17,8 @@ pub enum Instruction {
/// `x = op y`
UnaryAssign {
x: Symbol,
y: Symbol,
operator: Operator,
y: Symbol,
},
/// `branch target`
@@ -36,7 +37,7 @@ pub enum Instruction {
Function {
symbol: Global,
x: Symbol,
args: Vec<Symbol>,
parameters: Vec<Symbol>,
},
/// `x = y`
@@ -49,6 +50,61 @@ pub enum Instruction {
IndexedCopy { x: Symbol, y: Symbol, index: Symbol },
}
impl Instruction {
fn target_address(&self) -> Symbol {
match self {
Instruction::Copy { x, .. } => *x,
Instruction::IndexedAssign { x, .. } => *x,
Instruction::IndexedCopy { x, .. } => *x,
_ => unreachable!(),
}
}
}
impl std::fmt::Display for Instruction {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
Self::BinaryAssign { x, y, operator, z } => write!(f, "{x} = {y} {operator:?} {z}"),
Self::UnaryAssign { x, operator, y } => write!(f, "{x} = {operator:?} {y} "),
Self::UncoditionalBranch { target } => write!(f, "branch {target}"),
Self::ConditionalBranch { condition, target } => {
write!(f, "if {condition} branch {target}")
}
Self::Procedure { symbol, parameters } => write!(
f,
"{symbol:?}({})",
parameters.iter().fold(String::new(), |mut acc, p| {
write!(&mut acc, "{p}, ").unwrap();
acc
})
),
Self::Function {
symbol,
x,
parameters: args,
} => write!(
f,
"{x} = {symbol:?}({})",
args.iter().fold(String::new(), |mut acc, p| {
write!(&mut acc, "{p}, ").unwrap();
acc
})
),
Self::Copy { x, y } => write!(f, "{x} = {y}"),
Self::IndexedAssign { x, index, y } => write!(f, "{x}[{index}] = {y}"),
Self::IndexedCopy { x, y, index } => write!(f, "{x} = {y}[{index}]"),
}
}
}
#[derive(PartialEq, Debug)]
pub enum Operator {
Add,
@@ -139,17 +195,6 @@ fn increment_stack_height(symbol_table: &mut SymbolTable) -> Instruction {
}
}
impl Instruction {
fn target_address(&self) -> Symbol {
match self {
Instruction::Copy { x, .. } => *x,
Instruction::IndexedAssign { x, .. } => *x,
Instruction::IndexedCopy { x, .. } => *x,
_ => unreachable!(),
}
}
}
/// Lower an EVM instruction into corresponding 3AC instructions.
pub fn translate(opcode: &EvmInstruction, symbol_table: &mut SymbolTable) -> Vec<Instruction> {
use EvmInstruction::*;
@@ -272,7 +317,7 @@ mod tests {
use crate::{
instruction::Operator,
symbol::{Global, Kind, Symbol, Type},
symbol::{Address, Global, Kind, Symbol, Type},
};
use super::Instruction;
@@ -287,31 +332,37 @@ mod tests {
let expected = vec![
Instruction::IndexedAssign {
x: Symbol {
kind: Kind::Label(Global::Stack),
address: Address::Label(Global::Stack),
type_hint: Type::Word,
kind: Global::Stack.kind(),
},
index: Symbol {
kind: Kind::Label(Global::StackHeight),
address: Address::Label(Global::StackHeight),
type_hint: Type::Int(4),
kind: Global::StackHeight.kind(),
},
y: Symbol {
kind: Kind::Constant(U256::one()),
address: Address::Constant(U256::one()),
type_hint: Type::Bytes(1),
kind: Kind::Value,
},
},
Instruction::BinaryAssign {
x: Symbol {
kind: Kind::Label(Global::StackHeight),
address: Address::Label(Global::StackHeight),
type_hint: Type::Int(4),
kind: Global::StackHeight.kind(),
},
y: Symbol {
kind: Kind::Label(Global::StackHeight),
address: Address::Label(Global::StackHeight),
type_hint: Type::Int(4),
kind: Global::StackHeight.kind(),
},
operator: Operator::Add,
z: Symbol {
kind: Kind::Constant(U256::one()),
address: Address::Constant(U256::one()),
type_hint: Type::Int(4),
kind: Kind::Value,
},
},
];
+66 -15
View File
@@ -2,13 +2,23 @@ use indexmap::IndexSet;
use primitive_types::U256;
#[derive(Debug, PartialEq, Eq, Hash, Clone, Copy)]
pub enum Kind {
pub enum Address {
Constant(U256),
Temporary(usize),
Label(Global),
}
impl Kind {
impl std::fmt::Display for Address {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
Self::Constant(value) => write!(f, "{value:02x}"),
Self::Temporary(n) => write!(f, "tmp_{n}"),
Self::Label(label) => write!(f, "{label:?}"),
}
}
}
impl Address {
pub fn from_be_bytes(bytes: &[u8]) -> Self {
Self::Constant(U256::from_big_endian(bytes))
}
@@ -16,8 +26,15 @@ impl Kind {
#[derive(Debug, PartialEq, Eq, Hash, Clone, Copy)]
pub struct Symbol {
pub kind: Kind,
pub address: Address,
pub type_hint: Type,
pub kind: Kind,
}
impl std::fmt::Display for Symbol {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "({}) {}", self.type_hint, self.address)
}
}
impl Symbol {
@@ -27,11 +44,15 @@ impl Symbol {
_ => Default::default(),
};
Self::new(Kind::Label(symbol), type_hint)
Self::new(Address::Label(symbol), type_hint, symbol.kind())
}
fn new(kind: Kind, type_hint: Type) -> Self {
Self { kind, type_hint }
fn new(address: Address, type_hint: Type, kind: Kind) -> Self {
Self {
address,
type_hint,
kind,
}
}
}
@@ -44,30 +65,42 @@ pub enum Type {
Bool,
}
impl std::fmt::Display for Type {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
Self::Word => write!(f, "word"),
Self::Int(size) => write!(f, "int{}", size * 8),
Self::Bytes(size) => write!(f, "bytes{size}"),
Self::Bool => write!(f, "bool"),
}
}
}
impl Type {
pub fn pointer() -> Self {
Self::Int(4)
}
}
#[derive(Debug, PartialEq, Eq, Hash, Clone, Copy)]
pub enum Kind {
Pointer,
Value,
Function,
}
#[derive(Debug, PartialEq, Eq, Hash, Clone, Copy)]
pub enum Global {
/// Pointer
Stack,
/// Stack height variable
StackHeight,
/// Pointer
CallData,
/// Pointer
Memory,
/// Pointer
ReturnData,
/// Low level `memcpy` like function
MemoryCopy,
// EVM
// EVM runtime environment
Sha3,
Address,
CallDataLoad,
@@ -106,6 +139,16 @@ pub enum Global {
Event,
}
impl Global {
pub fn kind(&self) -> Kind {
match self {
Self::Stack | Self::CallData | Self::Memory | Self::ReturnData => Kind::Pointer,
Self::StackHeight => Kind::Value,
_ => Kind::Function,
}
}
}
#[derive(Debug, Default)]
pub struct SymbolTable {
symbols: IndexSet<Symbol>,
@@ -121,14 +164,22 @@ impl SymbolTable {
pub fn temporary(&mut self, type_hint: Option<Type>) -> Symbol {
let id = self.next();
let symbol = Symbol::new(Kind::Temporary(id), type_hint.unwrap_or_default());
let symbol = Symbol::new(
Address::Temporary(id),
type_hint.unwrap_or_default(),
Kind::Value,
);
assert!(self.symbols.insert(symbol));
symbol
}
pub fn constant(&mut self, value: U256, type_hint: Option<Type>) -> Symbol {
let symbol = Symbol::new(Kind::Constant(value), type_hint.unwrap_or_default());
let symbol = Symbol::new(
Address::Constant(value),
type_hint.unwrap_or_default(),
Kind::Value,
);
self.symbols.insert(symbol);
symbol