Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Mul and div opcodes #26

Merged
merged 18 commits into from
Jun 19, 2024
Merged
Show file tree
Hide file tree
Changes from 9 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
File renamed without changes.
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
.text
.file "add_sets_overflow.zasm"
.file "mul_sets_overflow.zasm"
.globl __entry
__entry:

Expand Down
2 changes: 1 addition & 1 deletion programs/div/div_quotient.zasm → programs/div/div.zasm
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
.text
.file "div_quotient.zasm"
.file "div.zasm"
.globl __entry
__entry:
.func_begin0:
Expand Down
20 changes: 20 additions & 0 deletions programs/div/div_codepage.zasm
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
.text
.file "div_codepage.zasm"
.globl __entry

.rodata
datavar:
.cell 42
.cell 3
.text

__entry:
.func_begin0:
add 3, r0, r1
div @datavar[0], r1, r3, r4
sstore r0, r0
ret
.func_end0:

.note.GNU-stack
.rodata
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
.text
.file "div_remainder.zasm"
.file "div.zasm"
.globl __entry
__entry:
.func_begin0:
add 25, r0, r1
add 6, r0, r2
div r1, r2, r3, r4
sstore r0, r4
sstore r0, r3
ret
.func_end0:

Expand Down
16 changes: 16 additions & 0 deletions programs/div/div_conditional_gt.zasm
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
.text
.file "div_conditional_gt.zasm"
.globl __entry
__entry:
.func_begin0:
add 1, r0, r3
add 1, r0, r4
add 42, r0, r1
add 3, r0, r2
div.gt r1, r2, r3, r4
sstore r0, r3
ret
.func_end0:

.note.GNU-stack
.rodata
15 changes: 15 additions & 0 deletions programs/div/div_set_eq_flag.zasm
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
.text
.file "div_set_eq_flag.zasm"
.globl __entry
__entry:
.func_begin0:
; EQ is set if the quotient is not zero
add 25, r0, r1
add 6, r0, r2
div! r1, r2, r3, r4
sstore r0, r3
ret
.func_end0:

.note.GNU-stack
.rodata
15 changes: 15 additions & 0 deletions programs/div/div_set_gt_flag.zasm
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
.text
.file "div_set_gt_flag.zasm"
.globl __entry
__entry:
.func_begin0:
; GT is set if the reminder is not zero.
add 25, r0, r1
add 6, r0, r2
div! r1, r2, r3, r4
sstore r0, r3
ret
.func_end0:

.note.GNU-stack
.rodata
19 changes: 19 additions & 0 deletions programs/div/div_stack.zasm
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
.text
.file "div_stack.zasm"
.globl __entry
__entry:

.func_begin0:
add 3, r0, r2
; grow stack
add 1, r0, stack+=[1]
; set stack values
add 42, r0, stack=[0]
; divide stack of absolute index 0
div stack=[0],r2, r3, r4
sstore r0, r0
ret

.func_end0:
.note.GNU-stack
.rodata
2 changes: 1 addition & 1 deletion programs/div/div_zero.zasm
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ __entry:
.func_begin0:
add 1, r0, r1
div r1, r0, r3, r4
sstore r0, r3
sstore r0, r0
ret
.func_end0:

Expand Down
4 changes: 2 additions & 2 deletions programs/mul/mul.zasm
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,8 @@ __entry:
add 3, r0, r1
add 2, r0, r2
mul r1, r2, r1, r0
mul 1, r1, r1, r0
sstore r0, r1
mul 1, r1, r3, r4
sstore r0, r3
ret
.func_end0:

Expand Down
13 changes: 13 additions & 0 deletions programs/mul/mul_big.zasm
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
.text
.file "mul_big.zasm"
.globl __entry
__entry:
.func_begin0:
; test sets r1 = 2**(256) - 1, r2 = 2**(256)
mul r1, r2, r3, r4
sstore r0, r1
ret
.func_end0:

.note.GNU-stack
.rodata
21 changes: 21 additions & 0 deletions programs/mul/mul_codepage.zasm
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
.text
.file "mul_codepage.zasm"
.globl __entry

.rodata
datavar:
.cell 42
.cell 3
.text

__entry:
.func_begin0:
add 1, r0, r1
mul @datavar[0], r1, r1, r0
mul @datavar[1], r1, r1, r0
sstore r0, r1
ret
.func_end0:

