This provides gmapMFor and gmapMFor2, which are like gmapM, but know what
they're looking for, and can therefore avoid going down branches of the tree
that won't contain any interesting types.
The basic approach is quite similar to Uniplate's PlateData: there's a function
(containsType) that'll tell you whether one type is contained somewhere within
another. However, unlike Uniplate, we build a static IntMap IntSet of the types
we need to know about, which allows rather quicker lookups. (I did try using
PlateData first.)
The result is that applyDepthM is now much quicker than it was before.
applyDepthM2 is a bit less impressive, which I assume is because it can't
really prune the tree much if it's looking for two types.
Future enhancements:
- convert more passes to use applyDepthM*;
- make gmapMFor* aware of constructors rather than just types, which should
allow a bit more pruning.
This touches an awful lot of code, but cgtest07/17 (arrays and retyping) pass.
This is useful because there are going to be places in the future where we'll
want to represent dimensions that are known at runtime but not at compile time
-- for example, mobile allocations, or dynamically-sized arrays. It simplifies
the code in a number of places.
However, we do now need to be careful that expressions containing variables do
not leak into the State, since they won't be affected by later passes.
Two caveats (marked as FIXMEs in the source):
- Retypes checking in the occam parser is disabled, since the plan is to move
it out to a pass anyway.
- There's some (now very obvious) duplication, particularly in the backend, of
bits of code that construct expressions for the total size of an array
(either in bytes or elements); this should be moved to a couple of helper
functions that everything can use.
This works at least for simple examples, although it's probably a bit
restrictive on the array indexes you're allowed; it should attempt to
constant-fold them.
This lets you say things like:
VAL []INT xs IS [i = 0 FOR 20 | i]:
and have it figure out that the type of xs is really [20]INT.
This also cleans up the code a very small amount.
The existing constant-folding code in the parser is still there, since it needs
to know whether things are constant, and A.Dimension expects an Int.
However, this pass is useful because it does a better job of constant folding
than the parser would on its own: it can fold subexpressions of expressions
that are as a whole not constant.
This is so that constant folding gets done early; it's important that it
doesn't happen after anything that tries to pull values into variables later
on.
Procs that are in csParProcs are now generated with the correct calling
convention directly, rather than having a second wrapper function generated
around them.
GCC seems to very occasionally generate addl -N rather than subl N.
Also don't allow subl -N any more -- if it's adjusting the stack pointer back
up, that doesn't mean it's going to use any less of the stack...
All it did was to make a list of the Procs generated by parsToProcs, so
parsToProcs may as well just do the same job itself.
The reason I'd made it a separate pass originally was that I wanted to
optimise out the wrapper when the child of a Par was already a ProcCall.
That optimisation isn't going to be possible any more with the new CCSP,
since wrappers have to fetch their arguments in a different way from
ordinary Procs.
This means all the tests now get run as part of one list, and HUnit keeps track
of the number of failures for us. (The reason I was doing this was so that
tocktest will exit non-zero on QuickCheck test failure too.)
As part of this, I've reworked TestMain's main function quite a bit. It'll now
filter QuickCheck tests into response to options too.