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

Mul and div opcodes #26

merged 18 commits into from
Jun 19, 2024

Conversation

juan518munoz
Copy link
Contributor

closes #3

chore: split program files into associated opcode dir for clarity

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")
Copy link
Contributor

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?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Not really needed, it's only to avoid eventually having to many similarly named tests on the same directory
image

Copy link
Contributor

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;
Copy link
Contributor

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.

Copy link
Contributor Author

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?

Copy link
Contributor

@fkrause98 fkrause98 Jun 13, 2024

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]
Copy link
Contributor

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.

Comment on lines 6 to 7
vm.set_register(opcode.dst0_index, src0 / src1);
vm.set_register(opcode.dst1_index, src0 % src1);
Copy link
Contributor

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

Copy link
Contributor Author

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.

Copy link
Contributor

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

Copy link
Contributor

@gianbelinche gianbelinche left a 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!

}

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>)) { ... } 

Comment on lines 31 to 32
low_bits.try_into().unwrap(),
Some(high_bits.try_into().unwrap()),
Copy link
Contributor

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

Copy link
Contributor

@fkrause98 fkrause98 left a 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.

}

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.

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 Show resolved Hide resolved
}

#[test]
fn test_more_complex_program_with_conditionals() {
Copy link
Contributor

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 🚀

@fkrause98 fkrause98 merged commit de1192b into main Jun 19, 2024
3 checks passed
@fkrause98 fkrause98 deleted the mul-and-div-opcodes branch June 19, 2024 17:57
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Mul and Div
3 participants