mirror of
https://github.com/pezkuwichain/revive.git
synced 2026-06-12 17:31:02 +00:00
@@ -0,0 +1,11 @@
|
|||||||
|
// SPDX-License-Identifier: MIT
|
||||||
|
|
||||||
|
pragma solidity ^0.8;
|
||||||
|
|
||||||
|
contract Bitwise {
|
||||||
|
function opByte(uint i, uint x) public payable returns (uint ret) {
|
||||||
|
assembly {
|
||||||
|
ret := byte(i, x)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -154,6 +154,12 @@ sol!(
|
|||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
|
sol!(
|
||||||
|
contract Bitwise {
|
||||||
|
function opByte(uint i, uint x) public payable returns (uint ret);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
impl Contract {
|
impl Contract {
|
||||||
/// Execute the contract.
|
/// Execute the contract.
|
||||||
///
|
///
|
||||||
@@ -508,6 +514,18 @@ impl Contract {
|
|||||||
calldata: Value::balance_ofCall::new((address,)).abi_encode(),
|
calldata: Value::balance_ofCall::new((address,)).abi_encode(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn bitwise_byte(index: U256, value: U256) -> Self {
|
||||||
|
let code = include_str!("../contracts/Bitwise.sol");
|
||||||
|
let name = "Bitwise";
|
||||||
|
|
||||||
|
Self {
|
||||||
|
name,
|
||||||
|
evm_runtime: crate::compile_evm_bin_runtime(name, code),
|
||||||
|
pvm_runtime: crate::compile_blob(name, code),
|
||||||
|
calldata: Bitwise::opByteCall::new((index, value)).abi_encode(),
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
|
|||||||
@@ -1,3 +1,5 @@
|
|||||||
|
use std::str::FromStr;
|
||||||
|
|
||||||
use alloy_primitives::{keccak256, Address, FixedBytes, B256, I256, U256};
|
use alloy_primitives::{keccak256, Address, FixedBytes, B256, I256, U256};
|
||||||
use alloy_sol_types::{sol, SolCall, SolValue};
|
use alloy_sol_types::{sol, SolCall, SolValue};
|
||||||
use rayon::iter::{IntoParallelRefIterator, ParallelIterator};
|
use rayon::iter::{IntoParallelRefIterator, ParallelIterator};
|
||||||
@@ -590,3 +592,25 @@ fn balance() {
|
|||||||
let received = U256::from_be_slice(&output.data);
|
let received = U256::from_be_slice(&output.data);
|
||||||
assert_eq!(expected, received)
|
assert_eq!(expected, received)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn bitwise_byte() {
|
||||||
|
assert_success(&Contract::bitwise_byte(U256::ZERO, U256::ZERO), true);
|
||||||
|
assert_success(&Contract::bitwise_byte(U256::ZERO, U256::MAX), true);
|
||||||
|
assert_success(&Contract::bitwise_byte(U256::MAX, U256::ZERO), true);
|
||||||
|
assert_success(
|
||||||
|
&Contract::bitwise_byte(U256::from_str("18446744073709551619").unwrap(), U256::MAX),
|
||||||
|
true,
|
||||||
|
);
|
||||||
|
|
||||||
|
let de_bruijn_sequence =
|
||||||
|
hex::decode("4060503824160d0784426150b864361d0f88c4a27148ac5a2f198d46e391d8f4").unwrap();
|
||||||
|
let value = U256::from_be_bytes::<32>(de_bruijn_sequence.clone().try_into().unwrap());
|
||||||
|
|
||||||
|
for (index, byte) in de_bruijn_sequence.iter().enumerate() {
|
||||||
|
let (_, output) = assert_success(&Contract::bitwise_byte(U256::from(index), value), true);
|
||||||
|
let expected = U256::from(*byte as i32);
|
||||||
|
let received = U256::abi_decode(&output.data, true).unwrap();
|
||||||
|
assert_eq!(expected, received)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -195,7 +195,14 @@ where
|
|||||||
context.build_load(result_pointer, "shift_right_arithmetic_result")
|
context.build_load(result_pointer, "shift_right_arithmetic_result")
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Translates the `byte` instruction.
|
/// Translates the `byte` instruction, extracting the byte of `operand_2`
|
||||||
|
/// found at index `operand_1`, starting from the most significant bit.
|
||||||
|
///
|
||||||
|
/// Builds a logical `and` with a corresponding bit mask.
|
||||||
|
///
|
||||||
|
/// Because this opcode returns zero on overflows, the index `operand_1`
|
||||||
|
/// is checked for overflow. On overflow, the mask will be all zeros,
|
||||||
|
/// resulting in a branchless implementation.
|
||||||
pub fn byte<'ctx, D>(
|
pub fn byte<'ctx, D>(
|
||||||
context: &mut Context<'ctx, D>,
|
context: &mut Context<'ctx, D>,
|
||||||
operand_1: inkwell::values::IntValue<'ctx>,
|
operand_1: inkwell::values::IntValue<'ctx>,
|
||||||
@@ -204,14 +211,61 @@ pub fn byte<'ctx, D>(
|
|||||||
where
|
where
|
||||||
D: Dependency + Clone,
|
D: Dependency + Clone,
|
||||||
{
|
{
|
||||||
Ok(context
|
const MAX_INDEX_BYTES: u64 = 31;
|
||||||
.build_call(
|
|
||||||
context.llvm_runtime().byte,
|
let is_overflow_bit = context.builder().build_int_compare(
|
||||||
&[
|
inkwell::IntPredicate::ULE,
|
||||||
operand_1.as_basic_value_enum(),
|
operand_1,
|
||||||
operand_2.as_basic_value_enum(),
|
context.word_const(MAX_INDEX_BYTES),
|
||||||
],
|
"is_overflow_bit",
|
||||||
"byte_call",
|
)?;
|
||||||
)
|
let is_overflow_byte = context.builder().build_int_z_extend(
|
||||||
.expect("Always exists"))
|
is_overflow_bit,
|
||||||
|
context.byte_type(),
|
||||||
|
"is_overflow_byte",
|
||||||
|
)?;
|
||||||
|
let mask_byte = context.builder().build_int_mul(
|
||||||
|
context.byte_type().const_all_ones(),
|
||||||
|
is_overflow_byte,
|
||||||
|
"mask_byte",
|
||||||
|
)?;
|
||||||
|
let mask_byte_word =
|
||||||
|
context
|
||||||
|
.builder()
|
||||||
|
.build_int_z_extend(mask_byte, context.word_type(), "mask_byte_word")?;
|
||||||
|
|
||||||
|
let index_truncated =
|
||||||
|
context
|
||||||
|
.builder()
|
||||||
|
.build_int_truncate(operand_1, context.byte_type(), "index_truncated")?;
|
||||||
|
let index_in_bits = context.builder().build_int_mul(
|
||||||
|
index_truncated,
|
||||||
|
context
|
||||||
|
.byte_type()
|
||||||
|
.const_int(revive_common::BIT_LENGTH_BYTE as u64, false),
|
||||||
|
"index_in_bits",
|
||||||
|
)?;
|
||||||
|
let index_from_most_significant_bit = context.builder().build_int_sub(
|
||||||
|
context.byte_type().const_int(
|
||||||
|
MAX_INDEX_BYTES * revive_common::BIT_LENGTH_BYTE as u64,
|
||||||
|
false,
|
||||||
|
),
|
||||||
|
index_in_bits,
|
||||||
|
"index_from_msb",
|
||||||
|
)?;
|
||||||
|
let index_extended = context.builder().build_int_z_extend(
|
||||||
|
index_from_most_significant_bit,
|
||||||
|
context.word_type(),
|
||||||
|
"index",
|
||||||
|
)?;
|
||||||
|
|
||||||
|
let mask = context
|
||||||
|
.builder()
|
||||||
|
.build_left_shift(mask_byte_word, index_extended, "mask")?;
|
||||||
|
let masked_value = context.builder().build_and(operand_2, mask, "masked")?;
|
||||||
|
let byte = context
|
||||||
|
.builder()
|
||||||
|
.build_right_shift(masked_value, index_extended, false, "byte")?;
|
||||||
|
|
||||||
|
Ok(byte.as_basic_value_enum())
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user