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

Restrict the number of stack inputs and outputs to 16 #1456

Merged
merged 13 commits into from
Oct 3, 2024

Conversation

Fumuran
Copy link
Contributor

@Fumuran Fumuran commented Aug 16, 2024

Closes #1428

This PR changes the input and output stack depth to be constant of 16. As a result of this change StackOutputs now doesn't have the OverflowArray, since we don't allow the stack to have more than 16 elements.

TODO:

  • Create a new error which returns if the program have a non-empty OverflowTable at the end of the execution.
  • Update docs and comments.
  • Update CHANGELOG.

Comment on lines 16 to 21
/// The number of stack registers which can be accessed by the VM directly. This is also the
/// minimum stack depth enforced by the VM.
pub const STACK_TOP_SIZE: usize = 16;

/// Maximum number of elements allowed for the input and output stack.
pub const STACK_DEPTH: usize = 16;
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Probably we should leave only one constant.

Copy link
Contributor

Choose a reason for hiding this comment

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

Agreed; I would maybe have just STACK_MAX_DEPTH? And then document that

  • it's the maximum number of non-zero elements allowed on the stack at the beginning and end of the execution
  • Anything more than that goes in the overflow table

Copy link
Contributor

Choose a reason for hiding this comment

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

I think MAX_STACK_DEPTH may be a bit confusing because we also have the concept of stack depth defined as 16 + number of elements in the overflow table (e.g., accessible via sdepth instruction).

We could use MIN_STACK_DEPTH (as stack depth never drops below 16) - but I'd probably prefer to keep STACK_TOP_SIZE as I think MIN_STACK_DEPTH would be a bit confusing as well.

Copy link
Contributor

Choose a reason for hiding this comment

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

I agree that MAX_STACK_DEPTH isn't ideal, but I also don't understand the naming behind "stack top size". In my mind, the "stack top" is the element on the top of the stack (e.g. in C++). Then "stack top size" is the size of that element.

Maybe VISIBLE_STACK_DEPTH, where "visible" refers to the fact that it's directly in the trace? If not, I find MIN_STACK_DEPTH to be less confusing than STACK_TOP_SIZE

Copy link
Contributor

Choose a reason for hiding this comment

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

I tried to use "stack top" as a stand-alone concept that refers to the top 16 elements of the stack - but probably that's a bit confusing. Basically, would be good to have something like that because it is tied to a few things:

  1. Only the top 16 elements can be initialize at the start of execution and remain populated at the end of execution.
  2. Only the top 16 elements can be accessed directly via instructions.
  3. Only the top 16 elements remain visible to the callee when we switch context via call or syscall instructions.
  4. The depth of the stack never drops below 16 elements.

And saying "the top 16 elements of the stack" is a bit of a mouthful.

Given the options though - I probably would prefer MIN_STACK_DEPTH to VISIBLE_STACK_DEPTH.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

But in that case I already done this: I left only one constant (MIN_STACK_DEPTH) and created a docstring with a description based on the Bobbin's comment. Sorry, probably I'm missing something.

Copy link
Contributor

Choose a reason for hiding this comment

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

We still have the constant STACK_TOP_SIZE here, right? My point is:

  1. Rename STACK_TOP_SIZE to MIN_STACK_DEPTH
  2. Add this docstring to it
  3. Remove this constant

Copy link
Contributor Author

@Fumuran Fumuran Aug 30, 2024

Choose a reason for hiding this comment

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

Ah, I see, there are two STACK_TOP_SIZE constants there! Yep, now I get it, I'll rework it as you said.

