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 bytecode = hex::decode(hexcode.trim()).unwrap();
let instructions = bytecode.disassemble(); let instructions = bytecode.disassemble();
//for instruction in instructions.iter() { Program::new(instructions).dot(BasicBlockFormatOption::Ir);
// println!("{instruction:?}");
//}
Program::new(instructions).dot(BasicBlockFormatOption::ByteCode);
} }
+8
View File
@@ -49,6 +49,14 @@ impl BasicBlock {
writeln!(&mut acc, "{:?}", opcode.instruction).unwrap(); writeln!(&mut acc, "{:?}", opcode.instruction).unwrap();
acc acc
}), }),
BasicBlockFormatOption::Ir => {
self.instructions
.iter()
.fold(String::new(), |mut acc, instruction| {
writeln!(&mut acc, "{instruction}").unwrap();
acc
})
}
_ => String::new(), _ => String::new(),
}; };
+71 -20
View File
@@ -1,5 +1,6 @@
use evmil::bytecode::Instruction as EvmInstruction; use evmil::bytecode::Instruction as EvmInstruction;
use primitive_types::U256; use primitive_types::U256;
use std::fmt::Write;
use crate::symbol::{Global, Symbol, SymbolTable, Type}; use crate::symbol::{Global, Symbol, SymbolTable, Type};
@@ -16,8 +17,8 @@ pub enum Instruction {
/// `x = op y` /// `x = op y`
UnaryAssign { UnaryAssign {
x: Symbol, x: Symbol,
y: Symbol,
operator: Operator, operator: Operator,
y: Symbol,
}, },
/// `branch target` /// `branch target`
@@ -36,7 +37,7 @@ pub enum Instruction {
Function { Function {
symbol: Global, symbol: Global,
x: Symbol, x: Symbol,
args: Vec<Symbol>, parameters: Vec<Symbol>,
}, },
/// `x = y` /// `x = y`
@@ -49,6 +50,61 @@ pub enum Instruction {
IndexedCopy { x: Symbol, y: Symbol, index: Symbol }, 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)] #[derive(PartialEq, Debug)]
pub enum Operator { pub enum Operator {
Add, 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. /// Lower an EVM instruction into corresponding 3AC instructions.
pub fn translate(opcode: &EvmInstruction, symbol_table: &mut SymbolTable) -> Vec<Instruction> { pub fn translate(opcode: &EvmInstruction, symbol_table: &mut SymbolTable) -> Vec<Instruction> {
use EvmInstruction::*; use EvmInstruction::*;
@@ -272,7 +317,7 @@ mod tests {
use crate::{ use crate::{
instruction::Operator, instruction::Operator,
symbol::{Global, Kind, Symbol, Type}, symbol::{Address, Global, Kind, Symbol, Type},
}; };
use super::Instruction; use super::Instruction;
@@ -287,31 +332,37 @@ mod tests {
let expected = vec![ let expected = vec![
Instruction::IndexedAssign { Instruction::IndexedAssign {
x: Symbol { x: Symbol {
kind: Kind::Label(Global::Stack), address: Address::Label(Global::Stack),
type_hint: Type::Word, type_hint: Type::Word,
kind: Global::Stack.kind(),
}, },
index: Symbol { index: Symbol {
kind: Kind::Label(Global::StackHeight), address: Address::Label(Global::StackHeight),
type_hint: Type::Int(4), type_hint: Type::Int(4),
kind: Global::StackHeight.kind(),
}, },
y: Symbol { y: Symbol {
kind: Kind::Constant(U256::one()), address: Address::Constant(U256::one()),
type_hint: Type::Bytes(1), type_hint: Type::Bytes(1),
kind: Kind::Value,
}, },
}, },
Instruction::BinaryAssign { Instruction::BinaryAssign {
x: Symbol { x: Symbol {
kind: Kind::Label(Global::StackHeight), address: Address::Label(Global::StackHeight),
type_hint: Type::Int(4), type_hint: Type::Int(4),
kind: Global::StackHeight.kind(),
}, },
y: Symbol { y: Symbol {
kind: Kind::Label(Global::StackHeight), address: Address::Label(Global::StackHeight),
type_hint: Type::Int(4), type_hint: Type::Int(4),
kind: Global::StackHeight.kind(),
}, },
operator: Operator::Add, operator: Operator::Add,
z: Symbol { z: Symbol {
kind: Kind::Constant(U256::one()), address: Address::Constant(U256::one()),
type_hint: Type::Int(4), type_hint: Type::Int(4),
kind: Kind::Value,
}, },
}, },
]; ];
+66 -15
View File
@@ -2,13 +2,23 @@ use indexmap::IndexSet;
use primitive_types::U256; use primitive_types::U256;
#[derive(Debug, PartialEq, Eq, Hash, Clone, Copy)] #[derive(Debug, PartialEq, Eq, Hash, Clone, Copy)]
pub enum Kind { pub enum Address {
Constant(U256), Constant(U256),
Temporary(usize), Temporary(usize),
Label(Global), 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 { pub fn from_be_bytes(bytes: &[u8]) -> Self {
Self::Constant(U256::from_big_endian(bytes)) Self::Constant(U256::from_big_endian(bytes))
} }
@@ -16,8 +26,15 @@ impl Kind {
#[derive(Debug, PartialEq, Eq, Hash, Clone, Copy)] #[derive(Debug, PartialEq, Eq, Hash, Clone, Copy)]
pub struct Symbol { pub struct Symbol {
pub kind: Kind, pub address: Address,
pub type_hint: Type, 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 { impl Symbol {
@@ -27,11 +44,15 @@ impl Symbol {
_ => Default::default(), _ => 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 { fn new(address: Address, type_hint: Type, kind: Kind) -> Self {
Self { kind, type_hint } Self {
address,
type_hint,
kind,
}
} }
} }
@@ -44,30 +65,42 @@ pub enum Type {
Bool, 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 { impl Type {
pub fn pointer() -> Self { pub fn pointer() -> Self {
Self::Int(4) Self::Int(4)
} }
} }
#[derive(Debug, PartialEq, Eq, Hash, Clone, Copy)]
pub enum Kind {
Pointer,
Value,
Function,
}
#[derive(Debug, PartialEq, Eq, Hash, Clone, Copy)] #[derive(Debug, PartialEq, Eq, Hash, Clone, Copy)]
pub enum Global { pub enum Global {
/// Pointer
Stack, Stack,
/// Stack height variable
StackHeight, StackHeight,
/// Pointer
CallData, CallData,
/// Pointer
Memory, Memory,
/// Pointer
ReturnData, ReturnData,
/// Low level `memcpy` like function
MemoryCopy, MemoryCopy,
// EVM // EVM runtime environment
Sha3, Sha3,
Address, Address,
CallDataLoad, CallDataLoad,
@@ -106,6 +139,16 @@ pub enum Global {
Event, 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)] #[derive(Debug, Default)]
pub struct SymbolTable { pub struct SymbolTable {
symbols: IndexSet<Symbol>, symbols: IndexSet<Symbol>,
@@ -121,14 +164,22 @@ impl SymbolTable {
pub fn temporary(&mut self, type_hint: Option<Type>) -> Symbol { pub fn temporary(&mut self, type_hint: Option<Type>) -> Symbol {
let id = self.next(); 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)); assert!(self.symbols.insert(symbol));
symbol symbol
} }
pub fn constant(&mut self, value: U256, type_hint: Option<Type>) -> 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); self.symbols.insert(symbol);
symbol symbol