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
Assembly instruction rationalization thoughts #171
Comments
u32 operations
I agree that this looks a bit strange, and that it would be nice to have a naming convention similar to stdlib. One option is to get rid of checked operations altogether and provide a way to check which could be used before any of these ops as desired. In the parsers, most of these binary arithmetic ops go through the same helper function that checks both arguments and then either keeps their order or leaves it reversed (1 cycle cheaper). We could just provide an operation to check 2 values and then have all core operations be unchecked. Having 2 different ways to check of course introduces the same problem discussed with the stack ops etc, so I'm not sure that's a good idea, but having one might be worth thinking about. Stack manipulation & inputsUnfortunately, I don't see a great solution here either. I think there are good reasons for having the composite operations. Additional points:
I think the best long term option is to just provide good information & warnings, such as showing cycle counts beside operations in an online reference similar to evm.codes or the Miden Assembly Playground from #175 In the immediate term, I think we should make sure the costs are highlighted clearly in the assembly reference, with some visual info such as color coding by cost or highlighting expensive ops, as well as listing recommended alternatives. |
One possible solution for u32 operations is to just use underscores (as we do in stdlib for u64 module). So, for addition, we'd have 3 instructions like so:
The above would be consistent with We can also make it so all 3 variants accept immediate values. For example: |
I think the underscores approach is good 👍 |
One of the things I'm inclined to do with stack manipulation operations is as follows:
For something like
For something like
The benefits of doing this are:
The downsides are:
|
Currently, the way we access memory in the VM is via We can introduce two more VM Stack transition for
Where Stack transition for
The result of this operation would be that the first element of the word at address This does add two more operations to VM operations - but I think these might be worth it. |
A full list of planned to be changed u32 operations with underscores is presented below.
|
Thank you! A couple of thoughts:
|
Oh - one other thing: the list is missing the following operations:
|
But aren't the regular (field) operators |
Regular field operations for comparisons are actually much less efficient than |
Having had the benefit of writing some simple (and not so simple) programs in Miden assembly, I think there are some opportunities to simplify (and in some cases augment) current assembly instruction set. My thoughts are below - though, these are rather preliminary and many of them might not be a good idea.
Field operations
All looks good here. There is one slightly inconsistent thing in comparison operations:
eq
andneq
operations allow for immediate parameters, while other comparison operations do not. The primary reason for allowing immediate parameters foreq
is thateq.0
gets reduced toEQZ
VM operation. And if we introduceeqz
assembly instruction we could remove immediate parameters fromeq
(andneq
) operation. But I'm not sure if this is a big deal.u32 operations
I'd love to adopt the same naming convention as we used in u64 stdlib module. For example, we could do something like this:
u32add
->u32add.checked
u32add.unsafe
->u32add.overflowing
u32add.full
could be eliminatedBut, in this case, it is not clear how to handle immediate values. For example,
u32add.checked.5
looks odd to me. And supplying immediate values to "checked" variants may be desirable because we can check whether the parameter is a valid u32 value at compile time pretty easily.A few other thoughts in u32 category:
u32addc
andu32madd
and have justu32addc.unchecked
andu32madd.unchecked
.u32addc
withu32add3
which would compute a sum of top 3 elements on the stack (and thus would be a more general version ofu32addc
). To do this, we'd need to think through how the AIR constraints would need to be changed.u32div.full
withu32divmod
- this would be consistent with the approach used in u64 module.eq
andneq
, we could also updateu32eq
andu32neq
.Stack manipulation
One thing that bothers me somewhat here is that some operations have different costs and these costs are not intuitive. For example:
dup.7
takes 1 VM cycles, butdup.8
takes 3, and thendup.9
takes 1 VM cycle again. Same goes formovup
andmovdn
.swap
operations take 2 cycles while others take 4.Thus, writing efficient code requires deep understanding of costs of each operations.
One solution to this could be to get rid of the operations which take multiple cycles. But this reduces future flexibility and I'm not sure it's worth it. We could also do some selective simplifications. For example:
swap
operations since they are always emulated using other ops anyway.movup
ormovdn
instructions) always take 1 VM cycle, and then accessing elements 8 - 16 is more expensive (e.g., 3 - 4 VM cycles).Input operations
Similar to the above, the cost model for these operations requires deep knowledge. E.g., it is not obvious that
storew.mem
is 4x faster thanpopw.mem
. But short of getting rid of these composite operations, I'm not sure what can be done.The text was updated successfully, but these errors were encountered: