use super::i256::{i256_cmp, i256_sign_compl, two_compl, Sign};
use crate::{
gas,
primitives::{Spec, U256},
Host, Interpreter,
};
use core::cmp::Ordering;
use rtvm_primitives::uint;
pub fn lt<H: Host + ?Sized>(interpreter: &mut Interpreter, _host: &mut H) {
gas!(interpreter, gas::VERYLOW);
pop_top!(interpreter, op1, op2);
*op2 = U256::from(op1 < *op2);
}
pub fn gt<H: Host + ?Sized>(interpreter: &mut Interpreter, _host: &mut H) {
gas!(interpreter, gas::VERYLOW);
pop_top!(interpreter, op1, op2);
*op2 = U256::from(op1 > *op2);
}
pub fn slt<H: Host + ?Sized>(interpreter: &mut Interpreter, _host: &mut H) {
gas!(interpreter, gas::VERYLOW);
pop_top!(interpreter, op1, op2);
*op2 = U256::from(i256_cmp(&op1, op2) == Ordering::Less);
}
pub fn sgt<H: Host + ?Sized>(interpreter: &mut Interpreter, _host: &mut H) {
gas!(interpreter, gas::VERYLOW);
pop_top!(interpreter, op1, op2);
*op2 = U256::from(i256_cmp(&op1, op2) == Ordering::Greater);
}
pub fn eq<H: Host + ?Sized>(interpreter: &mut Interpreter, _host: &mut H) {
gas!(interpreter, gas::VERYLOW);
pop_top!(interpreter, op1, op2);
*op2 = U256::from(op1 == *op2);
}
pub fn iszero<H: Host + ?Sized>(interpreter: &mut Interpreter, _host: &mut H) {
gas!(interpreter, gas::VERYLOW);
pop_top!(interpreter, op1);
*op1 = U256::from(*op1 == U256::ZERO);
}
pub fn bitand<H: Host + ?Sized>(interpreter: &mut Interpreter, _host: &mut H) {
gas!(interpreter, gas::VERYLOW);
pop_top!(interpreter, op1, op2);
*op2 = op1 & *op2;
}
pub fn bitor<H: Host + ?Sized>(interpreter: &mut Interpreter, _host: &mut H) {
gas!(interpreter, gas::VERYLOW);
pop_top!(interpreter, op1, op2);
*op2 = op1 | *op2;
}
pub fn bitxor<H: Host + ?Sized>(interpreter: &mut Interpreter, _host: &mut H) {
gas!(interpreter, gas::VERYLOW);
pop_top!(interpreter, op1, op2);
*op2 = op1 ^ *op2;
}
pub fn not<H: Host + ?Sized>(interpreter: &mut Interpreter, _host: &mut H) {
gas!(interpreter, gas::VERYLOW);
pop_top!(interpreter, op1);
*op1 = !*op1;
}
pub fn byte<H: Host + ?Sized>(interpreter: &mut Interpreter, _host: &mut H) {
gas!(interpreter, gas::VERYLOW);
pop_top!(interpreter, op1, op2);
let o1 = as_usize_saturated!(op1);
*op2 = if o1 < 32 {
U256::from(op2.byte(31 - o1))
} else {
U256::ZERO
};
}
pub fn shl<H: Host + ?Sized, SPEC: Spec>(interpreter: &mut Interpreter, _host: &mut H) {
check!(interpreter, CONSTANTINOPLE);
gas!(interpreter, gas::VERYLOW);
pop_top!(interpreter, op1, op2);
*op2 <<= as_usize_saturated!(op1);
}
pub fn shr<H: Host + ?Sized, SPEC: Spec>(interpreter: &mut Interpreter, _host: &mut H) {
check!(interpreter, CONSTANTINOPLE);
gas!(interpreter, gas::VERYLOW);
pop_top!(interpreter, op1, op2);
*op2 >>= as_usize_saturated!(op1);
}
pub fn sar<H: Host + ?Sized, SPEC: Spec>(interpreter: &mut Interpreter, _host: &mut H) {
check!(interpreter, CONSTANTINOPLE);
gas!(interpreter, gas::VERYLOW);
pop_top!(interpreter, op1, op2);
let value_sign = i256_sign_compl(op2);
*op2 = if value_sign == Sign::Zero || op1 >= U256::from(255) {
match value_sign {
Sign::Plus | Sign::Zero => U256::ZERO,
Sign::Minus => U256::MAX,
}
} else {
const ONE: U256 = uint!(1_U256);
let shift = usize::try_from(op1).unwrap();
match value_sign {
Sign::Plus | Sign::Zero => op2.wrapping_shr(shift),
Sign::Minus => two_compl(op2.wrapping_sub(ONE).wrapping_shr(shift).wrapping_add(ONE)),
}
};
}
#[cfg(test)]
mod tests {
use crate::instructions::bitwise::{sar, shl, shr};
use crate::{Contract, DummyHost, Interpreter};
use rtvm_primitives::{uint, Env, LatestSpec, U256};
#[test]
fn test_shift_left() {
let mut host = DummyHost::new(Env::default());
let mut interpreter = Interpreter::new(Contract::default(), u64::MAX, false);
struct TestCase {
value: U256,
shift: U256,
expected: U256,
}
uint! {
let test_cases = [
TestCase {
value: 0x0000000000000000000000000000000000000000000000000000000000000001_U256,
shift: 0x00_U256,
expected: 0x0000000000000000000000000000000000000000000000000000000000000001_U256,
},
TestCase {
value: 0x0000000000000000000000000000000000000000000000000000000000000001_U256,
shift: 0x01_U256,
expected: 0x0000000000000000000000000000000000000000000000000000000000000002_U256,
},
TestCase {
value: 0x0000000000000000000000000000000000000000000000000000000000000001_U256,
shift: 0xff_U256,
expected: 0x8000000000000000000000000000000000000000000000000000000000000000_U256,
},
TestCase {
value: 0x0000000000000000000000000000000000000000000000000000000000000001_U256,
shift: 0x0100_U256,
expected: 0x0000000000000000000000000000000000000000000000000000000000000000_U256,
},
TestCase {
value: 0x0000000000000000000000000000000000000000000000000000000000000001_U256,
shift: 0x0101_U256,
expected: 0x0000000000000000000000000000000000000000000000000000000000000000_U256,
},
TestCase {
value: 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff_U256,
shift: 0x00_U256,
expected: 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff_U256,
},
TestCase {
value: 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff_U256,
shift: 0x01_U256,
expected: 0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe_U256,
},
TestCase {
value: 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff_U256,
shift: 0xff_U256,
expected: 0x8000000000000000000000000000000000000000000000000000000000000000_U256,
},
TestCase {
value: 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff_U256,
shift: 0x0100_U256,
expected: 0x0000000000000000000000000000000000000000000000000000000000000000_U256,
},
TestCase {
value: 0x0000000000000000000000000000000000000000000000000000000000000000_U256,
shift: 0x01_U256,
expected: 0x0000000000000000000000000000000000000000000000000000000000000000_U256,
},
TestCase {
value: 0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff_U256,
shift: 0x01_U256,
expected: 0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe_U256,
},
];
}
for test in test_cases {
host.clear();
push!(interpreter, test.value);
push!(interpreter, test.shift);
shl::<DummyHost, LatestSpec>(&mut interpreter, &mut host);
pop!(interpreter, res);
assert_eq!(res, test.expected);
}
}
#[test]
fn test_logical_shift_right() {
let mut host = DummyHost::new(Env::default());
let mut interpreter = Interpreter::new(Contract::default(), u64::MAX, false);
struct TestCase {
value: U256,
shift: U256,
expected: U256,
}
uint! {
let test_cases = [
TestCase {
value: 0x0000000000000000000000000000000000000000000000000000000000000001_U256,
shift: 0x00_U256,
expected: 0x0000000000000000000000000000000000000000000000000000000000000001_U256,
},
TestCase {
value: 0x0000000000000000000000000000000000000000000000000000000000000001_U256,
shift: 0x01_U256,
expected: 0x0000000000000000000000000000000000000000000000000000000000000000_U256,
},
TestCase {
value: 0x8000000000000000000000000000000000000000000000000000000000000000_U256,
shift: 0x01_U256,
expected: 0x4000000000000000000000000000000000000000000000000000000000000000_U256,
},
TestCase {
value: 0x8000000000000000000000000000000000000000000000000000000000000000_U256,
shift: 0xff_U256,
expected: 0x0000000000000000000000000000000000000000000000000000000000000001_U256,
},
TestCase {
value: 0x8000000000000000000000000000000000000000000000000000000000000000_U256,
shift: 0x0100_U256,
expected: 0x0000000000000000000000000000000000000000000000000000000000000000_U256,
},
TestCase {
value: 0x8000000000000000000000000000000000000000000000000000000000000000_U256,
shift: 0x0101_U256,
expected: 0x0000000000000000000000000000000000000000000000000000000000000000_U256,
},
TestCase {
value: 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff_U256,
shift: 0x00_U256,
expected: 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff_U256,
},
TestCase {
value: 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff_U256,
shift: 0x01_U256,
expected: 0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff_U256,
},
TestCase {
value: 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff_U256,
shift: 0xff_U256,
expected: 0x0000000000000000000000000000000000000000000000000000000000000001_U256,
},
TestCase {
value: 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff_U256,
shift: 0x0100_U256,
expected: 0x0000000000000000000000000000000000000000000000000000000000000000_U256,
},
TestCase {
value: 0x0000000000000000000000000000000000000000000000000000000000000000_U256,
shift: 0x01_U256,
expected: 0x0000000000000000000000000000000000000000000000000000000000000000_U256,
},
];
}
for test in test_cases {
host.clear();
push!(interpreter, test.value);
push!(interpreter, test.shift);
shr::<DummyHost, LatestSpec>(&mut interpreter, &mut host);
pop!(interpreter, res);
assert_eq!(res, test.expected);
}
}
#[test]
fn test_arithmetic_shift_right() {
let mut host = DummyHost::new(Env::default());
let mut interpreter = Interpreter::new(Contract::default(), u64::MAX, false);
struct TestCase {
value: U256,
shift: U256,
expected: U256,
}
uint! {
let test_cases = [
TestCase {
value: 0x0000000000000000000000000000000000000000000000000000000000000001_U256,
shift: 0x00_U256,
expected: 0x0000000000000000000000000000000000000000000000000000000000000001_U256,
},
TestCase {
value: 0x0000000000000000000000000000000000000000000000000000000000000001_U256,
shift: 0x01_U256,
expected: 0x0000000000000000000000000000000000000000000000000000000000000000_U256,
},
TestCase {
value: 0x8000000000000000000000000000000000000000000000000000000000000000_U256,
shift: 0x01_U256,
expected: 0xc000000000000000000000000000000000000000000000000000000000000000_U256,
},
TestCase {
value: 0x8000000000000000000000000000000000000000000000000000000000000000_U256,
shift: 0xff_U256,
expected: 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff_U256,
},
TestCase {
value: 0x8000000000000000000000000000000000000000000000000000000000000000_U256,
shift: 0x0100_U256,
expected: 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff_U256,
},
TestCase {
value: 0x8000000000000000000000000000000000000000000000000000000000000000_U256,
shift: 0x0101_U256,
expected: 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff_U256,
},
TestCase {
value: 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff_U256,
shift: 0x00_U256,
expected: 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff_U256,
},
TestCase {
value: 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff_U256,
shift: 0x01_U256,
expected: 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff_U256,
},
TestCase {
value: 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff_U256,
shift: 0xff_U256,
expected: 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff_U256,
},
TestCase {
value: 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff_U256,
shift: 0x0100_U256,
expected: 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff_U256,
},
TestCase {
value: 0x0000000000000000000000000000000000000000000000000000000000000000_U256,
shift: 0x01_U256,
expected: 0x0000000000000000000000000000000000000000000000000000000000000000_U256,
},
TestCase {
value: 0x4000000000000000000000000000000000000000000000000000000000000000_U256,
shift: 0xfe_U256,
expected: 0x0000000000000000000000000000000000000000000000000000000000000001_U256,
},
TestCase {
value: 0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff_U256,
shift: 0xf8_U256,
expected: 0x000000000000000000000000000000000000000000000000000000000000007f_U256,
},
TestCase {
value: 0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff_U256,
shift: 0xfe_U256,
expected: 0x0000000000000000000000000000000000000000000000000000000000000001_U256,
},
TestCase {
value: 0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff_U256,
shift: 0xff_U256,
expected: 0x0000000000000000000000000000000000000000000000000000000000000000_U256,
},
TestCase {
value: 0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff_U256,
shift: 0x0100_U256,
expected: 0x0000000000000000000000000000000000000000000000000000000000000000_U256,
},
];
}
for test in test_cases {
host.clear();
push!(interpreter, test.value);
push!(interpreter, test.shift);
sar::<DummyHost, LatestSpec>(&mut interpreter, &mut host);
pop!(interpreter, res);
assert_eq!(res, test.expected);
}
}
}