diff --git a/crates/interpreter/src/frame.rs b/crates/interpreter/src/frame.rs index 93b14dbb..e2899b5a 100644 --- a/crates/interpreter/src/frame.rs +++ b/crates/interpreter/src/frame.rs @@ -2,7 +2,7 @@ use cranelift_entity::SecondaryMap; use sonatina_ir::{module::ModuleCtx, DataFlowGraph, Type, Value, I256}; -use crate::{types, value::EvalValue, ProgramCounter}; +use crate::{types, EvalValue, ProgramCounter}; pub struct Frame { pub ret_addr: ProgramCounter, diff --git a/crates/interpreter/src/lib.rs b/crates/interpreter/src/lib.rs index 440ff657..69190838 100644 --- a/crates/interpreter/src/lib.rs +++ b/crates/interpreter/src/lib.rs @@ -7,3 +7,4 @@ pub mod value; pub use frame::Frame; pub use pc::ProgramCounter; pub use state::State; +pub use value::{EvalResult, EvalValue}; diff --git a/crates/interpreter/src/state.rs b/crates/interpreter/src/state.rs index 127d2fb1..77190188 100644 --- a/crates/interpreter/src/state.rs +++ b/crates/interpreter/src/state.rs @@ -6,10 +6,10 @@ use std::{ use sonatina_ir::{ insn::{BinaryOp, CastOp, UnaryOp}, module::FuncRef, - Block, DataLocationKind, Immediate, InsnData, Module, I256, + Block, DataLocationKind, Immediate, InsnData, Module, }; -use crate::{types, Frame, ProgramCounter}; +use crate::{types, EvalResult, Frame, ProgramCounter}; pub struct State { module: Module, @@ -34,7 +34,7 @@ impl State { } } - pub fn run(mut self) -> Option { + pub fn run(mut self) -> EvalResult { loop { if let Some(arg) = self.step() { return arg; @@ -42,7 +42,7 @@ impl State { } } - pub fn step(&mut self) -> Option> { + pub fn step(&mut self) -> Option { let frame = self.frames.last_mut().unwrap(); let insn = self.pc.insn; let ctx = &self.module.ctx; @@ -205,9 +205,8 @@ impl State { None } Return { args } => { - let arg = args.map(|arg| frame.load(ctx, arg, dfg)); + let mut frame = self.frames.pop().unwrap(); // pop returning frame - let frame = self.frames.pop().unwrap(); // pop returning frame match self.frames.last_mut() { Some(caller_frame) => { // Function epilogue @@ -215,15 +214,23 @@ impl State { self.pc.resume_frame_at(frame.ret_addr); let caller = &self.module.funcs[self.pc.func_ref]; - if let Some(lit) = arg { + if let Some(arg) = *args { + let arg_literal = frame.load(ctx, arg, dfg); let v = caller.dfg.insn_result(self.pc.insn).unwrap(); - caller_frame.map(lit, v); + caller_frame.map(arg_literal, v); } self.pc.next_insn(&caller.layout); None } - None => Some(arg), + None => { + let Some(arg) = *args else { + return Some(EvalResult::Void); + }; + let arg_literal = frame.load(ctx, arg, dfg); + let ty = dfg.value_ty(arg); + Some(EvalResult::from_i256(ctx, arg_literal, ty)) + } } } Gep { args } => { @@ -259,7 +266,6 @@ impl State { #[cfg(test)] mod test { - use sonatina_ir::I256; use sonatina_parser::parser::Parser; use super::*; @@ -288,7 +294,7 @@ mod test { let result = state.run(); - assert_eq!(result.unwrap(), I256::all_one().neg()); + assert_eq!(result.into_i32(), 1i32); } #[test] @@ -309,7 +315,7 @@ mod test { let result = state.run(); - assert_eq!(result.unwrap(), (-3).into()); + assert_eq!(result.into_i16(), -3i16); } #[test] @@ -327,9 +333,7 @@ mod test { let result = state.run(); - const NEG_128: i16 = i16::from_be_bytes([0xff, 0x80]); - - assert_eq!(result.unwrap(), NEG_128.into()); + assert_eq!(result.into_i16(), -128i16); } #[test] @@ -347,9 +351,7 @@ mod test { let elem_ptr = state.run(); - let result = i16::from_be_bytes([0x0, 0x80]); - - assert_eq!(elem_ptr.unwrap(), result.into()); + assert_eq!(elem_ptr.into_i16(), 128i16); } #[test] @@ -369,7 +371,7 @@ mod test { let data = state.run(); - assert_eq!(data.unwrap(), 1.into()); + assert_eq!(data.into_i32(), 1i32); } #[test] @@ -396,7 +398,7 @@ mod test { let data = state.run(); - assert_eq!(data.unwrap(), 0.into()); + assert_eq!(data.into_i8(), 0i8); } #[test] @@ -415,9 +417,9 @@ mod test { let state = parse_module_make_state(input); - let boolean = state.run().unwrap(); + let boolean = state.run(); - assert_eq!(boolean, I256::zero()) + assert!(!boolean.into_bool()) } #[test] @@ -436,9 +438,9 @@ mod test { let state = parse_module_make_state(input); - let result = state.run().unwrap(); + let result = state.run(); - assert_eq!(result, 1.into()); + assert_eq!(result.into_i8(), 1i8); } #[test] @@ -459,9 +461,9 @@ mod test { let state = parse_module_make_state(input); - let result = state.run().unwrap(); + let result = state.run(); - assert_eq!(result, 2.into()); + assert_eq!(result.into_i64(), 2i64); } #[test] @@ -481,9 +483,9 @@ mod test { let state = parse_module_make_state(input); - let result = state.run().unwrap(); + let result = state.run(); - assert_eq!(result, (-1).into()); + assert_eq!(result.into_i8(), -1i8); } #[test] @@ -504,7 +506,7 @@ mod test { let elem_ptr = state.run(); - assert_eq!(elem_ptr.unwrap(), 12.into()); + assert_eq!(elem_ptr.into_usize(), 12usize); } #[test] @@ -523,7 +525,7 @@ mod test { let arg = state.run(); - assert!(arg.is_none()); + arg.into_void(); } #[cfg(target_arch = "aarch64")] @@ -543,7 +545,7 @@ mod test { let elem_ptr = state.run(); - assert_eq!(elem_ptr.unwrap(), 16.into()); + assert_eq!(elem_ptr.into_usize(), 16usize); } #[test] @@ -564,6 +566,6 @@ mod test { let elem_ptr = state.run(); - assert_eq!(elem_ptr.unwrap(), 11.into()); + assert_eq!(elem_ptr.into_usize(), 11usize); } } diff --git a/crates/interpreter/src/value.rs b/crates/interpreter/src/value.rs index a94eee21..d108845c 100644 --- a/crates/interpreter/src/value.rs +++ b/crates/interpreter/src/value.rs @@ -17,10 +17,10 @@ impl EvalValue { } pub fn i256(&self) -> I256 { - match self { - Self::Literal(i256) => *i256, - _ => panic!(), - } + let Self::Literal(i256) = *self else { + panic!("undefined"); + }; + i256 } pub fn deserialize(ctx: &ModuleCtx, ty: Type, b: Vec) -> Option { @@ -64,3 +64,97 @@ impl EvalValue { } } } + +pub enum EvalResult { + I1(bool), + I8(i8), + I16(i16), + I32(i32), + I64(i64), + I128(i128), + I256(I256), + Void, + Addr(usize), +} + +impl EvalResult { + pub fn from_i256(ctx: &ModuleCtx, i256: I256, ty: Type) -> Self { + use EvalResult::*; + match ty { + Type::I1 => I1(i256.trunc_to_i1()), + Type::I8 => I8(i256.trunc_to_i8()), + Type::I16 => I16(i256.trunc_to_i16()), + Type::I32 => I32(i256.trunc_to_i32()), + Type::I64 => I64(i256.trunc_to_i64()), + Type::I128 => I128(i256.trunc_to_i128()), + Type::I256 => I256(i256), + Type::Compound(_) => { + debug_assert!(ctx.with_ty_store(|s| s.is_ptr(ty))); + Addr(i256.to_u256().as_usize()) + } + _ => unreachable!(), + } + } + + pub fn into_bool(self) -> bool { + let Self::I1(boolean) = self else { + panic!("not a boolean") + }; + boolean + } + + pub fn into_i8(self) -> i8 { + let Self::I8(i8) = self else { + panic!("not an i8") + }; + i8 + } + + pub fn into_i16(self) -> i16 { + let Self::I16(i16) = self else { + panic!("not an i16") + }; + i16 + } + + pub fn into_i32(self) -> i32 { + let Self::I32(i32) = self else { + panic!("not an i32") + }; + i32 + } + + pub fn into_i64(self) -> i64 { + let Self::I64(i64) = self else { + panic!("not an i64") + }; + i64 + } + + pub fn into_i128(self) -> i128 { + let Self::I128(i128) = self else { + panic!("not an i128") + }; + i128 + } + + pub fn into_i256(self) -> I256 { + let Self::I256(i256) = self else { + panic!("not an i256") + }; + i256 + } + + pub fn into_void(self) { + let Self::Void = self else { + panic!("not a void") + }; + } + + pub fn into_usize(self) -> usize { + let Self::Addr(usize) = self else { + panic!("not a memory address") + }; + usize + } +} diff --git a/crates/ir/src/bigint.rs b/crates/ir/src/bigint.rs index 112ccbeb..0e00fb98 100644 --- a/crates/ir/src/bigint.rs +++ b/crates/ir/src/bigint.rs @@ -80,7 +80,6 @@ impl I256 { } pub fn trunc_to_i8(self) -> i8 { - println!("{:?}", self.to_u256().low_u32() as i8); self.to_u256().low_u32() as i8 }