-
Notifications
You must be signed in to change notification settings - Fork 3
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
Conversation
Makefile
Outdated
ASM_PROGRAMS = $(wildcard $(PROGRAMS_DIR)/*.zasm) | ||
ARTIFACTS_YUL = $(patsubst $(PROGRAMS_DIR)/%.yul, $(ARTIFACTS_DIR)/%.artifacts.yul, $(YUL_PROGRAMS)) | ||
ARTIFACTS_ASM = $(patsubst $(PROGRAMS_DIR)/%.zasm, $(ARTIFACTS_DIR)/%.artifacts.zasm, $(ASM_PROGRAMS)) | ||
YUL_PROGRAMS := $(shell find $(PROGRAMS_DIR) -type f -name "*.yul") |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why was this change needed?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Makes sense to me, let's just be 100% sure that it does not bring any unwanted problems when running tests and such.
|
||
pub fn _mul(vm: &mut VMState, opcode: Opcode) { | ||
let (src0, src1) = address_operands_read(vm, &opcode); | ||
let res = src0 * src1; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
These are 256 bit numbers, keep in mind the spec specifies the mul instruction multiplies the two numbers modulo 2**512.
The high and low bits are also returned in 2 separate operands, I think address_operands_read only takes into account the first operand destination, correct me If I'm wrong.
Also, we should check if overflow has occurred with mul_overflow, check #25 for an example on how to do this.
Ideally, this PR should also implement the logic for the flag changes, if specified. You can also check #25 for an example.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You are right, I'll change the function, it's corresponding test and check overflow.
Should we also implement the logic for flag changes in this PR, or leave it for a separate one as it's been done with #25?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, implement the logic flag here, and bring the changes from #25 now that is merged.
assert_eq!(remainder_result, U256::from_dec_str("1").unwrap()); | ||
} | ||
|
||
#[test] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good job with these tests.
src/op_handlers/div.rs
Outdated
vm.set_register(opcode.dst0_index, src0 / src1); | ||
vm.set_register(opcode.dst1_index, src0 % src1); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Here you should use address_operands_store for storing the results, right now it only cares about the dst0, it shouldn't be much different to implement it for dst1
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Right, the logic of both mul
and div
for address_operand_store
need to be implemented then.
programs/div/div_quotient.zasm
Outdated
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Eventually this will need to be tested with different input formats, like stack and codepage
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good job with the fixes!
src/address_operands.rs
Outdated
} | ||
|
||
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>)) { |
There was a problem hiding this comment.
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
There was a problem hiding this comment.
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>)) { ... }
src/op_handlers/mul.rs
Outdated
low_bits.try_into().unwrap(), | ||
Some(high_bits.try_into().unwrap()), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Maybe add a comment saying that since we used the u256_mask we already know this unwraps won't fail
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Almost there, I think what's more important here is the function addressing, I think my proposal is a nice way to solve this, but feel free to come up with something else if you want. The only thing I'm more worried about it's that the address operands store signature function should be as clean as possible.
src/address_operands.rs
Outdated
} | ||
|
||
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>)) { |
There was a problem hiding this comment.
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>)) { ... }
} | ||
|
||
#[test] | ||
fn test_more_complex_program_with_conditionals() { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Great job thoroughly testing this, must have taken some time 🚀
closes #3
chore: split program files into associated opcode dir for clarity