.note.GNU-stack
.rodata
14 changes: 14 additions & 0 deletions programs/mul/mul_conditional_gt.zasm
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
.text
.file "mul_conditional_gt.zasm"
.globl __entry
__entry:
.func_begin0:
add 3, r0, r1
add 14, r0, r2
mul.gt r1, r2, r3, r4
sstore r0, r3
ret
.func_end0:

.note.GNU-stack
.rodata
14 changes: 14 additions & 0 deletions programs/mul/mul_sets_overflow.zasm
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
.text
.file "add_sets_overflow.zasm"
.globl __entry
__entry:

.func_begin0:
; test sets r1 = 2**(256) - 1, r2 = 2**(256) - 1
mul! r1, r2, r3, r4
sstore r0, r1
ret

.func_end0:
.note.GNU-stack
.rodata
22 changes: 22 additions & 0 deletions programs/mul/mul_stack.zasm
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
.text
.file "mul_stack.zasm"
.globl __entry
__entry:

.func_begin0:
add 1, r0, r2
; grow stack
add 1, r0, stack+=[2]
; set stack values
add 2, r0, stack=[0]
add 3, r0, stack=[1]
; multiply by stack of absolute index 0
mul stack=[0],r2, r1, r0
; pop stack and multiply by the topmost value
mul stack-=[2],r1, r1, r0
sstore r0, r1
ret

