Commit Graph

82 Commits

Author SHA1 Message Date
chriseth
2748ac0579 Inline only at end (#3173)
Fixes https://github.com/powdr-labs/powdr/issues/3113

---------

Co-authored-by: Georg Wiese <georgwiese@gmail.com>
Co-authored-by: schaeff <thibaut@powdrlabs.com>
2025-08-25 15:41:02 +00:00
Thibaut Schaeffer
86c31acd9a Make powdr generic over the pgo method (#3188)
Introduce `PgoAdapter` which wraps `Adapter` and can call apc
generation. Removes the match statements over the pgo method. Breaking
change. Now the client can pick some pgo implementations like
`pgo::CellPgo` and use it like
`CellPgo::<MyAdapter>::new(pgo_data).generate_apcs(blocks)`. The client
can also implement `PgoAdapter<A: Adapter>` for its own pgo
implementation.
2025-08-22 13:59:23 +00:00
Georg Wiese
95e773400f Remove BusType::OpenVmBitwiseLookup (#3211)
After #3209, it is no longer necessary to list OpenVM's "bitwise lookup"
bus in the `BusType` enum, which lives in the VM-agnostic
`autoprecompiles` crate.
2025-08-22 11:19:53 +00:00
chriseth
4fa8d35674 Remove variables that are only constrained by a simple solvable algebraic constraints. (#3196)
Fixes https://github.com/powdr-labs/powdr/issues/3113

---------

Co-authored-by: Georg Wiese <georgwiese@gmail.com>
2025-08-20 15:20:43 +00:00
chriseth
5e83a8a93a Do not use bus field variables. (#3171)
Removes the special introduction and removal of bus variables because
the solver can now handle this on its own through the `LinearizedSolver`
component. It also has the benefit that we do not need to run the
optimizer twice any more (once with bus interaction variables and once
without).

Previously we would introduce a new variable type outside of the solver
and replace all bus interactions `bus_interaction(1, x + y * z)` by
`bus_interaction(1, bus_var_1)` and the algebraic constraint `bus_var_1
= x + y * z`.

Now the `LinearizedSolver` is a component inside the solver that
replaces all bus interaction fields (that are not already constants or
simple variables) and also replaces all non-linear components:

`bus_interaction(1, x + y * z)`

becomes

```
bus_interaction(1, v1)
v1 = x + v2
v2 = y * z
```

The reason behind also replacing non-linear parts is because range
constraints are only stored for variables, not for all sub-expressions.
Also if we find the same non-linear sub-expression multiple times, we
can now replace it directly by the same variable.

---------

Co-authored-by: Georg Wiese <georgwiese@gmail.com>
2025-08-20 14:20:15 +00:00
chriseth
bb49beb9b6 Remove outer negation when converting a grouped expression to an algebraic constraint. (#3194) 2025-08-19 11:26:33 +00:00
chriseth
36bd7abec7 Ignore range constraint on output. (#3190)
Summary: We do not need to add the range constraint on the output
because the output is uniquely determined by the formula and the range
constraints on the inputs.

Details:

This slightly improves the "low degree bus interaction optimizer". It
replaces a bus interaction by an algebraic constraint and simple range
constraints in the following way:

1. It performs exhaustive search about which of the non-constant fields
in the bus interaction are inputs and which (only one) is the output
2. Determines currently-known range constraints on inputs and outputs
3. Using exhaustive search, chooses a candidate function and checks that
for all input values in the range constraints, the candidate computes
the same output as the bus interaction would (i.e. the bus interaction
also allows exactly one output compatible with the concrete values for
the inputs).
4. If such a candidate is function, it replaces the bus interaction by
the candidate turned into an algebraic constraint and simple range
constraints (the ones determined in the beginning)

This PR changes the mechanism in that it does not re-add range
constraints for the output, only for the inputs. The reason is that the
algebraic constraint directly computes the value for the output for all
inputs within the range constraints of the input. So the algebraic
constraint already enforces the range constraint on the output from the
range constraints on the inputs.
2025-08-19 09:52:23 +00:00
chriseth
908a3f7fb3 Improve test reporting. (#3191)
Previously, for successful tests, it would still update the expectation
file and print that it did so, even though the contents were the same.
Now the "update" message is only printed if the contents are actually
different.
2025-08-19 09:08:43 +00:00
chriseth
5c2cc8f126 Add unit test for sha256 optimization (#3186) 2025-08-18 14:47:22 +00:00
Georg Wiese
bdf3a5fefa Low-degree bus interaction optimizer (#3130)
This PR adds a new optimizer: If a stateless bus interaction (a.k.a.
lookup) implements a low-degree function, it is replaced by a polynomial
constraint (and range constraints).

Some examples include:
- `xor(a, 0xff)` (logical `not` on bytes): This is a linear function
(`255 - a`)
- `xor(a, b)`, where `a` and `b` are known to not have the same bits
set: This equals `a + b`
- `xor(a, b)`, where `a` and `b` are known to be bit-valued: This is
equal to `a + b - 2 * a * b`

Doing this replacement has several advantages:
- A bus interaction is replaced with a polynomial constraint (which is
usually much cheaper)
- Because the output is equal to a low-degree expression of the inputs
(often linear), the inliner can inline it, so we don't have to commit to
it

Note that in addition to the linear function, a lookup always *also*
enforces a range constraint. These are added to the system by using the
API added with the range constraint optimizer (#3151). In many cases,
these constraints are redundant and can be removed again by the range
constraint optimizer (e.g. the inputs might come from memory, which can
be assumed to store byte-constrained words.

---------

Co-authored-by: Leo <leo@powdrlabs.com>
Co-authored-by: chriseth <chris@ethereum.org>
2025-08-15 10:47:55 +00:00
Georg Wiese
bb56087791 Use default OpenVM degree bounds (#3167)
Builds on #3166
2025-08-12 15:13:23 +00:00
Georg Wiese
a178517a9d Use expect-test in optimizer test (#3166)
Builds on #3164 (in queue)
2025-08-11 20:39:45 +00:00
Georg Wiese
46100870f5 Bug fix in filter_byte_constraints (#3164)
Fixes a soundness bug @chriseth
[found](https://github.com/powdr-labs/powdr/pull/3151/files#r2267259864)
that was introduced in #3151: I thought we can e.g. check `expr` to be 6
bit by checking `4 * expr` to be a byte. That is incorrect, e.g.
$4^{-1}$ would pass the check but should not.
2025-08-11 19:03:50 +00:00
Leo
f03aa041ff Fix default degree bound (#3155)
We used 5 for OpenVM's default constraint max degree bound for a long
time since that's what was in their SDK example, but they actually use
and suggest app log blowup = 1 for app proofs, which leads to max_degree
= 3. This PR changes the default to 3.

The basic PR is quite simple, see the first commit. A lot of the
`max_degree` propagation in the second commit is because of the
`get_air_metrics` function that needs it to call an OpenVM internal
function, and the max degree is not available in any existing data
structure at that point.

I thought the easiest was just to add it to these functions, and I had
to change one trait. But that felt easier/less invasive than changing
associated types/constants of other traits. @Schaeff let me know if this
is fine or if you prefer another route.
2025-08-11 15:19:45 +00:00
Georg Wiese
c638bbf081 Read tuple range checker sizes from config (#3154)
We used the default tuple range checker sizes, but it should be read
from the config. For example, in the reth benchmarks, the sizes are
actually different, leading to potential soundness or completeness bugs.
2025-08-08 16:00:57 +00:00
Georg Wiese
71d821c427 Range constraint optimizer (#3151)
Fixes #3128

---------

Co-authored-by: Leo <leo@powdrlabs.com>
2025-08-08 14:05:05 +00:00
Georg Wiese
d9288baa02 Add test for single mul instruction (#3153)
While working on #3151, I realized that none of the tests uses OpenVM's
"tuple range checker". The `mul` instruction is an example.
2025-08-08 09:20:34 +00:00
chriseth
24ddce250d Prefer inlining last variable. (#3136) 2025-08-05 19:03:23 +00:00
Georg Wiese
abb72c8581 Add list of columns when rendering symbolic machines (#3138)
Two reasons for this:
- When making changes to the optimizer, the diffs in the snapshots show
immediately which columns got removed
- When looking for more optimizations, it's also useful to go through
each column and ask "Why do we need this column?"
2025-08-04 21:10:50 +00:00
Leandro Pacheco
4be51aa95a Powdr openvm extension with new hints (#3100)
Extend our openvm guest/host with support for new hints.
Includes hints for `k256` affine coordinate inverse and sqrt.
2025-07-30 15:50:23 +00:00
Georg Wiese
11cb3d6803 Fix typo on comment (#3099)
Added a wrong comment in #3097 :/
2025-07-28 19:06:44 +00:00
Georg Wiese
45398d41a9 Test stack accesses (#3097) 2025-07-28 17:33:25 +00:00
chriseth
0d43b411b3 Turn solver into trait. (#3087)
Turns `Solver` into a trait to abstract away the bus interaction handler
and also allow other implementations in the future.

It also makes the solver persistent across optimization loops so that we
do not have to derive the same range constraints all over again.

This is also a preparatory PR to make the solver more independent from
the constraint system: The constraint system inside the solver will have
way more redundancies in the future.

---------

Co-authored-by: Georg Wiese <georgwiese@gmail.com>
2025-07-28 14:18:02 +00:00
chriseth
362d3f9fdb Remove redundant constraints. (#3074)
Removes algebraic constraints that are implied by other algebraic
constraints.

In order to do that, grouped expressions are turned into products of
factors such that these factors are as much normalized as possible. Then
we try to find algebraic constraints that are divisors of other
algebraic constraints (i.e. the factors are subsets).
2025-07-26 10:54:15 +00:00
Georg Wiese
0a1a7556e7 Add tests for pseudo instructions (#3073)
Done by Claude, not reviewed yet

---------

Co-authored-by: chriseth <chriseth.github@gmail.com>
2025-07-25 14:59:25 +00:00
Georg Wiese
6329f0ea65 Remove opcode (#3091)
We used to need the Opcode of the APC in order to hard-code it in the PC
lookup. However, for a while, we have removed PC lookups entirely,
hard-coding the PC in the execution bridge receive instead.

This removes the necessity to store the opcode. It was only used as an
ID of the APC. But for this, we can use the PC instead. This has the
added benefit that we can more easily relate it to the original program.
2025-07-25 14:33:43 +00:00
Georg Wiese
694450fdfe Include instructions & evaluation in APC snapshots (#3088)
Includes an evaluation of APCs in the snapshots.
2025-07-25 13:39:20 +00:00
chriseth
c79e4c17f0 Substitute bus vars at start and end. (#3078) 2025-07-25 11:08:22 +00:00
chriseth
46549ee718 Replace xor bus interaction by algebraic constraint (#3058)
Optimize xor lookups such that if the inputs are already
boolean-constrained, the xor operation is computed using an algebraic
constraint instead.
2025-07-25 08:16:59 +00:00
chriseth
1b30e81d78 Use UPDATE_EXPECT feature also for apc builder tests. (#3082) 2025-07-24 12:54:36 +00:00
Georg Wiese
eeb6776e85 Generalize bus type (#3070)
The `BusType` enum in the `autoprecompiles` crate still listed the
OpenVM bus types. Now, the bus types that we actually rely on are
hard-coded (e.g. execution bridge, memory, etc), but there is an `Other`
variant where the integration can add their own types:

92ae7469e8/autoprecompiles/src/bus_map.rs (L5-L19)

---------

Co-authored-by: Thibaut Schaeffer <schaeffer.thibaut@gmail.com>
2025-07-23 13:50:57 +00:00
chriseth
9a97fca7c6 Take other bus interactions into account when computing xor range constraints (#3012) 2025-07-22 09:32:46 +00:00
Georg Wiese
d74aaa1a83 Generalize memory (#3065)
This PR generalizes the memory optimizer to not make any specific
assumptions about the structure of memory bus interactions. This is done
by turning `MemoryBusInteraction` into a trait, which is an associated
type in the `Adapter`. Currently, there is one concrete implementation,
`OpenVmMemoryBusInteraction`.
2025-07-22 08:19:13 +00:00
chriseth
bcae937044 Add memcpy block test. (#3067)
Co-authored-by: Georg Wiese <georgwiese@gmail.com>
2025-07-21 15:38:51 +00:00
chriseth
1480efd132 Store column count. (#3066)
In order to get a feel for the optimizer, I think it is good to also
output the column count. It is rather difficult to get the column count
before optimization, but in the end we are only interested in the effect
of a new optimization step anyway, so I think this is fine.

---------

Co-authored-by: Georg Wiese <georgwiese@gmail.com>
2025-07-21 11:03:06 +00:00
Georg Wiese
caf069eb85 Generalize PC lookup & execution bus handling (#3055)
Generalizations that make fewer assumptions about the structure of bus
interactions like PC lookups and bus interactions. See comments below.

One change is that we know inline the initial PC (because we know it for
any given basic block), which leads to *all* PC lookups being removed,
slightly improving performance (at least reducing one witness column &
one bus interaction).

---------

Co-authored-by: schaeff <thibaut@powdrlabs.com>
2025-07-20 08:09:32 +00:00
Georg Wiese
c856986f75 BasicBlock: Store start_pc (#3059)
Suggested alternative to #3057: Instead of `start_idx`, we store the
`start_pc` to identify a basic block. Both should uniquely identify the
basic block, but the start PC is useful information on its own (whereas
the `start_idx` only makes sense to someone who knows the entire
program).

See also
https://github.com/powdr-labs/powdr/pull/3055#discussion_r2215738707.
2025-07-18 15:16:03 +00:00
Thibaut Schaeffer
c5d2b13e31 Partially remove opcode concept from apc crate, use VmOpcode in openvm crate (#3054)
This PR does two things:
- it partially removes the notion of opcode in the autoprecompile crate,
and instead relies on user provided functions to know if an instruction
is allowed/branching
- it uses VmOpcode as much as possible in the openvm crate instead of
usize

After this PR, the only remaining notion of opcode in the apc crate is
in the `SymbolicInstructionStatement` where it is still a single field
element. @georgwiese shared ideas to remove that too, or at least shift
it to the client, see #3055
2025-07-18 09:28:58 +00:00
Thibaut Schaeffer
922aa523c7 Trait based apc (#3040)
Group all traits under a single `Adapter` trait.
2025-07-15 11:56:56 +00:00
Thibaut Schaeffer
55048cfd32 Move block detection to APC crate (#3033)
Moving block detection to the APC crate. 
After this PR, a larger chunk of the `customize` function is
openvm-agnostic.
2025-07-11 08:59:40 +00:00
Thibaut Schaeffer
89378a3d01 Move APC export to APC crate (#3021)
We currently export the APCs to disk in the openvm crate.
Now that the APCs are generic, we can export them in the APC crate
already.
The json file is still generated in openvm, since it contains some
openvm-specific data, such as the number of logup columns (which depends
on the stark config, which the APC crate does not know about)
2025-07-10 08:48:42 +00:00
Thibaut Schaeffer
d6844422f6 Move concept of block to APC crate (#3020)
Simplify and make the concept of block less openvm specific.
The next step will be to move the saving the apcs to disk to the apc
crate.
2025-07-10 07:43:35 +00:00
Georg Wiese
ea088e0789 Refactor reassign_ids (#3019)
See [this
comment](https://github.com/powdr-labs/powdr/pull/2995/files#diff-7edc0d0adead528c534e3938578e77a31c59b70a6a9ea75e53e595ab05569dbfR98).
2025-07-09 09:50:07 +00:00
chriseth
9f88ae22a5 Test for shift by 8 (#3006) 2025-07-08 20:19:11 +00:00
Georg Wiese
c0cf02a491 Remove simplify_expression in some places (#3011)
Just so we don't do this:
```rust
quadratic_symbolic_expression_to_algebraic(
    &algebraic_to_quadratic_symbolic_expression(
        &quadratic_symbolic_expression_to_algebraic(&expr)))
```
😉
2025-07-08 14:50:51 +00:00
Thibaut Schaeffer
3d2d2b756c Use all columns in pgo (#3007)
When looking at metrics to rank apcs, we currently only take into
account main columns (excluding second stage columns)
Fix that.
2025-07-08 14:29:14 +00:00
Thibaut Schaeffer
1418069ea1 Remove option (#2986) 2025-07-03 11:06:19 +00:00
Steve Wang
e6a90c7f0f APC instruction tests (Shift chip) (#2947)
I think I'll focus more on PGO tmr related to APC vs non APC columns +
some more tests, so might as well merge this for now.

Conclusion for shift chip: no further optimization detected. Did a nice
job removing compile time flags and `imm` value related markers.
2025-06-27 09:28:43 +00:00
Thibaut Schaeffer
57d34d13b8 Adjust cell PGO cost function, add hard limit on column count (#2949)
In cell pgo:
- rank apcs by `cells_saved / column_count`
- select them as long as the total column count doesn't cross a max
value, possibly skipping some

---------

Co-authored-by: Steve Wang <qian.wang.wg24@wharton.upenn.edu>
2025-06-27 00:50:47 +00:00
Steve Wang
67630712ac APC Instruction Tests (Branch Eq and Branch Lt) (#2940)
Again, leaving comments here as I mark things or detect further
optimizations.

Intended single intruction tests for Branch Eq and Branch Lt chips (6
instructions total). Should be the most popular chips after ALU and LS.

Findings: after fully inspecting these branch related instructions, I
conclude that there aren't further optimizations needed. These chips
mostly revolve around value comparison (lots of diff and inverse
columns), all of which require knowing register values to further
simplify, which aren't typically solved at compile time, and therefore
almost all original constraints and bus interactions stay in except
those that involve compile time opcode flags.
2025-06-25 13:06:43 +00:00