From 1f1cb0eaf9ffeb42c89fff34caf1dbf5386cabff Mon Sep 17 00:00:00 2001 From: Yoshitomo Nakanishi Date: Sun, 13 Oct 2024 11:21:30 +0200 Subject: [PATCH 1/2] Add `IntToPtr` inst --- crates/interpreter/src/lib.rs | 104 ++++++++++++++--------------- crates/ir/src/inst/cast.rs | 8 +++ crates/ir/src/inst/evm/inst_set.rs | 1 + crates/ir/src/inst/inst_set.rs | 1 + crates/ir/src/interpret/cast.rs | 23 ++++++- crates/ir/src/interpret/data.rs | 2 +- crates/ir/src/interpret/mod.rs | 1 + crates/ir/src/isa/evm.rs | 13 ++-- crates/ir/src/value.rs | 2 +- crates/parser/src/inst/cast.rs | 1 + 10 files changed, 96 insertions(+), 60 deletions(-) diff --git a/crates/interpreter/src/lib.rs b/crates/interpreter/src/lib.rs index 4faf39de..665318a5 100644 --- a/crates/interpreter/src/lib.rs +++ b/crates/interpreter/src/lib.rs @@ -3,7 +3,7 @@ pub mod machine; #[cfg(test)] mod tests { use machine::Machine; - use sonatina_ir::{module::FuncRef, Module}; + use sonatina_ir::{module::FuncRef, Immediate, Module, Type}; use super::*; @@ -232,68 +232,68 @@ mod tests { assert_eq!(result.as_imm().unwrap().as_i256().trunc_to_i8(), -1); } - // #[test] - // fn gep() { - // let input = " - // target = \"evm-ethereum-london\" - - // type %s1 = {i32, i64, i1}; - - // func private %test() -> *i1 { - // block0: - // v0.*%s1 = alloca %s1; - // v1.*i1 = gep v0 2.i8; - // return v1; - // } - // "; - - // let state = parse_module_make_state(input); + #[test] + fn gep() { + let input = " + target = \"evm-ethereum-london\" - // let elem_ptr = state.run(); + type @s1 = {i32, i64, i1}; - // assert_eq!(elem_ptr.into_usize(), 12usize); - // } + func private %test(v0.i256) -> *i1 { + block0: + v1.*@s1 = int_to_ptr v0 *@s1; + v2.*i1 = gep v1 0.i256 2.i256; + return v2; + } + "; - // #[cfg(target_arch = "aarch64")] - // #[test] - // fn gep_ptr_ty() { - // let input = " - // target = \"evm-ethereum-london\" + let (mut machine, funcs) = setup(input); + let arg = Immediate::zero(Type::I256); + let result = machine.run(funcs[0], vec![arg.into()]); - // func private %test() -> **i32 { - // block0: - // v0.*[*i32; 3] = alloca [*i32; 3]; - // v1.**i32 = gep v0 2.i8; - // return v1; - // } - // "; + assert_eq!(result.as_imm().unwrap().as_i256().trunc_to_i64(), 12); + } - // let state = parse_module_make_state(input); + #[cfg(target_arch = "aarch64")] + #[test] + fn gep_ptr_ty() { + let input = " + target = \"evm-ethereum-london\" - // let elem_ptr = state.run(); + func private %test(v0.i256) -> **i32 { + block0: + v1.*[*i32; 3] = int_to_ptr v0 *[*i32; 3]; + v2.**i32 = gep v1 0.i256 2.i256; + return v2; + } + "; - // assert_eq!(elem_ptr.into_usize(), 16usize); - // } + let (mut machine, funcs) = setup(input); + let arg = Immediate::zero(Type::I256); + let result = machine.run(funcs[0], vec![arg.into()]); - // #[test] - // fn gep_nested_aggr_ty() { - // let input = " - // target = \"evm-ethereum-london\" + assert_eq!(result.as_imm().unwrap().as_i256().trunc_to_i64(), 64); + } - // type %s1 = {i32, [i16; 3], [i8; 2]}; + #[test] + fn gep_nested_aggr_ty() { + let input = " + target = \"evm-ethereum-london\" - // func private %test() -> *i8 { - // block0: - // v0.*%s1 = alloca %s1; - // v1.*i8 = gep v0 2.i8 1.i8; - // return v1; - // } - // "; + type @s1 = {i32, [i16; 3], [i8; 2]}; - // let state = parse_module_make_state(input); + func private %test(v0.i256) -> *i8 { + block0: + v1.*@s1 = int_to_ptr v0 *@s1; + v2.*i8 = gep v1 0.i256 2.i256 1.i256; + return v2; + } + "; - // let elem_ptr = state.run(); + let (mut machine, funcs) = setup(input); + let arg = Immediate::zero(Type::I256); + let result = machine.run(funcs[0], vec![arg.into()]); - // assert_eq!(elem_ptr.into_usize(), 11usize); - // } + assert_eq!(result.as_imm().unwrap().as_i256().trunc_to_i64(), 11); + } } diff --git a/crates/ir/src/inst/cast.rs b/crates/ir/src/inst/cast.rs index 09ef19a3..efd1a5fd 100644 --- a/crates/ir/src/inst/cast.rs +++ b/crates/ir/src/inst/cast.rs @@ -33,3 +33,11 @@ pub struct Bitcast { ty: Type, } impl_inst_write!(Bitcast, (from: ValueId, ty: Type)); + +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Inst)] +pub struct IntToPtr { + #[inst(value)] + from: ValueId, + ty: Type, +} +impl_inst_write!(IntToPtr, (from: ValueId, ty: Type)); diff --git a/crates/ir/src/inst/evm/inst_set.rs b/crates/ir/src/inst/evm/inst_set.rs index 626bada4..9de95c1b 100644 --- a/crates/ir/src/inst/evm/inst_set.rs +++ b/crates/ir/src/inst/evm/inst_set.rs @@ -19,6 +19,7 @@ pub struct EvmInstSet( cast::Zext, cast::Trunc, cast::Bitcast, + cast::IntToPtr, cmp::Lt, cmp::Gt, cmp::Slt, diff --git a/crates/ir/src/inst/inst_set.rs b/crates/ir/src/inst/inst_set.rs index 9f45f9c3..ed21e31e 100644 --- a/crates/ir/src/inst/inst_set.rs +++ b/crates/ir/src/inst/inst_set.rs @@ -46,6 +46,7 @@ define_inst_set_base! { cast::Zext, cast::Trunc, cast::Bitcast, + cast::IntToPtr, data::Mload, data::Mstore, data::Gep, diff --git a/crates/ir/src/interpret/cast.rs b/crates/ir/src/interpret/cast.rs index 480432e5..7e0b48f1 100644 --- a/crates/ir/src/interpret/cast.rs +++ b/crates/ir/src/interpret/cast.rs @@ -3,9 +3,10 @@ use crate::inst::cast::*; impl Interpret for Sext { fn interpret(&self, state: &mut dyn State) -> EvalValue { + state.set_action(Action::Continue); + let value = state.lookup_val(*self.from()); let ty = self.ty(); - state.set_action(Action::Continue); value.with_imm(|value| value.sext(*ty)) } @@ -13,9 +14,10 @@ impl Interpret for Sext { impl Interpret for Zext { fn interpret(&self, state: &mut dyn State) -> EvalValue { + state.set_action(Action::Continue); + let value = state.lookup_val(*self.from()); let ty = self.ty(); - state.set_action(Action::Continue); value.with_imm(|value| value.zext(*ty)) } @@ -30,3 +32,20 @@ impl Interpret for Trunc { value.with_imm(|value| value.trunc(*ty)) } } + +impl Interpret for IntToPtr { + fn interpret(&self, state: &mut dyn State) -> EvalValue { + state.set_action(Action::Continue); + let value = state.lookup_val(*self.from()); + let ty = self.ty(); + + value.with_imm(|value| { + let target_repr = state.dfg().ctx.type_layout.pointer_repl(); + if *ty > target_repr { + value.trunc(target_repr) + } else { + value.zext(target_repr) + } + }) + } +} diff --git a/crates/ir/src/interpret/data.rs b/crates/ir/src/interpret/data.rs index 73d4fef2..31c8d0dc 100644 --- a/crates/ir/src/interpret/data.rs +++ b/crates/ir/src/interpret/data.rs @@ -76,7 +76,7 @@ impl Interpret for Gep { CompoundTypeData::Struct(s) => { let mut local_offset = 0; - for i in 0..idx_value.saturating_sub(1) { + for i in 0..idx_value { let field_ty = s.fields[i]; let size = state.dfg().ctx.size_of(field_ty); let align = state.dfg().ctx.align_of(field_ty); diff --git a/crates/ir/src/interpret/mod.rs b/crates/ir/src/interpret/mod.rs index c3399b7d..c289dc17 100644 --- a/crates/ir/src/interpret/mod.rs +++ b/crates/ir/src/interpret/mod.rs @@ -31,6 +31,7 @@ pub trait Interpret { inst::cast::Sext, inst::cast::Zext, inst::cast::Trunc, + inst::cast::IntToPtr, inst::cmp::Lt, inst::cmp::Gt, inst::cmp::Slt, diff --git a/crates/ir/src/isa/evm.rs b/crates/ir/src/isa/evm.rs index 651c54ba..6c42a95a 100644 --- a/crates/ir/src/isa/evm.rs +++ b/crates/ir/src/isa/evm.rs @@ -39,6 +39,15 @@ struct EvmTypeLayout {} impl TypeLayout for EvmTypeLayout { fn size_of(&self, ty: crate::Type, ctx: &ModuleCtx) -> usize { match ty { + Type::Unit => 0, + Type::I1 => 1, + Type::I8 => 1, + Type::I16 => 2, + Type::I32 => 4, + Type::I64 => 8, + Type::I128 => 16, + Type::I256 => 32, + Type::Compound(cmpd) => { let cmpd_data = ctx.with_ty_store(|s| s.resolve_compound(cmpd).clone()); match cmpd_data { @@ -60,10 +69,6 @@ impl TypeLayout for EvmTypeLayout { } } } - - Type::Unit => 0, - - _ => 32, } } diff --git a/crates/ir/src/value.rs b/crates/ir/src/value.rs index 012e5a43..a2053850 100644 --- a/crates/ir/src/value.rs +++ b/crates/ir/src/value.rs @@ -135,7 +135,7 @@ impl Immediate { Self::I32(val) => (val as u32).into(), Self::I64(val) => (val as u64).into(), Self::I128(val) => (val as u128).into(), - Self::I256(_) => unreachable!(), + Self::I256(val) => val, }; Self::from_i256(i256, ty) diff --git a/crates/parser/src/inst/cast.rs b/crates/parser/src/inst/cast.rs index 2cd106d3..a7e6afb5 100644 --- a/crates/parser/src/inst/cast.rs +++ b/crates/parser/src/inst/cast.rs @@ -4,3 +4,4 @@ super::impl_inst_build! {Sext, has_sext, (from: ValueId, ty: Type)} super::impl_inst_build! {Zext, has_zext, (from: ValueId, ty: Type)} super::impl_inst_build! {Trunc, has_trunc, (from: ValueId, ty: Type)} super::impl_inst_build! {Bitcast, has_bitcast, (from: ValueId, ty: Type)} +super::impl_inst_build! {IntToPtr, has_int_to_ptr, (from: ValueId, ty: Type)} From 22720cc651ee6fdd898d0283f8a19870b4a86be6 Mon Sep 17 00:00:00 2001 From: Yoshitomo Nakanishi Date: Sun, 13 Oct 2024 15:47:06 +0200 Subject: [PATCH 2/2] Add `PtrToInt` --- crates/ir/src/inst/cast.rs | 8 ++++++++ crates/ir/src/inst/evm/inst_set.rs | 1 + crates/ir/src/inst/inst_set.rs | 1 + crates/ir/src/interpret/cast.rs | 25 +++++++++++++++++++++---- crates/ir/src/interpret/mod.rs | 1 + crates/parser/src/inst/cast.rs | 1 + 6 files changed, 33 insertions(+), 4 deletions(-) diff --git a/crates/ir/src/inst/cast.rs b/crates/ir/src/inst/cast.rs index efd1a5fd..fb6b54c4 100644 --- a/crates/ir/src/inst/cast.rs +++ b/crates/ir/src/inst/cast.rs @@ -41,3 +41,11 @@ pub struct IntToPtr { ty: Type, } impl_inst_write!(IntToPtr, (from: ValueId, ty: Type)); + +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Inst)] +pub struct PtrToInt { + #[inst(value)] + from: ValueId, + ty: Type, +} +impl_inst_write!(PtrToInt, (from: ValueId, ty: Type)); diff --git a/crates/ir/src/inst/evm/inst_set.rs b/crates/ir/src/inst/evm/inst_set.rs index 9de95c1b..21a5f6cf 100644 --- a/crates/ir/src/inst/evm/inst_set.rs +++ b/crates/ir/src/inst/evm/inst_set.rs @@ -20,6 +20,7 @@ pub struct EvmInstSet( cast::Trunc, cast::Bitcast, cast::IntToPtr, + cast::PtrToInt, cmp::Lt, cmp::Gt, cmp::Slt, diff --git a/crates/ir/src/inst/inst_set.rs b/crates/ir/src/inst/inst_set.rs index ed21e31e..258e212b 100644 --- a/crates/ir/src/inst/inst_set.rs +++ b/crates/ir/src/inst/inst_set.rs @@ -47,6 +47,7 @@ define_inst_set_base! { cast::Trunc, cast::Bitcast, cast::IntToPtr, + cast::PtrToInt, data::Mload, data::Mstore, data::Gep, diff --git a/crates/ir/src/interpret/cast.rs b/crates/ir/src/interpret/cast.rs index 7e0b48f1..7e577548 100644 --- a/crates/ir/src/interpret/cast.rs +++ b/crates/ir/src/interpret/cast.rs @@ -40,11 +40,28 @@ impl Interpret for IntToPtr { let ty = self.ty(); value.with_imm(|value| { - let target_repr = state.dfg().ctx.type_layout.pointer_repl(); - if *ty > target_repr { - value.trunc(target_repr) + let ptr_repr = state.dfg().ctx.type_layout.pointer_repl(); + if *ty > ptr_repr { + value.trunc(ptr_repr) } else { - value.zext(target_repr) + value.zext(ptr_repr) + } + }) + } +} + +impl Interpret for PtrToInt { + fn interpret(&self, state: &mut dyn State) -> EvalValue { + state.set_action(Action::Continue); + let value = state.lookup_val(*self.from()); + let ty = self.ty(); + + value.with_imm(|value| { + let ptr_repr = state.dfg().ctx.type_layout.pointer_repl(); + if *ty > ptr_repr { + value.zext(*ty) + } else { + value.trunc(*ty) } }) } diff --git a/crates/ir/src/interpret/mod.rs b/crates/ir/src/interpret/mod.rs index c289dc17..590f39d9 100644 --- a/crates/ir/src/interpret/mod.rs +++ b/crates/ir/src/interpret/mod.rs @@ -32,6 +32,7 @@ pub trait Interpret { inst::cast::Zext, inst::cast::Trunc, inst::cast::IntToPtr, + inst::cast::PtrToInt, inst::cmp::Lt, inst::cmp::Gt, inst::cmp::Slt, diff --git a/crates/parser/src/inst/cast.rs b/crates/parser/src/inst/cast.rs index a7e6afb5..dc22e8da 100644 --- a/crates/parser/src/inst/cast.rs +++ b/crates/parser/src/inst/cast.rs @@ -5,3 +5,4 @@ super::impl_inst_build! {Zext, has_zext, (from: ValueId, ty: Type)} super::impl_inst_build! {Trunc, has_trunc, (from: ValueId, ty: Type)} super::impl_inst_build! {Bitcast, has_bitcast, (from: ValueId, ty: Type)} super::impl_inst_build! {IntToPtr, has_int_to_ptr, (from: ValueId, ty: Type)} +super::impl_inst_build! {PtrToInt, has_ptr_to_int, (from: ValueId, ty: Type)}