fix: Change PoseidonHasher::write to be inline_always #6468
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Description
Problem*
Resolves #6441
Summary*
Adds the
#[inline_always]
attribute toPoseidonHasher::write
. This way at least we can pass the tests in #6429 for--inliner-aggressiveness 0
, which is what was supposed to be the default value in #6378 We still have to exclude the-Inf
option in the tests.Looking behind the scenes, many of the functions in the test have inlining costs slightly less than zero, so with -Inf they don't get inlined, but with 0 they do, but that is not enough to make the test pass. An aggressiveness of 22 is enough; as it happens
write
has a cost of 21, and inlining this method does the trick.I don't know if it makes sense to add this attribute, but wanted to open a PR to discuss.
The PR targets the test-matrix branch and changes the test generation to go through the whole possible range of aggressiveness for ACIR but allow us to override the minimum for Brillig.
Additional Context
The SSA generated contains huge arrays coming from the various
poseidon::bn254::consts::x5_[2-16]_config
functions, and Noir crashes trying to allocate more than MAX_STACK_FRAME_SIZE registers for these constants. With -Inf it dies after allocating ~2200 registers, with 0 it goes up to over ~15000, I assume across different stack frames.With +Inf it looks like as if it only kept 11 out of the 15 arrays (just scrolling down the SSA and counting the huge swathes of number blocks 👀), and only creates ~800 registers.
For the record the SSA of just the
write
function looks like this:A working hypothesis is that
PoseidonHasher::finish()
has a big if-else for each of the 15 different acceptable lengths it can handle, each of which have a different set of constants. If we inlinewrite
then the compiler doesn't lose track of which slice is being mutated, and can eliminate the unneeded constants.It's worth trying to run the program with
--show-brillig
(which prints the brillig opcodes as it creates them) with--inliner-aggressivness
22 and 0 (without adding the attribute). With aggressiveness 22 the entire brillig opcode is maybe 4K lines, while with 0 it dies after 15K lines. It shows all the constants being created, which seem to come from a chain of blocks jumping from one to the next. I thought it might be the fact that extra copies are needed ifwrite
is a separate function, due to shared references in the function input.write
is used to hash the signatures and the input together here.Documentation*
Check one:
PR Checklist*
cargo fmt
on default settings.