Edit: probably we shouldn't remove the MIN_STACK_DEPTH constant from the core, it is widely used across the repo, and sometimes we can't import the one from air without importing the air crate itself (for example, we can't import it to the core), so probably it will be cleaner to leave both of MIN_STACK_DEPTH constants.

Edit 2: or, if we really want to leave only one constant, probably it will be better to remove one from the air and just import there the constant from the core, it will be a lot better in terms of dependency conciseness.

Copy link
Contributor

@plafer plafer Sep 3, 2024

Choose a reason for hiding this comment

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

Ah yes good point! I didn't even notice it was defined a few times (STACK_TOP_SIZE in core, in air and MIN_STACK_DEPTH).

As you said I would define it just once in core here (although renamed to MIN_STACK_DEPTH) and use that in all crates.

Copy link
Contributor

Choose a reason for hiding this comment

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

One thing to note, we still use the term "stack top" pretty consistently throughout the codebase to refer to the top 16 elements of the stack (e.g., here and here). I wonder to what extent we can replace these with StackInputs and StackOutputs structs. Though, updating the debug instruction should probably be in a separate PR

@Fumuran Fumuran force-pushed the andrew-limit-io-stack-to-16 branch 3 times, most recently from e62147e to fbf3df9 Compare August 21, 2024 03:35
@Fumuran Fumuran marked this pull request as ready for review August 21, 2024 03:37
@Fumuran Fumuran requested a review from bobbinth August 21, 2024 03:37
@bobbinth bobbinth requested a review from plafer August 23, 2024 23:14
@Fumuran Fumuran force-pushed the andrew-limit-io-stack-to-16 branch from fbf3df9 to 98ce230 Compare August 26, 2024 10:52
Copy link
Contributor

@plafer plafer left a comment

Choose a reason for hiding this comment

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

Looks good! We're missing a few things but all are minor

core/src/stack/inputs.rs Outdated Show resolved Hide resolved
core/src/stack/inputs.rs Outdated Show resolved Hide resolved
core/src/stack/outputs.rs Outdated Show resolved Hide resolved
processor/src/stack/overflow.rs Outdated Show resolved Hide resolved
processor/src/stack/mod.rs Show resolved Hide resolved
prover/src/lib.rs Outdated Show resolved Hide resolved
@@ -32,6 +32,7 @@ processor = { package = "miden-processor", path = "../processor", version = "0.1
"testing",
] }
prover = { package = "miden-prover", path = "../prover", version = "0.10", default-features = false }
stdlib = { package = "miden-stdlib", path = "../stdlib", version = "0.10", default-features = false }
Copy link
Contributor

Choose a reason for hiding this comment

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

It seems like test-utils depends on stdlib, and stdlib depends on test-utils. What am I missing? Why isn't this an error?

Copy link
Contributor

Choose a reason for hiding this comment

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

Why do we need the stdlib dependency here? I would prover not to introduce it (if we can avoid it).

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I added the stdlib dependency to be able to use sys::truncate_stack in the build_op_test! macro. Without it we get the OutputStackOverflow error each time we push something to the stack. Potentially we can rework all tests which use build_op_test! so that we will need to drop excess values from the stack, but I thought that using trucnate_stack will be more clean.

I agree that adding the stdlib dependency is undesirable, but I'm not sure how can we solve this problem without it.

Copy link
Contributor

Choose a reason for hiding this comment

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

One way to solve this is to just manually copy the implementation of sys::truncate_stack into test_utils crate somewhere. Then, test program can be defined like:

{TRUNCATE_STACK_PROC} begin {} exec.truncate_stack end

Copy link
Contributor Author

Choose a reason for hiding this comment

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

If I get it right, the problem is that usage of the constant inside the macro require this constant to be available in the modules where this macro is used. So in order to create a program using the source code of the truncate_stack procedure I need to manually paste in inside the macro (which will be ugly, but will work)

Comment on lines 16 to 21
/// The number of stack registers which can be accessed by the VM directly. This is also the
/// minimum stack depth enforced by the VM.
pub const STACK_TOP_SIZE: usize = 16;

/// Maximum number of elements allowed for the input and output stack.
pub const STACK_DEPTH: usize = 16;
Copy link
Contributor

Choose a reason for hiding this comment

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

Agreed; I would maybe have just STACK_MAX_DEPTH? And then document that

  • it's the maximum number of non-zero elements allowed on the stack at the beginning and end of the execution
  • Anything more than that goes in the overflow table

