use super::i256::{i256_cmp, i256_sign_compl, two_compl, Sign};
use crate::{
gas,
primitives::{Spec, U256},
Host, InstructionResult, Interpreter,
};
use core::cmp::Ordering;
pub fn lt<H: Host>(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>(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>(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>(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>(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>(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>(interpreter: &mut Interpreter, _host: &mut H) {
gas!(interpreter, gas::VERYLOW);
pop_top!(interpreter, op1, op2);
*op2 = op1 & *op2;
}
pub fn bitor<H: Host>(interpreter: &mut Interpreter, _host: &mut H) {
gas!(interpreter, gas::VERYLOW);
pop_top!(interpreter, op1, op2);
*op2 = op1 | *op2;
}
pub fn bitxor<H: Host>(interpreter: &mut Interpreter, _host: &mut H) {
gas!(interpreter, gas::VERYLOW);
pop_top!(interpreter, op1, op2);
*op2 = op1 ^ *op2;
}
pub fn not<H: Host>(interpreter: &mut Interpreter, _host: &mut H) {
gas!(interpreter, gas::VERYLOW);
pop_top!(interpreter, op1);
*op1 = !*op1;
}
pub fn byte<H: Host>(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, 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, 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, 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 *op2 == U256::ZERO || op1 >= U256::from(256) {
match value_sign {
Sign::Plus | Sign::Zero => U256::ZERO,
Sign::Minus => U256::MAX,
}
} else {
const ONE: U256 = U256::from_limbs([1, 0, 0, 0]);
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)),
}
};
}