Skip to content

Commit

Permalink
Merge pull request #26 from k0aki/interpreter
Browse files Browse the repository at this point in the history
Implement interpreter
  • Loading branch information
Y-Nak authored Sep 30, 2023
2 parents 963ecd8 + 77132d6 commit d2c9ed0
Show file tree
Hide file tree
Showing 12 changed files with 993 additions and 2 deletions.
2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
[workspace]
members = ["crates/ir", "crates/codegen", "crates/object", "crates/parser", "crates/filecheck", "crates/triple"]
members = ["crates/ir", "crates/codegen", "crates/object", "crates/parser", "crates/filecheck", "crates/triple", "crates/interpreter"]
22 changes: 22 additions & 0 deletions crates/interpreter/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
[package]
name = "sonatina-interpreter"
version = "0.0.3-alpha"
edition = "2021"
authors = ["Sonatina Developers"]
license = "Apache-2.0"
readme = "../../README.md"
homepage = "https://github.com/fe-lang/sonatina/tree/main/crates/interpreter"
repository = "https://github.com/fe-lang/sonatina"
description = "Interpreter of sonatina intermediate representation"
categories = ["compilers", "wasm"]
keywords = ["compiler", "evm", "wasm", "smart-contract"]

# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html

[dependencies]
byteorder = { version = "1.4.3", default-features = false }
cranelift-entity = "0.100"
sonatina-ir = { path = "../ir", version = "0.0.3-alpha" }

[dev-dependencies]
sonatina-parser = { path = "../parser", version = "0.0.3-alpha" }
86 changes: 86 additions & 0 deletions crates/interpreter/src/frame.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
use cranelift_entity::{packed_option::PackedOption, SecondaryMap};

use sonatina_ir::{module::ModuleCtx, DataFlowGraph, Type, Value, I256};

use crate::{types, EvalValue, ProgramCounter};

#[derive(Default)]
pub struct Frame {
pub ret_addr: PackedOption<ProgramCounter>,
local_values: SecondaryMap<Value, EvalValue>, // 256-bit register
alloca_region: Vec<u8>, // big endian
}

impl Frame {
pub fn new() -> Self {
Self::default()
}

pub fn set_ret_addr(&mut self, ret_addr: ProgramCounter) {
self.ret_addr = ret_addr.into();
}

pub fn load_args(&mut self, args: &[Value], arg_literals: impl Iterator<Item = I256>) {
for (v, literal_value) in args.iter().zip(arg_literals) {
self.local_values[*v] = EvalValue::from_i256(literal_value)
}
}

pub fn load(&mut self, v: Value, dfg: &DataFlowGraph) -> I256 {
if !self.is_assigned(v) {
if let Some(gv) = dfg.value_gv(v) {
dfg.ctx.with_gv_store(|s| {
if !s.is_const(gv) {
todo!()
}
})
}
let i256 = dfg.value_imm(v).unwrap().as_i256();
self.local_values[v] = EvalValue::from_i256(i256);
}
self.local_values[v].i256()
}

pub fn map(&mut self, literal: I256, v: Value) {
debug_assert!(!self.is_assigned(v));
self.local_values[v] = EvalValue::from_i256(literal)
}

pub fn alloca(&mut self, ctx: &ModuleCtx, ty: Type, v: Value) {
debug_assert!(!self.is_assigned(v));

let addr = self.alloca_region.len();

let size = types::size_of_ty_data(ctx, ty);
self.alloca_region.resize(addr + size, 0);
self.local_values[v] = EvalValue::from_usize(addr);
}

pub fn ldr(&mut self, ctx: &ModuleCtx, addr: I256, v: Value, ty: Type) {
let addr = addr.to_u256().as_usize();
debug_assert!(addr < self.alloca_region.len());

let size = types::size_of_ty_data(ctx, ty);
let literal_b = &self.alloca_region[addr..addr + size];
let Some(data) = EvalValue::deserialize(ctx, ty, literal_b) else {
return;
};
self.map(data.i256(), v);
}

pub fn str(&mut self, ctx: &ModuleCtx, addr: I256, data: I256, ty: Type) {
let addr = addr.to_u256().as_usize();
let size = types::size_of_ty_data(ctx, ty);
let reg_value = EvalValue::from_i256(data);
reg_value.serialize(ctx, ty, &mut self.alloca_region[addr..size]);
}

pub fn is_assigned(&self, v: Value) -> bool {
for (local_v, local) in self.local_values.iter() {
if v == local_v {
return matches!(local, EvalValue::Literal(_));
}
}
false
}
}
10 changes: 10 additions & 0 deletions crates/interpreter/src/lib.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
pub mod frame;
pub mod pc;
pub mod state;
pub mod types;
pub mod value;

pub use frame::Frame;
pub use pc::ProgramCounter;
pub use state::State;
pub use value::{EvalResult, EvalValue};
50 changes: 50 additions & 0 deletions crates/interpreter/src/pc.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
use cranelift_entity::packed_option::ReservedValue;
use sonatina_ir::{module::FuncRef, Block, Insn, Layout};

#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub struct ProgramCounter {
pub func_ref: FuncRef,
pub insn: Insn,
}

impl ReservedValue for ProgramCounter {
fn reserved_value() -> Self {
let func_ref = FuncRef::reserved_value();
let insn = Insn::reserved_value();
ProgramCounter { func_ref, insn }
}

fn is_reserved_value(&self) -> bool {
self.func_ref == FuncRef::reserved_value() && self.insn == Insn::reserved_value()
}
}

impl ProgramCounter {
pub fn new(entry_func: FuncRef, layout: &Layout) -> Self {
let entry = layout.entry_block().unwrap();
let insn = layout.first_insn_of(entry).unwrap();

Self {
func_ref: entry_func,
insn,
}
}

pub fn call(&mut self, callee_ref: FuncRef, callee_layout: &Layout) {
*self = ProgramCounter::new(callee_ref, callee_layout)
}

pub fn next_insn(&mut self, layout: &Layout) {
self.insn = layout.next_insn_of(self.insn).unwrap();
}

pub fn branch_to(&mut self, block: Block, layout: &Layout) {
self.insn = layout.first_insn_of(block).unwrap();
}

pub fn resume_frame_at(&mut self, ret_addr: Self) {
let ProgramCounter { func_ref, insn } = ret_addr;
self.func_ref = func_ref;
self.insn = insn;
}
}
Loading

0 comments on commit d2c9ed0

Please sign in to comment.