.func_end0:
.note.GNU-stack
.rodata
File renamed without changes.
68 changes: 52 additions & 16 deletions src/address_operands.rs
Original file line number Diff line number Diff line change
Expand Up @@ -72,25 +72,57 @@ pub fn address_operands_read(vm: &mut VMState, opcode: &Opcode) -> (U256, U256)
}
}
}
fn only_reg_write(vm: &mut VMState, opcode: &Opcode, res: U256) {
vm.set_register(opcode.dst0_index, res);

/// The first operand is used most of the times
/// the second operand is used only for div and mul
enum OutputOperandPosition {
First,
Second,
}

fn reg_and_imm_write(vm: &mut VMState, opcode: &Opcode) -> U256 {
let dst0 = vm.get_register(opcode.dst0_index);
let offset = opcode.imm1;
fn only_reg_write(
vm: &mut VMState,
opcode: &Opcode,
output_op_pos: OutputOperandPosition,
res: U256,
) {
match output_op_pos {
OutputOperandPosition::First => vm.set_register(opcode.dst0_index, res),
OutputOperandPosition::Second => vm.set_register(opcode.dst1_index, res),
}
}

dst0 + U256::from(offset)
fn reg_and_imm_write(
vm: &mut VMState,
output_op_pos: OutputOperandPosition,
opcode: &Opcode,
) -> U256 {
match output_op_pos {
OutputOperandPosition::First => {
let dst0 = vm.get_register(opcode.dst0_index);
let offset = opcode.imm1;
let res = dst0 + U256::from(offset);
vm.set_register(opcode.dst0_index, res);
res
}
OutputOperandPosition::Second => {
let dst1 = vm.get_register(opcode.dst1_index);
let offset = opcode.imm1;
let res = dst1 + U256::from(offset);
vm.set_register(opcode.dst1_index, res);
res
}
}
}

pub fn address_operands_store(vm: &mut VMState, opcode: &Opcode, res: U256) {
pub fn address_operands_store(vm: &mut VMState, opcode: &Opcode, res: (U256, Option<U256>)) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Instead of passing an Option, wouldn't it be best to just have 2 functions, one for dst0 and the other for dst1, since the implementation is different.
I think this adds noise

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Since this is a very special case, I think it's worth adding another implementation for div and mul, here's my proposal:

pub fn address_operands_store(vm: &mut VMState, opcode: &Opcode, res: U256) { 
    address_operands(vm, opcode, (res, None))
}
pub fn address_operands_div_mul(vm: &mut VMState, opcode: &Opcode, res: (U256, U256){ 
  address_operands(vm, opcode, (res, Some(U256))
}

fn address_operands(vm: &mut VMState, opcode: &Opcode, res: (U256, Option<U256>)) { ... } 

match opcode.dst0_operand_type {
Operand::RegOnly => {
only_reg_write(vm, opcode, res);
only_reg_write(vm, opcode, OutputOperandPosition::First, res.0);
}
Operand::RegOrImm(variant) => match variant {
RegOrImmFlags::UseRegOnly => {
only_reg_write(vm, opcode, res);
only_reg_write(vm, opcode, OutputOperandPosition::First, res.0);
}
RegOrImmFlags::UseImm16Only => {
panic!("dest cannot be imm16 only");
Expand All @@ -99,38 +131,38 @@ pub fn address_operands_store(vm: &mut VMState, opcode: &Opcode, res: U256) {
Operand::Full(variant) => {
match variant {
ImmMemHandlerFlags::UseRegOnly => {
only_reg_write(vm, opcode, res);
only_reg_write(vm, opcode, OutputOperandPosition::First, res.0);
}
ImmMemHandlerFlags::UseStackWithPushPop => {
// stack+=[src0 + offset] + src1
let src0 = reg_and_imm_write(vm, opcode);
let src0 = reg_and_imm_write(vm, OutputOperandPosition::First, opcode);
vm.current_frame.stack.fill_with_zeros(src0 + 1);
vm.current_frame.stack.store_with_offset(
1,
TaggedValue {
value: res,
value: res.0,
is_pointer: false,
},
);
}
ImmMemHandlerFlags::UseStackWithOffset => {
// stack[src0 + offset] + src1
let src0 = reg_and_imm_write(vm, opcode);
let src0 = reg_and_imm_write(vm, OutputOperandPosition::First, opcode);
vm.current_frame.stack.store_with_offset(
src0.as_usize(),
TaggedValue {
value: res,
value: res.0,
is_pointer: false,
},
);
}
ImmMemHandlerFlags::UseAbsoluteOnStack => {
// stack=[src0 + offset] + src1
let src0 = reg_and_imm_write(vm, opcode);
let src0 = reg_and_imm_write(vm, OutputOperandPosition::First, opcode);
vm.current_frame.stack.store_absolute(
src0.as_usize(),
TaggedValue {
value: res,
value: res.0,
is_pointer: false,
},
);
Expand All @@ -144,4 +176,8 @@ pub fn address_operands_store(vm: &mut VMState, opcode: &Opcode, res: U256) {
}
}
}
if let Some(res) = res.1 {
// Second operand can only be a register
only_reg_write(vm, opcode, OutputOperandPosition::Second, res);
}
}
6 changes: 3 additions & 3 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -53,9 +53,9 @@ pub fn run_program_with_custom_state(bin_path: &str, mut vm: VMState) -> (U256,
Variant::Add(_) => {
_add(&mut vm, &opcode);
}
Variant::Sub(_) => _sub(&mut vm, opcode),
Variant::Mul(_) => _mul(&mut vm, opcode),
Variant::Div(_) => _div(&mut vm, opcode),
Variant::Sub(_) => _sub(&mut vm, &opcode),
Variant::Mul(_) => _mul(&mut vm, &opcode),
Variant::Div(_) => _div(&mut vm, &opcode),
Variant::Jump(_) => todo!(),
Variant::Context(_) => todo!(),
Variant::Shift(_) => todo!(),
Expand Down
2 changes: 1 addition & 1 deletion src/op_handlers/add.rs
Original file line number Diff line number Diff line change
Expand Up @@ -27,5 +27,5 @@ pub fn _add(vm: &mut VMState, opcode: &Opcode) {
// Gt is set if both of lt_of and eq are cleared.
vm.flag_gt |= !vm.flag_lt_of && !vm.flag_eq;
}
address_operands_store(vm, opcode, res);
address_operands_store(vm, opcode, (res, None));
}
19 changes: 14 additions & 5 deletions src/op_handlers/div.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,17 @@
use crate::address_operands::address_operands_read;
use crate::address_operands::{address_operands_read, address_operands_store};
use crate::{opcode::Opcode, state::VMState};

pub fn _div(vm: &mut VMState, opcode: Opcode) {
let (src0, src1) = address_operands_read(vm, &opcode);
vm.set_register(opcode.dst0_index, src0 / src1);
vm.set_register(opcode.dst1_index, src0 % src1);
pub fn _div(vm: &mut VMState, opcode: &Opcode) {
let (src0, src1) = address_operands_read(vm, opcode);
let (quotient, remainder) = src0.div_mod(src1);
if opcode.alters_vm_flags {
// Lt overflow is cleared
vm.flag_lt_of = false;
// Eq is set if quotient is not zero
vm.flag_eq = !quotient.is_zero();
// Gt is set if the remainder is not zero
vm.flag_gt = !remainder.is_zero();
}

address_operands_store(vm, opcode, (quotient, Some(remainder)));
}
Loading