From 80e14f182dd9a5bc3c781ce297e7d6ab2ff3e7fd Mon Sep 17 00:00:00 2001 From: xermicus Date: Thu, 7 Dec 2023 22:31:16 +0100 Subject: [PATCH] add symbol kinds Signed-off-by: xermicus --- crates/cli/src/main.rs | 6 +-- crates/ir-tac/src/cfg.rs | 8 +++ crates/ir-tac/src/instruction.rs | 91 +++++++++++++++++++++++++------- crates/ir-tac/src/symbol.rs | 81 ++++++++++++++++++++++------ 4 files changed, 146 insertions(+), 40 deletions(-) diff --git a/crates/cli/src/main.rs b/crates/cli/src/main.rs index 3792ed1..c239beb 100644 --- a/crates/cli/src/main.rs +++ b/crates/cli/src/main.rs @@ -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); } diff --git a/crates/ir-tac/src/cfg.rs b/crates/ir-tac/src/cfg.rs index 5e0b913..742b7dc 100644 --- a/crates/ir-tac/src/cfg.rs +++ b/crates/ir-tac/src/cfg.rs @@ -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(), }; diff --git a/crates/ir-tac/src/instruction.rs b/crates/ir-tac/src/instruction.rs index 94f2ad5..93f8e3d 100644 --- a/crates/ir-tac/src/instruction.rs +++ b/crates/ir-tac/src/instruction.rs @@ -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, + parameters: Vec, }, /// `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 { 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, }, }, ]; diff --git a/crates/ir-tac/src/symbol.rs b/crates/ir-tac/src/symbol.rs index 46e2aab..3df2fd1 100644 --- a/crates/ir-tac/src/symbol.rs +++ b/crates/ir-tac/src/symbol.rs @@ -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, @@ -121,14 +164,22 @@ impl SymbolTable { pub fn temporary(&mut self, type_hint: Option) -> 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) -> 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