processor/src/stack/overflow.rs Show resolved Hide resolved
/// Gets the initial value of the overflow table auxiliary column from the provided sets of initial
/// values and random elements.
fn get_overflow_table_init<E>(alphas: &[E], init_values: &[Felt]) -> E
pub fn get_aux_assertions_first_step<E>(result: &mut Vec<Assertion<E>>)
Copy link
Contributor

Choose a reason for hiding this comment

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

We can also remove processor::stack::aux_trace::AuxTraceBuilder::init_responses() (the default implementation in AuxColumnBuilder is now sufficient).

I also think this means we can get rid of both fields in that AuxTraceBuilder.

Copy link
Contributor

Choose a reason for hiding this comment

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

nit: we can actually fully remove the definition, since it has an implementation in the trait directly

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Ah, I see, we can just use the default implementation, indeed.

Copy link
Contributor

@bobbinth bobbinth left a comment

Choose a reason for hiding this comment

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

Looks good! Thank you! I also left some comments inline.

miden/tests/integration/main.rs Outdated Show resolved Hide resolved
core/src/stack/inputs.rs Outdated Show resolved Hide resolved
core/src/stack/inputs.rs Outdated Show resolved Hide resolved
Comment on lines 16 to 21
/// The number of stack registers which can be accessed by the VM directly. This is also the
/// minimum stack depth enforced by the VM.
pub const STACK_TOP_SIZE: usize = 16;

/// Maximum number of elements allowed for the input and output stack.
pub const STACK_DEPTH: usize = 16;
Copy link
Contributor

Choose a reason for hiding this comment

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

I think MAX_STACK_DEPTH may be a bit confusing because we also have the concept of stack depth defined as 16 + number of elements in the overflow table (e.g., accessible via sdepth instruction).

We could use MIN_STACK_DEPTH (as stack depth never drops below 16) - but I'd probably prefer to keep STACK_TOP_SIZE as I think MIN_STACK_DEPTH would be a bit confusing as well.

core/src/stack/outputs.rs Outdated Show resolved Hide resolved
core/src/stack/outputs.rs Outdated Show resolved Hide resolved
@@ -32,6 +32,7 @@ processor = { package = "miden-processor", path = "../processor", version = "0.1
"testing",
] }
prover = { package = "miden-prover", path = "../prover", version = "0.10", default-features = false }
stdlib = { package = "miden-stdlib", path = "../stdlib", version = "0.10", default-features = false }
Copy link
Contributor

Choose a reason for hiding this comment

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

Why do we need the stdlib dependency here? I would prover not to introduce it (if we can avoid it).

Copy link
Contributor

@bobbinth bobbinth left a comment

Choose a reason for hiding this comment

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

Thank you! Looks good! I left a few more comments inline.

I think the main thing is that we can probably treat StackInputs and StackOutputs as very thin wrappers around [Felt; MIN_STACK_DEPTH] and so, can probably simplify them a bit more by implementing Deref into [Felt; MIN_STACK_DEPTH] for them.

Another thing to consider is that for many functions which return [Felt; MIN_STACK_DEPTH] we can probably return StackOutputs struct instead.

core/src/stack/mod.rs Outdated Show resolved Hide resolved
core/src/stack/inputs.rs Outdated Show resolved Hide resolved
core/src/stack/inputs.rs Outdated Show resolved Hide resolved
core/src/stack/inputs.rs Outdated Show resolved Hide resolved
core/src/stack/outputs.rs Outdated Show resolved Hide resolved
core/src/stack/outputs.rs Outdated Show resolved Hide resolved
air/src/constraints/stack/mod.rs Outdated Show resolved Hide resolved
Comment on lines 418 to 423
pub fn stack_top_to_ints(values: &[u64]) -> Vec<u64> {
let mut result: Vec<u64> = values.to_vec();
result.resize(STACK_TOP_SIZE, 0);
result.resize(MIN_STACK_DEPTH, 0);
result
}
Copy link
Contributor

Choose a reason for hiding this comment

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

