use super::i256::i256_cmp;
use crate::{
interpreter_types::{InterpreterTypes, RuntimeFlag, StackTr},
InstructionContext,
};
use core::cmp::Ordering;
use primitives::U256;
pub fn lt<WIRE: InterpreterTypes, H: ?Sized>(context: InstructionContext<'_, H, WIRE>) {
popn_top!([op1], op2, context.interpreter);
*op2 = U256::from(op1 < *op2);
}
pub fn gt<WIRE: InterpreterTypes, H: ?Sized>(context: InstructionContext<'_, H, WIRE>) {
popn_top!([op1], op2, context.interpreter);
*op2 = U256::from(op1 > *op2);
}
pub fn clz<WIRE: InterpreterTypes, H: ?Sized>(context: InstructionContext<'_, H, WIRE>) {
check!(context.interpreter, OSAKA);
popn_top!([], op1, context.interpreter);
let leading_zeros = op1.leading_zeros();
*op1 = U256::from(leading_zeros);
}
pub fn slt<WIRE: InterpreterTypes, H: ?Sized>(context: InstructionContext<'_, H, WIRE>) {
popn_top!([op1], op2, context.interpreter);
*op2 = U256::from(i256_cmp(&op1, op2) == Ordering::Less);
}
pub fn sgt<WIRE: InterpreterTypes, H: ?Sized>(context: InstructionContext<'_, H, WIRE>) {
popn_top!([op1], op2, context.interpreter);
*op2 = U256::from(i256_cmp(&op1, op2) == Ordering::Greater);
}
pub fn eq<WIRE: InterpreterTypes, H: ?Sized>(context: InstructionContext<'_, H, WIRE>) {
popn_top!([op1], op2, context.interpreter);
*op2 = U256::from(op1 == *op2);
}
pub fn iszero<WIRE: InterpreterTypes, H: ?Sized>(context: InstructionContext<'_, H, WIRE>) {
popn_top!([], op1, context.interpreter);
*op1 = U256::from(op1.is_zero());
}
pub fn bitand<WIRE: InterpreterTypes, H: ?Sized>(context: InstructionContext<'_, H, WIRE>) {
popn_top!([op1], op2, context.interpreter);
*op2 = op1 & *op2;
}
pub fn bitor<WIRE: InterpreterTypes, H: ?Sized>(context: InstructionContext<'_, H, WIRE>) {
popn_top!([op1], op2, context.interpreter);
*op2 = op1 | *op2;
}
pub fn bitxor<WIRE: InterpreterTypes, H: ?Sized>(context: InstructionContext<'_, H, WIRE>) {
popn_top!([op1], op2, context.interpreter);
*op2 = op1 ^ *op2;
}
pub fn not<WIRE: InterpreterTypes, H: ?Sized>(context: InstructionContext<'_, H, WIRE>) {
popn_top!([], op1, context.interpreter);
*op1 = !*op1;
}
pub fn byte<WIRE: InterpreterTypes, H: ?Sized>(context: InstructionContext<'_, H, WIRE>) {
popn_top!([op1], op2, context.interpreter);
let o1 = as_usize_saturated!(op1);
*op2 = if o1 < 32 {
U256::from(op2.byte(31 - o1))
} else {
U256::ZERO
};
}
pub fn shl<WIRE: InterpreterTypes, H: ?Sized>(context: InstructionContext<'_, H, WIRE>) {
check!(context.interpreter, CONSTANTINOPLE);
popn_top!([op1], op2, context.interpreter);
let shift = as_usize_saturated!(op1);
*op2 = if shift < 256 {
*op2 << shift
} else {
U256::ZERO
}
}
pub fn shr<WIRE: InterpreterTypes, H: ?Sized>(context: InstructionContext<'_, H, WIRE>) {
check!(context.interpreter, CONSTANTINOPLE);
popn_top!([op1], op2, context.interpreter);
let shift = as_usize_saturated!(op1);
*op2 = if shift < 256 {
*op2 >> shift
} else {
U256::ZERO
}
}
pub fn sar<WIRE: InterpreterTypes, H: ?Sized>(context: InstructionContext<'_, H, WIRE>) {
check!(context.interpreter, CONSTANTINOPLE);
popn_top!([op1], op2, context.interpreter);
let shift = as_usize_saturated!(op1);
*op2 = if shift < 256 {
op2.arithmetic_shr(shift)
} else if op2.bit(255) {
U256::MAX
} else {
U256::ZERO
};
}
#[cfg(test)]
mod tests {
use crate::{
host::DummyHost,
instructions::bitwise::{byte, clz, sar, shl, shr},
InstructionContext, Interpreter,
};
use primitives::{hardfork::SpecId, uint, U256};
#[test]
fn test_shift_left() {
let mut interpreter = Interpreter::default();
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 {
push!(interpreter, test.value);
push!(interpreter, test.shift);
let context = InstructionContext {
host: &mut DummyHost::default(),
interpreter: &mut interpreter,
};
shl(context);
let res = interpreter.stack.pop().unwrap();
assert_eq!(res, test.expected);
}
}
#[test]
fn test_logical_shift_right() {
let mut interpreter = Interpreter::default();
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 {
push!(interpreter, test.value);
push!(interpreter, test.shift);
let context = InstructionContext {
host: &mut DummyHost::default(),
interpreter: &mut interpreter,
};
shr(context);
let res = interpreter.stack.pop().unwrap();
assert_eq!(res, test.expected);
}
}
#[test]
fn test_arithmetic_shift_right() {
let mut interpreter = Interpreter::default();
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 {
push!(interpreter, test.value);
push!(interpreter, test.shift);
let context = InstructionContext {
host: &mut DummyHost::default(),
interpreter: &mut interpreter,
};
sar(context);
let res = interpreter.stack.pop().unwrap();
assert_eq!(res, test.expected);
}
}
#[test]
fn test_byte() {
struct TestCase {
input: U256,
index: usize,
expected: U256,
}
let mut interpreter = Interpreter::default();
let input_value = U256::from(0x1234567890abcdef1234567890abcdef_u128);
let test_cases = (0..32)
.map(|i| {
let byte_pos = 31 - i;
let shift_amount = U256::from(byte_pos * 8);
let byte_value = (input_value >> shift_amount) & U256::from(0xFF);
TestCase {
input: input_value,
index: i,
expected: byte_value,
}
})
.collect::<Vec<_>>();
for test in test_cases.iter() {
push!(interpreter, test.input);
push!(interpreter, U256::from(test.index));
let context = InstructionContext {
host: &mut DummyHost::default(),
interpreter: &mut interpreter,
};
byte(context);
let res = interpreter.stack.pop().unwrap();
assert_eq!(res, test.expected, "Failed at index: {}", test.index);
}
}
#[test]
fn test_clz() {
let mut interpreter = Interpreter::default();
interpreter.runtime_flag.spec_id = SpecId::OSAKA;
let mut host = DummyHost::new(SpecId::OSAKA);
struct TestCase {
value: U256,
expected: U256,
}
uint! {
let test_cases = [
TestCase { value: 0x0_U256, expected: 256_U256 },
TestCase { value: 0x1_U256, expected: 255_U256 },
TestCase { value: 0x2_U256, expected: 254_U256 },
TestCase { value: 0x3_U256, expected: 254_U256 },
TestCase { value: 0x4_U256, expected: 253_U256 },
TestCase { value: 0x7_U256, expected: 253_U256 },
TestCase { value: 0x8_U256, expected: 252_U256 },
TestCase { value: 0xff_U256, expected: 248_U256 },
TestCase { value: 0x100_U256, expected: 247_U256 },
TestCase { value: 0xffff_U256, expected: 240_U256 },
TestCase {
value: 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff_U256, expected: 0_U256,
},
TestCase {
value: 0x8000000000000000000000000000000000000000000000000000000000000000_U256, expected: 0_U256,
},
TestCase { value: 0x4000000000000000000000000000000000000000000000000000000000000000_U256, expected: 1_U256,
},
TestCase { value: 0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff_U256,
expected: 1_U256,
},
];
}
for test in test_cases {
push!(interpreter, test.value);
let context = InstructionContext {
host: &mut host,
interpreter: &mut interpreter,
};
clz(context);
let res = interpreter.stack.pop().unwrap();
assert_eq!(
res, test.expected,
"CLZ for value {:#x} failed. Expected: {}, Got: {}",
test.value, test.expected, res
);
}
}
}