if we do strictness analysis now we will not get a worker-wrapper
for m1, because of the "let a1 ..." (notice that a1 is not strict in
its body).

Not having this worker wrapper might be very bad, because it might
mean that we will have to rebox arguments to m1 if they are
already unboxed, generating extra allocations, as occurs with m2 (cc)
above.

To solve this problem we have decided to run the simplifier after
float-inwards, so that lets whose body is a HNF are floated out,
undoing the float-inwards transformation in these cases.
We are then back to the original code, which would have a worker-wrapper
for m1 after strictness analysis and would avoid the extra let in m2.

What we lose in this case are the opportunities for case-floating
that could be presented if, for example, a1 would indeed be demanded (strict)
after the floating inwards.

The only way of having the best of both is if we have the worker/wrapper
pass explicitly called, and then we could do with

float-in

strictness analysis

simplify

strictness analysis

worker-wrapper generation

as we would

be able to detect the strictness of m1 after the first call to the strictness analyser, and exploit it with the simplifier (in case it was strict).

after the call to the simplifier (if m1 was not demanded) it would be floated out just like we currently do, before stricness analysis II and worker/wrapperisation.

The reason to not do worker/wrapperisation twice is to avoid
generating wrappers for wrappers which could happen.

8. If full laziness is ever done after strictness

...remember to switch off
demandedness flags on floated bindings! This isn't done at the moment.

9. Ignore-inline-pragmas flag for final simplification

[Occurred in the prelude, compiling ITup2.hs, function dfun.Ord.(*,*)]
Sometimes (e.g. in dictionary methods) we generate
worker/wrappers for functions but the wrappers are never
inlined. In dictionaries we often have

dict = let f1 = ...
f2 = ...
...
in (f1,f2,...)

and if we create worker/wrappers for f1,...,fn the wrappers will not
be inlined anywhere, and we will have ended up with extra
closures (one for the worker and one for the wrapper) and extra
function calls, as when we access the dictionary we will be acessing
the wrapper, which will call the worker.
The simplifier never inlines workers into wrappers, as the wrappers
themselves have INLINE pragmas attached to them (so that they are always
inlined, and we do not know in advance how many times they will be inlined).

To solve this problem, in the last call to the simplifier we will
ignore these inline pragmas and handle the workers and the wrappers
as normal definitions. This will allow a worker to be inlined into
the wrapper if it satisfies all the criteria for inlining (e.g. it is
the only occurrence of the worker etc.).

10. Run Float Inwards once more after strictness-simplify

[Occurred in the prelude, compiling IInt.hs, function const.Int.index.wrk]
When workers are generated after strictness analysis (worker/wrapper),
we generate them with "reboxing" lets, that simply reboxes the unboxed
arguments, as it may be the case that the worker will need the
original boxed value:

in this case the simplifier will remove the binding for y as it is not
used (we expected this to happen very often, but we do not know how
many "reboxers" are eventually removed and how many are kept), and
will keep the binding for x. But notice that x is only used in *one*
of the branches in the case, but is always being allocated! The
floating inwards pass would push its definition into the True branch.
A similar benefit occurs if it is only used inside a let definition.
These are basically the advantages of floating inwards, but they are
only exposed after the S.A./worker-wrapperisation of the code! As we
also have reasons to float inwards before S.A. we have to run it
twice.