Skip to content

Commit

Permalink
Add EvmSdiv/EvmUdiv
Browse files Browse the repository at this point in the history
  • Loading branch information
Y-Nak committed Nov 16, 2024
1 parent d89b1b0 commit 45acf8b
Show file tree
Hide file tree
Showing 12 changed files with 224 additions and 8 deletions.
4 changes: 2 additions & 2 deletions crates/filecheck/fixtures/adce/all_dests_remove.sntn
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ func public %all_dests_removed() -> i8 {
jump block3;

block2:
v4.i8 = sdiv v0 2.i8;
v4.i8 = evm_sdiv v0 2.i8;
v5.i8 = sext v1 i8;
v6.i8 = add v1 v5;
jump block3;
Expand All @@ -44,7 +44,7 @@ func public %all_dests_removed2(v0.i8) -> i8 {
jump block3;

block2:
v4.i8 = sdiv v0 2.i8;
v4.i8 = evm_sdiv v0 2.i8;
v5.i8 = sext v1 i8;
v6.i8 = add v1 v5;
jump block3;
Expand Down
2 changes: 1 addition & 1 deletion crates/filecheck/fixtures/adce/simple_dce.sntn
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,6 @@ target = "evm-ethereum-london"
func public %simple(v0.i8) -> i8 {
block0:
v1.i8 = sub v0 1.i8;
v2.i8 = udiv v1 v0;
v2.i8 = evm_udiv v1 v0;
return 2.i8;
}
17 changes: 17 additions & 0 deletions crates/ir/src/bigint.rs
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,23 @@ impl I256 {
}
}

pub fn overflowing_rem(self, rhs: I256) -> (I256, bool) {
if rhs.is_zero() {
panic!("attempt to divide by zero");
}

if self.is_minimum() && rhs.is_negative && rhs.abs == U256::one() {
return (I256::zero(), true);
}

let rem_abs = self.abs % rhs.abs;

match self.is_negative {
true => (I256::make_negative(rem_abs), false),
false => (I256::make_positive(rem_abs), false),
}
}

pub fn from_be_bytes(bytes: &[u8]) -> Self {
let u256_val = U256::from_big_endian(bytes);
Self::from_u256(u256_val)
Expand Down
8 changes: 4 additions & 4 deletions crates/ir/src/inst/evm/inst_set.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,6 @@ pub struct EvmInstSet(
arith::Add,
arith::Mul,
arith::Sub,
arith::Sdiv,
arith::Udiv,
arith::Umod,
arith::Smod,
arith::Shl,
arith::Shr,
arith::Sar,
Expand Down Expand Up @@ -45,6 +41,10 @@ pub struct EvmInstSet(
logic::And,
logic::Or,
logic::Xor,
evm::EvmSdiv,
evm::EvmUdiv,
evm::EvmUmod,
evm::EvmSmod,
evm::EvmStop,
evm::EvmAddMod,
evm::EvmMulMod,
Expand Down
36 changes: 36 additions & 0 deletions crates/ir/src/inst/evm/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,42 @@ pub mod inst_set;

use crate::{inst::impl_inst_write, value::ValueId};

#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Inst)]
pub struct EvmUdiv {
#[inst(value)]
lhs: ValueId,
#[inst(value)]
rhs: ValueId,
}
impl_inst_write!(EvmUdiv);

#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Inst)]
pub struct EvmSdiv {
#[inst(value)]
lhs: ValueId,
#[inst(value)]
rhs: ValueId,
}
impl_inst_write!(EvmSdiv);

#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Inst)]
pub struct EvmUmod {
#[inst(value)]
lhs: ValueId,
#[inst(value)]
rhs: ValueId,
}
impl_inst_write!(EvmUmod);

#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Inst)]
pub struct EvmSmod {
#[inst(value)]
lhs: ValueId,
#[inst(value)]
rhs: ValueId,
}
impl_inst_write!(EvmSmod);

#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Inst)]
#[inst(side_effect(crate::inst::SideEffect::Write))]
#[inst(terminator)]
Expand Down
4 changes: 4 additions & 0 deletions crates/ir/src/inst/inst_set.rs
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,10 @@ define_inst_set_base! {
control_flow::Return,
control_flow::Phi,
// Evm specific
evm::EvmUdiv,
evm::EvmSdiv,
evm::EvmUmod,
evm::EvmSmod,
evm::EvmStop,
evm::EvmAddMod,
evm::EvmMulMod,
Expand Down
22 changes: 22 additions & 0 deletions crates/ir/src/interpret/arith.rs
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,28 @@ impl Interpret for Udiv {
}
}

impl Interpret for Umod {
fn interpret(&self, state: &mut dyn State) -> EvalValue {
state.set_action(Action::Continue);

let lhs = state.lookup_val(*self.lhs());
let rhs = state.lookup_val(*self.rhs());

EvalValue::zip_with_imm(lhs, rhs, |lhs, rhs| lhs.urem(rhs))
}
}

impl Interpret for Smod {
fn interpret(&self, state: &mut dyn State) -> EvalValue {
state.set_action(Action::Continue);

let lhs = state.lookup_val(*self.lhs());
let rhs = state.lookup_val(*self.rhs());

EvalValue::zip_with_imm(lhs, rhs, |lhs, rhs| lhs.srem(rhs))
}
}

impl Interpret for Shl {
fn interpret(&self, state: &mut dyn State) -> EvalValue {
state.set_action(Action::Continue);
Expand Down
117 changes: 117 additions & 0 deletions crates/ir/src/interpret/evm/mod.rs
Original file line number Diff line number Diff line change
@@ -1 +1,118 @@
use super::{Action, EvalValue, Interpret, State};
use crate::inst::evm::*;

impl Interpret for EvmUdiv {
fn interpret(&self, state: &mut dyn State) -> EvalValue {
state.set_action(Action::Continue);

let lhs = state.lookup_val(*self.lhs());
let rhs = state.lookup_val(*self.rhs());

EvalValue::zip_with_imm(
lhs,
rhs,
|lhs, rhs| {
if rhs.is_zero() {
rhs
} else {
lhs.udiv(rhs)
}
},
)
}
}

impl Interpret for EvmSdiv {
fn interpret(&self, state: &mut dyn State) -> EvalValue {
state.set_action(Action::Continue);

let lhs = state.lookup_val(*self.lhs());
let rhs = state.lookup_val(*self.rhs());

EvalValue::zip_with_imm(
lhs,
rhs,
|lhs, rhs| {
if rhs.is_zero() {
rhs
} else {
lhs.sdiv(rhs)
}
},
)
}
}

impl Interpret for EvmUmod {
fn interpret(&self, state: &mut dyn State) -> EvalValue {
state.set_action(Action::Continue);

let lhs = state.lookup_val(*self.lhs());
let rhs = state.lookup_val(*self.rhs());

EvalValue::zip_with_imm(
lhs,
rhs,
|lhs, rhs| {
if rhs.is_zero() {
rhs
} else {
lhs.urem(rhs)
}
},
)
}
}

impl Interpret for EvmSmod {
fn interpret(&self, state: &mut dyn State) -> EvalValue {
state.set_action(Action::Continue);

let lhs = state.lookup_val(*self.lhs());
let rhs = state.lookup_val(*self.rhs());

EvalValue::zip_with_imm(
lhs,
rhs,
|lhs, rhs| {
if rhs.is_zero() {
rhs
} else {
lhs.srem(rhs)
}
},
)
}
}

impl Interpret for EvmAddMod {
fn interpret(&self, state: &mut dyn State) -> EvalValue {
state.set_action(Action::Continue);
let lhs = state.lookup_val(*self.lhs());
let rhs = state.lookup_val(*self.rhs());

EvalValue::zip_with_imm(lhs, rhs, |lhs, rhs| {
if rhs.is_zero() {
rhs
} else {
(lhs + rhs).urem(rhs)
}
})
}
}

impl Interpret for EvmMulMod {
fn interpret(&self, state: &mut dyn State) -> EvalValue {
state.set_action(Action::Continue);
let lhs = state.lookup_val(*self.lhs());
let rhs = state.lookup_val(*self.rhs());

EvalValue::zip_with_imm(lhs, rhs, |lhs, rhs| {
if rhs.is_zero() {
rhs
} else {
(lhs * rhs).urem(rhs)
}
})
}
}
8 changes: 8 additions & 0 deletions crates/ir/src/interpret/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,8 @@ pub trait Interpret {
inst::arith::Mul,
inst::arith::Sdiv,
inst::arith::Udiv,
inst::arith::Umod,
inst::arith::Smod,
inst::arith::Shl,
inst::arith::Shr,
inst::arith::Sar,
Expand Down Expand Up @@ -59,6 +61,12 @@ pub trait Interpret {
inst::control_flow::Phi,
inst::control_flow::Call,
inst::control_flow::Return,
inst::evm::EvmUdiv,
inst::evm::EvmSdiv,
inst::evm::EvmUmod,
inst::evm::EvmSmod,
inst::evm::EvmAddMod,
inst::evm::EvmMulMod,
);
}

Expand Down
8 changes: 8 additions & 0 deletions crates/ir/src/value.rs
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,14 @@ impl Immediate {
self.apply_binop(rhs, |lhs, rhs| lhs.overflowing_div(rhs).0)
}

pub fn urem(self, rhs: Self) -> Self {
self.apply_binop(rhs, |lhs, rhs| (lhs.to_u256() / rhs.to_u256()).into())
}

pub fn srem(self, rhs: Self) -> Self {
self.apply_binop(rhs, |lhs, rhs| lhs.overflowing_rem(rhs).0)
}

pub fn lt(self, rhs: Self) -> Self {
self.apply_binop_raw(rhs, |lhs, rhs| (lhs.to_u256() < rhs.to_u256()).into())
}
Expand Down
4 changes: 4 additions & 0 deletions crates/parser/src/inst/evm/mod.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
use ir::inst::evm::*;

super::impl_inst_build! {EvmUdiv, (lhs: ValueId, rhs:ValueId)}
super::impl_inst_build! {EvmSdiv, (lhs: ValueId, rhs:ValueId)}
super::impl_inst_build! {EvmUmod, (lhs: ValueId, rhs:ValueId)}
super::impl_inst_build! {EvmSmod, (lhs: ValueId, rhs:ValueId)}
super::impl_inst_build! {EvmStop, ()}
super::impl_inst_build! {EvmAddMod, (lhs: ValueId, rhs: ValueId, modulus: ValueId)}
super::impl_inst_build! {EvmMulMod, (lhs: ValueId, rhs: ValueId, modulus: ValueId)}
Expand Down
2 changes: 1 addition & 1 deletion crates/parser/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -314,7 +314,7 @@ target = \"evm-ethereum-london\"
func public %simple(v0.i8) -> i8 {
block0:
v1.i8 = sub v0 1.i8;
v2.i8 = udiv v1 v0;
v2.i8 = evm_udiv v1 v0;
return 2.i8;
}
";
Expand Down

0 comments on commit 45acf8b

Please sign in to comment.