Closed JasonGross closed 8 years ago
It might be a good idea to keep the Input
(reified gallina with the correct operations) and Output
(linear chain of lets) languages separate for these reasons
Here are some things that I think we want to be parameters of the language:
I do not need cse, and I'm not sure whether the reflective syntax is the best place to do it. Are you sure it would not be easier to just not duplicate subexpressions in the first place? Note that being way too liberal with duplicating would lead to exponential blow-up, so some care is needed anyway.
Another question: should literal constants should have the same type as variables in the source code? The two are not interchangable in assembly.
Parameterization by available primitive operators sounds reasonable. I think our natural path for just the original at-MIT project would save that level of generalization until after we were happy with our first full verified implementation. But it probably isn't such a big deal to add the extra generality now. (However, given @varomodt's time constraints for finishing his thesis, it might be worth adding such generality in a separate branch until he's done.)
At first I was thinking that it would be easiest to include separate Type
parameters for unary and binary operators. Unfortunately, that wouldn't accommodate different bit-width combinations, so maybe instead we use list nat -> nat -> Type
. That is, each operator's type is indexed with the bit widths of its inputs and output.
I agree that literal constants and free variables should get different AST constructors, because they're compiled differently. Re: discussion on our mailing list, I expect that free variables should be annotated with constants bounding their values (to support compile-time bounds checking), while obviously such a thing is redundant for literals.
Indexing operations by width isn't sufficient; some operations (ldi
, shl
, shr
) take in a non-register constant, and other operations make use of the boolean carry flag (selc
) and/or return the flag (adc
, subc
). I'm currently leaning towards supporting 1-to-n operators, which take a syntactic tuple as input, and return a Gallina tuple of outputs. This would allow us to avoid pair projections in the output language while still treating all operators as 1-to-1 when we don't care about the details of their arguments. The biggest downside that I see is that this will leave a bunch of unfolded Gallina projections lying around. Another alternative is to separately support 1-to-1 and 1-to-2 operators. I plan to spend today and tomorrow working on this, as part of cleaning up my montgomery assembly pipeline.
We now have something like eight different variants of reflected syntax:
Input.expr
andOutput.expr
in https://github.com/mit-plv/fiat-crypto/blob/jgross-phoas/src/Experiments/FancyMachineMontgomery256.v (mine) , https://github.com/mit-plv/fiat-crypto/blob/rsloan-phoas/src/Experiments/SpecificCurve25519.v (@varomodt 's), and https://github.com/mit-plv/fiat-crypto/blob/phoas/src/Experiments/SpecificCurve25519.v (@andres-erbsen 's), my untyped symbolic (SymbolicExpr
) in https://github.com/mit-plv/fiat-crypto/blob/jgross-phoas/src/Experiments/FancyMachineMontgomery256.v (I also haveSyntax
, which I use only for notations), and possibly another one that is the input to @varomodt 's assembly pipeline. We should probably unify them, to some extend, so that we're not duplicating work and copy-pasting.I propose that we settle on how to design the inductive syntax here. There are some high-level questions:
let
s, or that you don't have trees of operations?bool
and of type word?There are some questions of what constructions we should support. I need the following features:
bool
constants (foradc
)Z
constants (forldi
,shl
,shr
)Z
constants (things whose identity should be fixed at reification time, which are of typeZ
, but whichZ_beq
will block on)let ... in ...
(and a variant for handling n-to-2 operators)The things I want to be able to do with the language are:
fst
of anadc
and asnd
of the sameadc
into a single "carry-let-binding")What do we need elsewhere?
There are also some design questions:
let ... in ...
be different for different numbers of arguments?let ... in ...
?