Compiler front end:
- Standard things: Constant subexpression elimination etc.
Backend (gates and constraints):
- Automatic custom gate synthesis for repeated basic blocks
- Cost model for balancing proof size, prover exponentiations, maximum gate arity, gate depth.
- Partitioning the circuit to combine multiple constraints into single domain eval (“row”).
- Furthermore, partitions need not be disjoint. With large arity or otherwise, one is likely to be able to eval multiple constraints per domain on overlapping subsets in a single “row” or “window”. Examples: single-constraint matrix multiplication, single-constraint batch inversion.
- For tables, choosing the right table sizes.
- Just like real compilers, best solutions will involve approximate optimisation with empirical benchmarks