Skip to content

Commit

Permalink
They said it couldn't be done
Browse files Browse the repository at this point in the history
  • Loading branch information
puma314 committed Jun 23, 2024
1 parent 0249875 commit db37588
Show file tree
Hide file tree
Showing 5 changed files with 327 additions and 403 deletions.
109 changes: 1 addition & 108 deletions core/src/alu/divrem/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,6 @@ pub mod utils;

use core::borrow::{Borrow, BorrowMut};
use core::mem::size_of;
use hashbrown::HashMap;

use p3_air::{Air, AirBuilder, BaseAir};
use p3_field::AbstractField;
Expand All @@ -76,7 +75,6 @@ use sp1_derive::AlignedBorrow;
use crate::air::MachineAir;
use crate::air::{SP1AirBuilder, Word};
use crate::alu::divrem::utils::{get_msb, get_quotient_and_remainder, is_signed_operation};
use crate::alu::{create_alu_lookups, AluEvent};
use crate::bytes::event::ByteRecord;
use crate::bytes::{ByteLookupEvent, ByteOpcode};
use crate::disassembler::WORD_SIZE;
Expand Down Expand Up @@ -354,119 +352,29 @@ impl<F: PrimeField> MachineAir<F> for DivRemChip {
}

// Insert the necessary multiplication & LT events.
//
// This generate_trace for div must be executed _before_ calling generate_trace for
// mul and LT upon which div depends. This ordering is critical as mul and LT
// require all the mul and LT events be added before we can call generate_trace.
{
// Insert the absolute value computation events.
{
let mut add_events: Vec<AluEvent> = vec![];
if cols.abs_c_alu_event == F::one() {
add_events.push(AluEvent {
lookup_id: event.sub_lookups[4],
shard: event.shard,
channel: event.channel,
clk: event.clk,
opcode: Opcode::ADD,
a: 0,
b: event.c,
c: (event.c as i32).abs() as u32,
sub_lookups: create_alu_lookups(),
})
}
if cols.abs_rem_alu_event == F::one() {
add_events.push(AluEvent {
lookup_id: event.sub_lookups[5],
shard: event.shard,
channel: event.channel,
clk: event.clk,
opcode: Opcode::ADD,
a: 0,
b: remainder,
c: (remainder as i32).abs() as u32,
sub_lookups: create_alu_lookups(),
})
}
let mut alu_events = HashMap::new();
alu_events.insert(Opcode::ADD, add_events);
output.add_alu_events(alu_events);
}

let mut lower_word = 0;
for i in 0..WORD_SIZE {
lower_word += (c_times_quotient[i] as u32) << (i * BYTE_SIZE);
}

let mut upper_word = 0;
for i in 0..WORD_SIZE {
upper_word += (c_times_quotient[WORD_SIZE + i] as u32) << (i * BYTE_SIZE);
}

let lower_multiplication = AluEvent {
lookup_id: event.sub_lookups[0],
shard: event.shard,
channel: event.channel,
clk: event.clk,
opcode: Opcode::MUL,
a: lower_word,
c: event.c,
b: quotient,
sub_lookups: create_alu_lookups(),
};
cols.lower_nonce = F::from_canonical_u32(
input
.nonce_lookup
.get(&event.sub_lookups[0])
.copied()
.unwrap_or_default(),
);
output.add_mul_event(lower_multiplication);

let upper_multiplication = AluEvent {
lookup_id: event.sub_lookups[1],
shard: event.shard,
channel: event.channel,
clk: event.clk,
opcode: {
if is_signed_operation(event.opcode) {
Opcode::MULH
} else {
Opcode::MULHU
}
},
a: upper_word,
c: event.c,
b: quotient,
sub_lookups: create_alu_lookups(),
};
cols.upper_nonce = F::from_canonical_u32(
input
.nonce_lookup
.get(&event.sub_lookups[1])
.copied()
.unwrap_or_default(),
);
output.add_mul_event(upper_multiplication);
let lt_event = if is_signed_operation(event.opcode) {
if is_signed_operation(event.opcode) {
cols.abs_nonce = F::from_canonical_u32(
input
.nonce_lookup
.get(&event.sub_lookups[2])
.copied()
.unwrap_or_default(),
);
AluEvent {
lookup_id: event.sub_lookups[2],
shard: event.shard,
channel: event.channel,
opcode: Opcode::SLTU,
a: 1,
b: (remainder as i32).abs() as u32,
c: u32::max(1, (event.c as i32).abs() as u32),
clk: event.clk,
sub_lookups: create_alu_lookups(),
}
} else {
cols.abs_nonce = F::from_canonical_u32(
input
Expand All @@ -475,22 +383,7 @@ impl<F: PrimeField> MachineAir<F> for DivRemChip {
.copied()
.unwrap_or_default(),
);
AluEvent {
lookup_id: event.sub_lookups[3],
shard: event.shard,
channel: event.channel,
opcode: Opcode::SLTU,
a: 1,
b: remainder,
c: u32::max(1, event.c),
clk: event.clk,
sub_lookups: create_alu_lookups(),
}
};

if cols.remainder_check_multiplicity == F::one() {
output.add_lt_event(lt_event);
}
}

// Range check.
Expand Down
115 changes: 114 additions & 1 deletion core/src/alu/divrem/utils.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
use crate::runtime::Opcode;
use crate::alu::{create_alu_lookups, AluEvent};
use crate::runtime::{Opcode, Runtime};

/// Returns `true` if the given `opcode` is a signed operation.
pub fn is_signed_operation(opcode: Opcode) -> bool {
Expand Down Expand Up @@ -28,3 +29,115 @@ pub fn get_quotient_and_remainder(b: u32, c: u32, opcode: Opcode) -> (u32, u32)
pub const fn get_msb(a: u32) -> u8 {
((a >> 31) & 1) as u8
}

pub fn emit_divrem_alu_events(runtime: &mut Runtime, event: AluEvent) {
let (quotient, remainder) = get_quotient_and_remainder(event.b, event.c, event.opcode);
let c_msb = get_msb(event.c);
let rem_msb = get_msb(remainder);
let mut c_neg = 0;
let mut rem_neg = 0;
let is_signed_operation = is_signed_operation(event.opcode);
if is_signed_operation {
c_neg = c_msb; // same as abs_c_alu_event
rem_neg = rem_msb; // same as abs_rem_alu_event
}

if c_neg == 1 {
runtime.record.add_events.push(AluEvent {
lookup_id: event.sub_lookups[4],
shard: event.shard,
channel: event.channel,
clk: event.clk,
opcode: Opcode::ADD,
a: 0,
b: event.c,
c: (event.c as i32).abs() as u32,
sub_lookups: create_alu_lookups(),
});
}
if rem_neg == 1 {
runtime.record.add_events.push(AluEvent {
lookup_id: event.sub_lookups[5],
shard: event.shard,
channel: event.channel,
clk: event.clk,
opcode: Opcode::ADD,
a: 0,
b: remainder,
c: (remainder as i32).abs() as u32,
sub_lookups: create_alu_lookups(),
});
}

let c_times_quotient = {
if is_signed_operation {
(((quotient as i32) as i64) * ((event.c as i32) as i64)).to_le_bytes()
} else {
((quotient as u64) * (event.c as u64)).to_le_bytes()
}
};
let lower_word = u32::from_le_bytes(c_times_quotient[0..4].try_into().unwrap());
let upper_word = u32::from_le_bytes(c_times_quotient[4..8].try_into().unwrap());

let lower_multiplication = AluEvent {
lookup_id: event.sub_lookups[0],
shard: event.shard,
channel: event.channel,
clk: event.clk,
opcode: Opcode::MUL,
a: lower_word,
c: event.c,
b: quotient,
sub_lookups: create_alu_lookups(),
};
runtime.record.mul_events.push(lower_multiplication);

let upper_multiplication = AluEvent {
lookup_id: event.sub_lookups[1],
shard: event.shard,
channel: event.channel,
clk: event.clk,
opcode: {
if is_signed_operation {
Opcode::MULH
} else {
Opcode::MULHU
}
},
a: upper_word,
c: event.c,
b: quotient,
sub_lookups: create_alu_lookups(),
};
runtime.record.mul_events.push(upper_multiplication);

let lt_event = if is_signed_operation {
AluEvent {
lookup_id: event.sub_lookups[2],
shard: event.shard,
channel: event.channel,
opcode: Opcode::SLTU,
a: 1,
b: (remainder as i32).abs() as u32,
c: u32::max(1, (event.c as i32).abs() as u32),
clk: event.clk,
sub_lookups: create_alu_lookups(),
}
} else {
AluEvent {
lookup_id: event.sub_lookups[3],
shard: event.shard,
channel: event.channel,
opcode: Opcode::SLTU,
a: 1,
b: remainder,
c: u32::max(1, event.c),
clk: event.clk,
sub_lookups: create_alu_lookups(),
}
};

if event.c != 0 {
runtime.record.lt_events.push(lt_event);
}
}
Loading

0 comments on commit db37588

Please sign in to comment.