Skip to content

Commit cc1346e

Browse files
authored
perf(levm): improve signextend opcode performance (#4071)
**Motivation** Removed some unnecesary double checks. (left is pr, right is main) <img width="1416" height="925" alt="image" src="https://github.com/user-attachments/assets/ee0272b3-014d-4317-bad5-c7b738b7edd2" />
1 parent 2a9c418 commit cc1346e

File tree

2 files changed

+26
-25
lines changed

2 files changed

+26
-25
lines changed

CHANGELOG.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@
44

55
### 2025-08-19
66

7+
- Improve signextend opcode performance [#4071](https://github.com/lambdaclass/ethrex/pull/4071)
8+
79
- Improve performance of calldataload, calldatacopy, extcodecopy, codecopy, returndatacopy [#4070](https://github.com/lambdaclass/ethrex/pull/4070)
810

911

crates/vm/levm/src/opcode_handlers/arithmetic.rs

Lines changed: 24 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
use crate::{
22
errors::{InternalError, OpcodeResult, VMError},
33
gas_cost,
4-
opcode_handlers::bitwise_comparison::checked_shift_left,
54
vm::VM,
65
};
76
use ethrex_common::{U256, U512};
@@ -226,30 +225,30 @@ impl<'a> VM<'a> {
226225
return Ok(OpcodeResult::Continue { pc_increment: 1 });
227226
}
228227

229-
let bits_per_byte = U256::from(8);
230-
let sign_bit_position_on_byte = U256::from(7);
231-
232-
let sign_bit_index = bits_per_byte
233-
.checked_mul(byte_size_minus_one)
234-
.and_then(|total_bits| total_bits.checked_add(sign_bit_position_on_byte))
235-
.ok_or(InternalError::Overflow)?;
236-
237-
#[expect(clippy::arithmetic_side_effects)]
238-
let shifted_value = value_to_extend >> sign_bit_index;
239-
let sign_bit = shifted_value & U256::one();
240-
241-
let sign_bit_mask = checked_shift_left(U256::one(), sign_bit_index)?
242-
.checked_sub(U256::one())
243-
.ok_or(InternalError::Underflow)?; //Shifted should be at least one
244-
245-
let result = if sign_bit.is_zero() {
246-
value_to_extend & sign_bit_mask
247-
} else {
248-
value_to_extend | !sign_bit_mask
249-
};
250-
current_call_frame.stack.push1(result)?;
251-
252-
Ok(OpcodeResult::Continue { pc_increment: 1 })
228+
#[allow(
229+
clippy::arithmetic_side_effects,
230+
reason = "Since byte_size_minus_one ≤ 31, overflow is impossible"
231+
)]
232+
let sign_bit_index = byte_size_minus_one * 8 + 7;
233+
234+
#[expect(
235+
clippy::arithmetic_side_effects,
236+
reason = "sign_bit_index max value is 31 * 8 + 7 = 255, which can't overflow."
237+
)]
238+
{
239+
let sign_bit = (value_to_extend >> sign_bit_index) & U256::one();
240+
let mask = (U256::one() << sign_bit_index) - U256::one();
241+
242+
let result = if sign_bit.is_zero() {
243+
value_to_extend & mask
244+
} else {
245+
value_to_extend | !mask
246+
};
247+
248+
current_call_frame.stack.push1(result)?;
249+
250+
Ok(OpcodeResult::Continue { pc_increment: 1 })
251+
}
253252
}
254253
}
255254

0 commit comments

Comments
 (0)