do we need an IR?
classical compilers that have different backend/targets seem to have an intermediate representation in which they can compute optimizations.
Should we have an IR? There's different ones that exist today, like vampIR (Anoma) and ACIR (Noir).
I don't know how Circom does it, but they have an optimization pass where you can specify how many passes you want to perform (similar to the -O of gcc).
Potential related resources:
as for how custom gates could still allow accelerations, we could easily have intrinsic/builtin functions to prevent any optimizations from happening
introducing an IR would be a bit complicated at this stage, but worth doing at some point. We should at least start thinking about how it would look like:
- [ ] what an IR would look like?
- [ ] what optimizations on that IR would look like?
- [ ] how would we compile noname to that IR?
- [ ] how would we compile that IR to constraints?
related to https://github.com/zksecurity/noname/issues/42 and https://github.com/zksecurity/noname/issues/46
To reduce the amount of constraints describing a circuit, the CIRCOM compiler simplifies the linear constraints. More specifically, the compiler divides the set of constraints into clusters of related linear constraints and then applies the classical Gauss-Jordan elimination to each of them. These optimizations are iterated until it is no longer possible to optimize more linear constraints. The compiler treats clusters independently which allows to parallelize the optimization subprocesses. The compiler runs these optimizations by default but the user can choose to turn them off with a command-line option. Currently, there is also an ongoing work on non-trivial optimization techniques applied to R1CS.
There's also this gist that talks about constraint simplification: