Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implement interpreter #26

Merged
merged 14 commits into from
Sep 30, 2023
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
Loading