I'm wondering if we need functions like this one and the one above now. Maybe we should just have StackOutputs::as_int_vec() and StackInputs::as_int_vec() or something like this.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

We can get rid of the stack_to_ints function above (or, at least, use it for a "non-stack" inputs: for memory and hashes), but I think that this stack_top_to_ints function helps a lot: it guaranties that the final_stack array (provided to the test), which could be even empty, at the comparison time will have the MIN_STACK_DEPTH length.
As an alternative we can construct the StackOutputs from this array and then cast it to the vector of ints, but just a resize here should be much more efficient.

@Fumuran
Copy link
Contributor Author

Fumuran commented Sep 13, 2024

TODO:

  • Remove stdlib dependency from the test-utils

Copy link
Contributor

@plafer plafer left a comment

Choose a reason for hiding this comment

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

LGTM! (re: my previous review)

@plafer
Copy link
Contributor

plafer commented Sep 23, 2024

@bobbinth can we get a final review on this one?

@bobbinth
Copy link
Contributor

One thing holding this up is that I think this will break the current block construction code in miden-node (because the code, if I remember correctly) relies on putting most inputs onto the stack. So, the question is whether we want to address 0xPolygonMiden/miden-node#78 before merging this one.

Copy link
Contributor

@bobbinth bobbinth left a comment

Choose a reason for hiding this comment

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

Looks good! Thank you. Not a full review, but I left some more comments inline.

core/src/stack/inputs.rs Outdated Show resolved Hide resolved
core/src/stack/inputs.rs Outdated Show resolved Hide resolved
core/src/stack/outputs.rs Outdated Show resolved Hide resolved
core/src/stack/outputs.rs Outdated Show resolved Hide resolved
Comment on lines 96 to +102
/// Returns mutable access to the stack outputs, to be used for testing or running examples.
/// TODO: this should be marked with #[cfg(test)] attribute, but that currently won't work with
/// the integration test handler util.
pub fn stack_mut(&mut self) -> &mut [Felt] {
&mut self.stack
&mut self.elements
}
Copy link
Contributor

Choose a reason for hiding this comment

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

Should this not be behind the testing flag?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

If we apply some test features (default test or feature = "testing") we can't use it anymore in the test-utils here.

Copy link
Contributor

Choose a reason for hiding this comment

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

Could we not import the dependency in test-utils with the testing feature enabled?

@plafer
Copy link
Contributor

plafer commented Oct 1, 2024

@Fumuran @bobbinth can we prioritize merging this? I am blocked on it so that I can move the stack overflow table to LogUp-GKR

@Fumuran Fumuran force-pushed the andrew-limit-io-stack-to-16 branch from 050c956 to 4ea0ac0 Compare October 1, 2024 16:01
Copy link
Contributor

@bobbinth bobbinth left a comment

Choose a reason for hiding this comment

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

Looks good! Thank you! I left some more comments inline - but they are pretty minor.

test-utils/src/lib.rs Outdated Show resolved Hide resolved
test-utils/src/lib.rs Outdated Show resolved Hide resolved
processor/src/stack/mod.rs Outdated Show resolved Hide resolved
processor/src/operations/comb_ops.rs Outdated Show resolved Hide resolved
processor/src/decoder/aux_trace/mod.rs Show resolved Hide resolved
miden/tests/integration/operations/field_ops.rs Outdated Show resolved Hide resolved
miden/tests/integration/operations/field_ops.rs Outdated Show resolved Hide resolved
miden/tests/integration/operations/stack_ops.rs Outdated Show resolved Hide resolved
processor/src/stack/tests.rs Outdated Show resolved Hide resolved
Copy link
Contributor

@bobbinth bobbinth left a comment

Choose a reason for hiding this comment

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

Look good! Thank you! I think the main outstanding thing is to update the mdBook documentation - let's do this in a follow-up PR though.

@bobbinth bobbinth merged commit b2c5215 into next Oct 3, 2024
9 checks passed
@bobbinth bobbinth deleted the andrew-limit-io-stack-to-16 branch October 3, 2024 06:03
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.

3 participants