mirror of
https://github.com/pezkuwichain/revive.git
synced 2026-06-13 09:31:05 +00:00
simplify wrapped divisions and sdiv cfg
Signed-off-by: xermicus <cyrill@parity.io>
This commit is contained in:
@@ -59,7 +59,7 @@ pub fn division<'ctx, D>(
|
|||||||
where
|
where
|
||||||
D: Dependency + Clone,
|
D: Dependency + Clone,
|
||||||
{
|
{
|
||||||
WrappedDivision::new(context, operand_2)?.with(|| {
|
wrapped_division(context, operand_2, || {
|
||||||
Ok(context
|
Ok(context
|
||||||
.builder()
|
.builder()
|
||||||
.build_int_unsigned_div(operand_1, operand_2, "DIV")?)
|
.build_int_unsigned_div(operand_1, operand_2, "DIV")?)
|
||||||
@@ -75,7 +75,7 @@ pub fn remainder<'ctx, D>(
|
|||||||
where
|
where
|
||||||
D: Dependency + Clone,
|
D: Dependency + Clone,
|
||||||
{
|
{
|
||||||
WrappedDivision::new(context, operand_2)?.with(|| {
|
wrapped_division(context, operand_2, || {
|
||||||
Ok(context
|
Ok(context
|
||||||
.builder()
|
.builder()
|
||||||
.build_int_unsigned_rem(operand_1, operand_2, "MOD")?)
|
.build_int_unsigned_rem(operand_1, operand_2, "MOD")?)
|
||||||
@@ -94,59 +94,54 @@ pub fn division_signed<'ctx, D>(
|
|||||||
where
|
where
|
||||||
D: Dependency + Clone,
|
D: Dependency + Clone,
|
||||||
{
|
{
|
||||||
WrappedDivision::new(context, operand_2)?.with(|| {
|
assert_eq!(
|
||||||
let block_no_overflow = context.append_basic_block("no_overflow");
|
operand_2.get_type().get_bit_width(),
|
||||||
let block_operand_1_overflow = context.append_basic_block("operand_1_overflow");
|
revive_common::BIT_LENGTH_WORD as u32
|
||||||
let block_select_quotient = context.append_basic_block("block_select_quotient");
|
);
|
||||||
|
|
||||||
let max_uint = context.builder().build_int_z_extend(
|
let block_calculate = context.append_basic_block("calculate");
|
||||||
context
|
let block_overflow = context.append_basic_block("overflow");
|
||||||
.integer_type(revive_common::BIT_LENGTH_WORD - 1)
|
let block_select = context.append_basic_block("select_result");
|
||||||
.const_all_ones(),
|
let block_origin = context.basic_block();
|
||||||
context.word_type(),
|
context.builder().build_switch(
|
||||||
"constant_zext_max_uint",
|
operand_2,
|
||||||
)?;
|
block_calculate,
|
||||||
let is_operand_1_overflow = context.builder().build_int_compare(
|
&[
|
||||||
inkwell::IntPredicate::EQ,
|
(context.word_type().const_zero(), block_select),
|
||||||
operand_1,
|
(context.word_type().const_all_ones(), block_overflow),
|
||||||
context.builder().build_int_neg(max_uint, "min_uint")?,
|
],
|
||||||
"is_operand_1_overflow",
|
)?;
|
||||||
)?;
|
|
||||||
context.build_conditional_branch(
|
|
||||||
is_operand_1_overflow,
|
|
||||||
block_operand_1_overflow,
|
|
||||||
block_no_overflow,
|
|
||||||
)?;
|
|
||||||
|
|
||||||
context.set_basic_block(block_operand_1_overflow);
|
context.set_basic_block(block_calculate);
|
||||||
let is_operand_2_overflow = context.builder().build_int_compare(
|
let quotient = context
|
||||||
inkwell::IntPredicate::EQ,
|
.builder()
|
||||||
operand_2,
|
.build_int_signed_div(operand_1, operand_2, "SDIV")?;
|
||||||
context.word_type().const_all_ones(),
|
context.build_unconditional_branch(block_select);
|
||||||
"is_operand_2_overflow",
|
|
||||||
)?;
|
|
||||||
context.build_conditional_branch(
|
|
||||||
is_operand_2_overflow,
|
|
||||||
block_select_quotient,
|
|
||||||
block_no_overflow,
|
|
||||||
)?;
|
|
||||||
|
|
||||||
context.set_basic_block(block_no_overflow);
|
context.set_basic_block(block_overflow);
|
||||||
let quotient = context
|
let max_uint = context.builder().build_int_z_extend(
|
||||||
.builder()
|
context
|
||||||
.build_int_signed_div(operand_1, operand_2, "SDIV")?;
|
.integer_type(revive_common::BIT_LENGTH_WORD - 1)
|
||||||
context.build_unconditional_branch(block_select_quotient);
|
.const_all_ones(),
|
||||||
|
context.word_type(),
|
||||||
|
"max_uint",
|
||||||
|
)?;
|
||||||
|
let is_operand_1_overflow = context.builder().build_int_compare(
|
||||||
|
inkwell::IntPredicate::EQ,
|
||||||
|
operand_1,
|
||||||
|
context.builder().build_int_neg(max_uint, "min_uint")?,
|
||||||
|
"is_operand_1_overflow",
|
||||||
|
)?;
|
||||||
|
context.build_conditional_branch(is_operand_1_overflow, block_select, block_calculate)?;
|
||||||
|
|
||||||
context.set_basic_block(block_select_quotient);
|
context.set_basic_block(block_select);
|
||||||
let phi_value = context
|
let result = context.builder().build_phi(context.word_type(), "result")?;
|
||||||
.builder()
|
result.add_incoming(&[
|
||||||
.build_phi(context.word_type(), "phi_quotient")?;
|
(&operand_1, block_overflow),
|
||||||
phi_value.add_incoming(&[
|
(&context.word_const(0), block_origin),
|
||||||
("ient.as_basic_value_enum(), block_no_overflow),
|
("ient.as_basic_value_enum(), block_calculate),
|
||||||
(&operand_1, block_operand_1_overflow),
|
]);
|
||||||
]);
|
Ok(result.as_basic_value())
|
||||||
Ok(phi_value.as_basic_value().into_int_value())
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Translates the signed arithmetic remainder.
|
/// Translates the signed arithmetic remainder.
|
||||||
@@ -158,73 +153,53 @@ pub fn remainder_signed<'ctx, D>(
|
|||||||
where
|
where
|
||||||
D: Dependency + Clone,
|
D: Dependency + Clone,
|
||||||
{
|
{
|
||||||
WrappedDivision::new(context, operand_2)?.with(|| {
|
wrapped_division(context, operand_2, || {
|
||||||
Ok(context
|
Ok(context
|
||||||
.builder()
|
.builder()
|
||||||
.build_int_signed_rem(operand_1, operand_2, "SMOD")?)
|
.build_int_signed_rem(operand_1, operand_2, "SMOD")?)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Helper to wrap division operations so that zero will be returned
|
/// Wrap division operations so that zero will be returned if the
|
||||||
/// if the denominator is zero (see also Ethereum YP Appendix H.2).
|
/// denominator is zero (see also Ethereum YP Appendix H.2).
|
||||||
struct WrappedDivision<'a, 'ctx, D: Dependency + Clone> {
|
///
|
||||||
context: &'a Context<'ctx, D>,
|
/// The closure is expected to calculate and return the quotient.
|
||||||
block_origin: inkwell::basic_block::BasicBlock<'ctx>,
|
///
|
||||||
block_calculate: inkwell::basic_block::BasicBlock<'ctx>,
|
/// The result is either the calculated quotient or zero,
|
||||||
block_select: inkwell::basic_block::BasicBlock<'ctx>,
|
/// selected at runtime.
|
||||||
}
|
fn wrapped_division<'ctx, D, F, T>(
|
||||||
|
context: &Context<'ctx, D>,
|
||||||
impl<'a, 'ctx, D: Dependency + Clone> WrappedDivision<'a, 'ctx, D> {
|
denominator: inkwell::values::IntValue<'ctx>,
|
||||||
/// Create a new wrapped division (inserts a switch on the denominator).
|
f: F,
|
||||||
fn new(
|
) -> anyhow::Result<inkwell::values::BasicValueEnum<'ctx>>
|
||||||
context: &'a Context<'ctx, D>,
|
where
|
||||||
denominator: inkwell::values::IntValue<'ctx>,
|
D: Dependency + Clone,
|
||||||
) -> anyhow::Result<Self> {
|
F: FnOnce() -> anyhow::Result<T>,
|
||||||
assert_eq!(
|
T: inkwell::values::IntMathValue<'ctx>,
|
||||||
denominator.get_type().get_bit_width(),
|
{
|
||||||
revive_common::BIT_LENGTH_WORD as u32
|
assert_eq!(
|
||||||
);
|
denominator.get_type().get_bit_width(),
|
||||||
|
revive_common::BIT_LENGTH_WORD as u32
|
||||||
let block_calculate = context.append_basic_block("calculate");
|
);
|
||||||
let block_select = context.append_basic_block("select");
|
|
||||||
context.builder().build_switch(
|
let block_calculate = context.append_basic_block("calculate");
|
||||||
denominator,
|
let block_select = context.append_basic_block("select");
|
||||||
block_calculate,
|
let block_origin = context.basic_block();
|
||||||
&[(context.word_const(0), block_select)],
|
context.builder().build_switch(
|
||||||
)?;
|
denominator,
|
||||||
|
block_calculate,
|
||||||
Ok(Self {
|
&[(context.word_const(0), block_select)],
|
||||||
context,
|
)?;
|
||||||
block_origin: context.basic_block(),
|
|
||||||
block_calculate,
|
context.set_basic_block(block_calculate);
|
||||||
block_select,
|
let calculated_value = f()?.as_basic_value_enum();
|
||||||
})
|
context.build_unconditional_branch(block_select);
|
||||||
}
|
|
||||||
|
context.set_basic_block(block_select);
|
||||||
/// Insert code to calculate the operation.
|
let result = context.builder().build_phi(context.word_type(), "result")?;
|
||||||
///
|
result.add_incoming(&[
|
||||||
/// The closure is expected to calculate and return the quotient.
|
(&context.word_const(0), block_origin),
|
||||||
///
|
(&calculated_value, block_calculate),
|
||||||
/// The returned value is either the calculated quotient or zero, selected at runtime.
|
]);
|
||||||
fn with<T, F>(self, f: F) -> anyhow::Result<inkwell::values::BasicValueEnum<'ctx>>
|
Ok(result.as_basic_value())
|
||||||
where
|
|
||||||
F: FnOnce() -> anyhow::Result<T>,
|
|
||||||
T: inkwell::values::IntMathValue<'ctx>,
|
|
||||||
{
|
|
||||||
self.context.set_basic_block(self.block_calculate);
|
|
||||||
let calculated_value = f()?.as_basic_value_enum();
|
|
||||||
let calculated_value_incoming_block = self.context.basic_block();
|
|
||||||
self.context.build_unconditional_branch(self.block_select);
|
|
||||||
|
|
||||||
self.context.set_basic_block(self.block_select);
|
|
||||||
let phi_value = self
|
|
||||||
.context
|
|
||||||
.builder()
|
|
||||||
.build_phi(self.context.word_type(), "phi_result")?;
|
|
||||||
phi_value.add_incoming(&[
|
|
||||||
(&self.context.word_const(0), self.block_origin),
|
|
||||||
(&calculated_value, calculated_value_incoming_block),
|
|
||||||
]);
|
|
||||||
Ok(phi_value.as_basic_value())
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user