Repo cleanup. Fixes #6
authorAlexander Pankiv <alexanderpankiv@gmail.com>
Fri, 25 Dec 2015 15:56:45 +0000 (16:56 +0100)
committerJan Stolarek <jan.stolarek@p.lodz.pl>
Mon, 18 Jan 2016 16:31:50 +0000 (17:31 +0100)
  * remove unused modules
  * delete unnecessary tex comments
  * delete paper
  * update .gitignore: we no longer need to ignore LaTeX build artifacts,
    as the paper has been removed from the repository.  We also ignore
    cabal sandboxes
  * update readme to link to the paper.

38 files changed:
.gitignore
HOWTO-BRANCHES [deleted file]
PROBLEMS [deleted file]
README.md
hoopl.cabal
hoopl.pdf [deleted file]
paper/.gitignore [deleted file]
paper/Makefile [deleted file]
paper/NOTES [deleted file]
paper/Rew.hs [deleted file]
paper/TODO [deleted file]
paper/bbl.dias.mk [deleted file]
paper/bbl.nr.mk [deleted file]
paper/bbl.simonpj.mk [deleted file]
paper/bitly.dias.mk [deleted file]
paper/bitly.nr.mk [deleted file]
paper/bitly.simonpj.mk [deleted file]
paper/code.sty [deleted file]
paper/defuse [deleted file]
paper/dfopt.bib [deleted file]
paper/dfopt.tex [deleted file]
paper/haskell-reviews.txt [deleted file]
paper/hsprelude [deleted file]
paper/icfp2010response.txt [deleted file]
paper/icfp2010reviews.html [deleted file]
paper/latex.mk [deleted file]
paper/mkfile [deleted file]
paper/notes-relatedwork [deleted file]
paper/old-implementation-sections.tex [deleted file]
paper/onepage.tex [deleted file]
paper/proto-response.txt [deleted file]
paper/refs.txt [deleted file]
paper/spell.mk [deleted file]
paper/xsource [deleted file]
src/Compiler/Hoopl/Combinators.hs
src/Compiler/Hoopl/Dataflow.hs
src/Compiler/Hoopl/DataflowFold.hs [deleted file]
src/Compiler/Hoopl/OldDataflow.hs [deleted file]

index 392c4de..eefe95e 100644 (file)
@@ -1,32 +1,16 @@
 .*.swp
 *.bak
-*.bbl.old*
-odfopt.tex
-oodfopt.tex
-nrbib.tex
-_darcs
 *~
 
-dfopt.txt
-dfoptdu.tex
-defuse.tex
-dfopt.bbl
-notesinmargin.tex
-
-
-timestamp.tex
-
-*.log
-*.blg
-*.nlg
-*.dvi
-*.aux
-*.out
-dfopt.ps
-paper/*.pdf
 dist
-/GNUmakefile
-/dist-install
-/dist-boot
-/ghc.mk
+dist-install
+dist-boot
+ghc.mk
 .hpc
+
+# Cabal sandbox
+.cabal-sandbox
+cabal.sandbox.config
+
+# Coverage reports
+*.tix
diff --git a/HOWTO-BRANCHES b/HOWTO-BRANCHES
deleted file mode 100644 (file)
index 932b50b..0000000
+++ /dev/null
@@ -1,15 +0,0 @@
-Here's how to work on Hoopl without breaking GHC.
-
-  - Hoopl maintainers should work on the branch "develop", where they
-    need not validate changes against GHC.
-
-  - GHC uses the 'master' branch, and makes changes there from time to
-    time as necessary to keep GHC working
-
-  - GHC central merges master with develop occasionally (e.g. before a
-    new GHC stable branch is created).
-
-  - Intermediate releases can be made from develop, although we have
-    to ensure that each GHC release ships with a released version of
-    the library.  (As of May 2012, Ian Lynagh coordinates with the
-    package maintainers to make this happen.)
diff --git a/PROBLEMS b/PROBLEMS
deleted file mode 100644 (file)
index f001d67..0000000
--- a/PROBLEMS
+++ /dev/null
@@ -1,68 +0,0 @@
-Problems with polymorphic transfer functions on the left of an arrow
-using RankNTypes: 
-
-  - Can't easily write generic debugging code to show facts
-    propagating through a graph, because
-      . can't tell the shape of the node
-      . therefore can't tell the type of the facts
-
-  - Can't write a generic dominator analysis that assumes only (Edges n)
-
-  - Can't use default cases (or at least not easily) in the transfer
-    function
-
-  - Harder to reuse common predicate transformers like
-
-      - id
-      - distributeFacts :: Edges n => n -> f -> FactBase f
-        distributeFacts n f = mkFactBase [(l, f) | l <- successors n]
-
-
-
-----------------------------------
-Instructions given to NR's class:
-
-
-All,
-
-If you consult the type definition of FwdTransfer,
-you'll see that it requires a polymorphic function and uses a type 
-family which alters the types of arguments and results depending on
-the shape of a node.  If the type of a fact is 'f', then
-
-  - The predicate transformer for a closed/open node has type  f -> FactBase f
-  - The predicate transformer for an open/open node has type   f -> f
-  - The predicate transformer for an open/closed node has type FactBase f -> f
-
-Simon was very enamored of this interface, but it's clear that it
-imposes a heavy burden on clients:
-
- 1. For a typical first node such as
-
-        LabelNode l
-
-    You'll have to capture the fact using
-
-        fromJust $ factLookup factbase l
-
- 2. For a last node you may want something like
-
-        \f -> mkFactBase [(l, f) | l <- successors n]
-
-    Some last nodes may require more elaborate code.
-
- 3. Because the function is both GADT and polymorphic, you can't
-    default any cases---every constructor has to be written
-    explicitly.  When you are doing this, but you don't care about the
-    constructor's arguments, it can be useful to use the record
-    wildcard syntax:
-
-       xfer (ArraySet {}) = id
-
-    This syntax matches any fully saturated application of ArraySet,
-    no matter how many arguments ArraySet expects.
-
-    
-
-
-Norman
index 383e1d7..e7b0cda 100644 (file)
--- a/README.md
+++ b/README.md
@@ -3,29 +3,31 @@ The `hoopl` Package  [![Hackage](https://img.shields.io/hackage/v/hoopl.svg)](ht
 
 ## Hoopl: A Higher-Order OPtimization Library
 
-API documentation can be found on [Hackage](https://hackage.haskell.org/package/hoopl).
+API documentation can be found on
+[Hackage](https://hackage.haskell.org/package/hoopl).  For detailed explanation
+of the library design see paper ["Hoopl: A Modular, Reusable Library for
+Dataflow Analysis and
+Transformation"](http://research.microsoft.com/en-us/um/people/simonpj/Papers/c--/hoopl-haskell10.pdf)
 
 | Directory      | Contents
 | -------------- | ---------
-| `paper/`       | A paper about Hoopl
-| `prototypes/`  | A sampling of prototypes and early designs
 | `src/`         | The current official sources to the Cabal package
 | `testing/`     | Tests, including a sample client.  See [`testing/README`](testing/README)
 
 ### Development Notes
 
-To build the library, change to the src directory and run
+To build the library run:
 
-    cabal configure --prefix=$HOME --user   # we have no idea what this means
+    cabal configure
     cabal build
     cabal install --enable-documentation
 
-To run the tests in the folder testing/, change to the src directory and run 
+To run the tests in the `testing/` folder run:
 
     cabal configure --enable-tests
     cabal test
 
-To run the tests with the test coverage report, change to the src directory and run 
+To run the tests with the test coverage report run:
 
     cabal configure --enable-tests -f testcoverage
     cabal test
index ccbe486..cbd604c 100644 (file)
@@ -51,8 +51,6 @@ Library
                      Compiler.Hoopl.Wrappers,
                      Compiler.Hoopl.Passes.Dominator,
                      Compiler.Hoopl.Passes.DList
---                     Compiler.Hoopl.DataflowFold,
---                     Compiler.Hoopl.OldDataflow,
 
   -- The remaining modules are hidden *provisionally*
   Other-modules:     Compiler.Hoopl.Checkpoint,
diff --git a/hoopl.pdf b/hoopl.pdf
deleted file mode 100644 (file)
index 461654b..0000000
Binary files a/hoopl.pdf and /dev/null differ
diff --git a/paper/.gitignore b/paper/.gitignore
deleted file mode 100644 (file)
index 2b35c02..0000000
+++ /dev/null
@@ -1,46 +0,0 @@
-.*.swp
-*.bak
-*.bbl.old*
-odfopt.tex
-oodfopt.tex
-nrbib.tex
-_darcs
-*~
-*.hi
-*.o
-
-dfopt.txt
-dfoptdu.tex
-defuse.tex
-dfopt.bbl
-notesinmargin.tex
-
-timestamp.tex
-comb1.tex
-iterf.tex
-pairf.tex
-dg.tex
-cprop.tex
-hoopl.tex
-hoopl.ps
-fptype.tex
-bodyfun.tex
-node.tex
-cat.tex
-block.tex
-fpimp.tex
-txfb.tex
-update.tex
-
-
-*.log
-*.blg
-*.nlg
-*.dvi
-*.aux
-*.out
-dfopt.ps
-*.pdf
-onepage.ps
-dom.ps
-dom.epsi
diff --git a/paper/Makefile b/paper/Makefile
deleted file mode 100644 (file)
index 27baf12..0000000
+++ /dev/null
@@ -1,63 +0,0 @@
-#      General makefile for Latex stuff
-
-.SUFFIXES: .tib .verb .tex .fig .dvi .ps
-
-MAIN = dfopt
-
-# Styles are in papers/styles
-TEXINPUTS := .:../styles//:$(TEXINPUTS)
-
-# Bibliographies are in papers/bibs
-BIBINPUTS := .:../bibs//:$(BIBINPUTS)
-
-default: comb1.tex iterf.tex pairf.tex dg.tex  cprop.tex
-       [ -r "$(MAIN)du.tex" ] && chmod +w $(MAIN)du.tex
-       ./defuse < $(MAIN).tex > $(MAIN)du.tex
-       chmod -w $(MAIN)du.tex
-       latex $(MAIN).tex
-#      bibtex $(MAIN)
-       latex $(MAIN).tex
-       latex $(MAIN).tex
-       dvips -f -P pdf < $(MAIN).dvi > $(MAIN).ps
-       ps2pdf $(MAIN).ps
-
-
-
-esc:
-       latex escMeets.tex
-       bibtex escMeets
-       dvips -f < escMeets.dvi > escMeets.ps
-
-bib:
-       bibtex $(MAIN)
-
-pdf:
-       latex $(MAIN).tex
-       bibtex $(MAIN)
-       latex $(MAIN).tex
-       pdflatex $(MAIN).tex
-
-ps:
-       latex $(MAIN).tex
-       bibtex $(MAIN)
-       latex $(MAIN).tex
-       latex $(MAIN).tex
-       dvips -t a4 $(MAIN).dvi -o $(MAIN).ps
-
-clean-ps:
-       clean-ps imp*.ps
-
-HOOPL=../src/Compiler/Hoopl
-
-comb1.tex iterf.tex pairf.tex: ./xsource $(HOOPL)/Combinators.hs
-       lua ./xsource $(HOOPL)/Combinators.hs
-
-dg.tex: ./xsource $(HOOPL)/Dataflow.hs
-       lua ./xsource $(HOOPL)/Dataflow.hs
-
-CLIENT=../testing
-CPROPS=$(CLIENT)/ConstProp.hs $(CLIENT)/Simplify.hs $(CLIENT)/Test.hs
-
-cprop.tex: ./xsource $(CPROPS)
-       lua ./xsource $(CPROPS)
-
diff --git a/paper/NOTES b/paper/NOTES
deleted file mode 100644 (file)
index d041c2f..0000000
+++ /dev/null
@@ -1,197 +0,0 @@
-Notes 18 March 2010
-~~~~~~~~~~~~~~~~~~~
-
-  * John and Norman are not convinced that the ChangeFlag 'tfb_cha' is
-    being updated correctly when facts change.  Because block IDs are
-    added to 'tfb_bids' incrementally, we are worried that a fact at
-    label L could be made to climb by a predecessor, but that this
-    change wouldn't be noted by updateFact unless the block labelled L
-    had already been visited.  We spent a good 20 minutes on this
-    question, which right there is indicative of a problem.  The
-    computation of the fixed point needs to be manifestly correct.
-    Perhaps tfb_bids should be initialized all at one go, and perhaps
-    it should be given type 'BlockId -> Bool'?
-
-  * The 'nodeGraph' function, together with the supporting case of
-    OCFlag and IsOC, are a bit eye-popping.   A good explanation
-    should be a high priority.  Also, it would be good to be able to
-    say in the paper whether GHC -O is able to eliminate the IsOC
-    type-class dictionaries.  Finally, it is probably also worth
-    noting that if Haskell had Sorts as in the Omega language, this
-    issue might not arise.
-
-  * Similarly, the new type-class constraints in GFTR are worth
-    noting, and the same questions arise about dictionaries.
-
-  * Norman has a few ideas to tidy the implementation of gftGraph.
-    He will try them out, and if he likes them, will send them on.
-
-  * The >>> arrow has but one use.  We suggest a local binding:
-
-      blocks_once :: Blocks n -> Trans (TxFactBase n f) (TxFactBase n f)
-      blocks_once = foldr ((>>>) . block_once) idTrans
-        where (t1 >>> t2) f = t1 f >>= t2
-
-  * Does the "it's a bit disgusting..." comment still apply?
-
-
-
-
-
-
-
-Notes March 2010
-~~~~~~~~~~~~~~~~
-Normans comment on draft so far:
-
-- Revisit introduction
-
-- Still skeptical about blockId function
-
-- GMany: does the list have to be non-empty?
-   Could we have GMany b1 [] b2?  
-   
-- Distinction between invariants that hold on "finished graphs"
-  and ones that hold on graphs under construction.
-
-- Consider (GUnit b) :: Graph C C, can successors(b) include b's 
-  own BlockId?  No.  
-
-- If you ask for successors(x) can you get any pointer into x?
-  Answer no.  
-  Simon says: you can can only get a loop in g_blocks.  A singleton
-  block can't be a loop.  
-
-- Client knows about nodes. Our job is to lift to blocks and graphs.
-
-
-* I would love to simplify the Graph type, further, but I don't know
-  how.  In particular, we seem to *need* a function of type
-       lift :: n e x -> Graph n e x
-  to use when the client's rewriting function says Nothing.
-
-  But that forces the slightly 
-
-* Talking to John, we agreed that a common use of Hoopl will be to
-  analyse full graphs, to get a full mapping (BlockId -> fact), for
-  the *internal* nodes of the graph, not just its out-edges.  Inded
-  for a full graph (eg a procedure body) there wil *be* no out-edges.
-
-  So maybe we want 
-     data Graph n e x where
-       ...
-       GMany { 
-       g_entry :: Block n e C,
-       g_blocks :: FullGraph n,
-        ...}
-
-  where
-    newtype FullGraph n = FG [Block n C C]
-  
-  And the client might define a procedure thus:
-
-    data Procedure = Proc BlockId  -- Entry point
-                          (FullGraph CmmNode)
-
-  Now we may imagine
-       GFT_FullGraph n f = GFT (FullGraph n)
-  and the client interface might be exposed for FullGraph.
-  Meanwhile, the recursive invocations of the analysis still
-  work on Graphs.
-
-  So a FullGraph would be a fourth kind of entity (as well as
-  nodes, blocks, graphs), albeit one that is not an instance of
-  Edges.
-
-That would make the signature of analyseAndRewrite look like this:
-
-analyseAndRewrite
-   :: forall n f. Edges n
-   => RewritingDepth
-   -> DataflowLattice f
-   -> ForwardTransfers n f
-   -> ForwardRewrites n f
-   -> GFT_FullGraph n f
-
-where
-  GFT_FullGraph n f = FullGraph n -> InFactC f -> 
-
-* Incidentally, eleveating FullGraph in this way would let
-  us switch to BlockEnv or whatever else we wanted if that 
-  proved convenient.
-
-* Maybe FullGraph should be Graph, and Graph should be PGraph (for
-  partial graph), or SubGraph.
-
-* I was thinking how to do dead-block elimination.  Given a fact
-  (B17 -> Dead), how can I rewrite the block with label B17 to
-  an empty graph?  I'd like to write
-      rewrite fact_fun (Label b) 
-        | fact_fun b == Dead = Just (GUnit (BUnit b `BCat` unreachable))
-        | otherwise          = Nothing
-
-  So what is "unreachable :: Block".  I suppose it's a new constructor
-  of the Block type, that eats all its downstream fellows:
-
-       data Block n e x where
-          BUnr :: Block n O x
-         ...as before...
-
-  It's a bit like the GNil constructor, which is there primarily
-  to allow us to rewrite a node to a no-op.
-
-  Its a bit tiresome that it has be be in Block not Graph, but
-  we still need that Label. 
-
-
-Ideas
-~~~~~
-"Optimization" encompasses:
-  - substitution informed by equational reasoning (about states)
-  - removal of redundant code, as justified by reasoning about
-    continuations
-
-"Code motion" is achieved by inserting redundant code,
-thereby making original code redundant, which in turn
-can be removed.
-
-Technique
-~~~~~~~~~
-No single technique; the secret sauce is how we combine things:
-  - Zipper CFG
-  - Disctinct representations for construction and analyis of CFGs
-  - Maximum use of polymorphism
-  - Type classes to make notation resemble prior art
-  - Transfer equations coded in dragon-book style
-  - Fixed points courtesy Lerner, Grove, and Chambers (2002)
-
-Contribution
-~~~~~~~~~~~~
-We make dataflow optimization easy to think about and easy to build:
-
- * Ideas that reconcile the ad-hoc 'optimization zoo' found in the
-   dragon book with methods of reasoning long understood by functional
-   programmers.
-
- * Design and implementation that make it not just possible but *easy*
-   to use dataflow techniques in your compiler.
-
-
-
----------------------------------
-Working title: Dataflow Optimization Made Simple
-
-Note: By decomposing 'optimizations' into smaller units, we simplify.
-'induction-variable elimination' is *not* an atomic thing!
-
-
----------------------------------
-Vague Outline
-1. Intro
-2. Short example
-3. Logical view of optimization
-4. Clients (examples, including type class declarations)
-5. Graphs
-6. Fixed-point computation; the dataflow monad
-7. Discussion
-
diff --git a/paper/Rew.hs b/paper/Rew.hs
deleted file mode 100644 (file)
index d4bf3c6..0000000
+++ /dev/null
@@ -1,46 +0,0 @@
-module Rew
-where
-
-data Rew a = No
-           | Mk a
-           | Then (Rew a) (Rew a)
-           | Iter (Rew a)
-
-rewrite :: Rew (node -> fact -> Maybe graph)
-        -> node -> fact -> Maybe (graph, Rew (node -> fact -> Maybe graph))
-rewrite_direct rs n f = rew rs
-    where rew No       = Nothing
-          rew (Mk r)   =
-              case r n f of Nothing -> Nothing
-                            Just g -> Just (g, No)
-          rew (r1 `Then` r2) =
-              case rew r1 of
-                Nothing -> rew r2
-                Just (g, r1') -> Just (g, r1' `Then` r2)
-          rew (Iter r) =
-              case rew r of
-                Nothing -> Nothing
-                Just (g, r') -> Just (g, r' `Then` Iter r)
-
-rewrite rs node f = rew rs Just Nothing
- where
-  rew No     j n = n
-  rew (Mk r) j n =
-     case r node f of Nothing -> n
-                      Just g -> j (g, No)
-  rew (r1 `Then` r2) j n = rew r1 (j . add r2) (rew r2 j n)
-  rew (Iter r)       j n = rew r (j . add (Iter r)) n
-  add tail (g, r) = (g, r `Then` tail)
-
-rewritem :: Monad m => Rew (node -> fact -> m (Maybe graph))
-         -> node -> fact -> m (Maybe (graph, Rew (node -> fact -> m (Maybe graph))))
-rewritem rs node f = rew rs (return . Just) (return Nothing)
- where
-  rew No     j n = n
-  rew (Mk r) j n = do mg <- r node f
-                      case mg of Nothing -> n
-                                 Just g -> j (g, No)
-  rew (r1 `Then` r2) j n = rew r1 (j . add r2) (rew r2 j n)
-  rew (Iter r)       j n = rew r (j . add (Iter r)) n
-  add tail (g, r) = (g, r `Then` tail)
-
diff --git a/paper/TODO b/paper/TODO
deleted file mode 100644 (file)
index ead5c64..0000000
+++ /dev/null
@@ -1,26 +0,0 @@
-HOOPL:
-  - get Simon to review Lerner, Ullman & Kam, Kildall
-  - implementation section: why?
-       . really exists
-       . not insane
-       . dramatically simpler than original & other implementations
-       . can see some of the idea
-  - massive failure of parallel structure between sections 3 and 6
-    (three bullets)
-  - Hypothesis:
-
-      if {P} s --> s' by rewrite, and {P} s {Q} and {P} s' {Q'}, then
-      Q \sqsubseteq Q'
-
-      if s {Q} --> s' by rewrite, and {P} s {Q} and {P'} s' {Q}, then
-      P' \sqsubseteq P
-
-    Why do we care?  Is this a theorem?  A requirement?  Do we want
-    implication (in the logic) and not a lattic op?  How does
-    implication translate to lattice ops, anyway?  (disjunction ~ join)
-
-
-
-DFOPT: if any extra room, restore Davidson reference!
-       then: 'to reduce register pressure'
-       then: 2nd dataflow paper
diff --git a/paper/bbl.dias.mk b/paper/bbl.dias.mk
deleted file mode 100644 (file)
index d36fb58..0000000
+++ /dev/null
@@ -1,5 +0,0 @@
-%.bbl:Q: %.aux
-       echo "=== Pretend I ran nbibtex here (use the .bib from the repo to make a .bbl) ==="
-
-%.bib: %.aux
-       echo "=== Pretend I ran nbibtex here (use the .bib from the repo to make a .bbl) ==="
diff --git a/paper/bbl.nr.mk b/paper/bbl.nr.mk
deleted file mode 100644 (file)
index 0935e72..0000000
+++ /dev/null
@@ -1,6 +0,0 @@
-%.bbl: %.aux
-       nbibtex $stem
-
-%.bib: %.aux
-       nbibtex -o $target -bib $stem
-
diff --git a/paper/bbl.simonpj.mk b/paper/bbl.simonpj.mk
deleted file mode 100644 (file)
index ee8c327..0000000
+++ /dev/null
@@ -1,2 +0,0 @@
-%.bbl:Q: %.aux
-       echo "=== Pretend I ran nbibtex here (use the .bbl from the repo) ==="
diff --git a/paper/bitly.dias.mk b/paper/bitly.dias.mk
deleted file mode 100644 (file)
index 33adf52..0000000
+++ /dev/null
@@ -1,3 +0,0 @@
-%.bitly:VQ:
-       # do nothing
\ No newline at end of file
diff --git a/paper/bitly.nr.mk b/paper/bitly.nr.mk
deleted file mode 100644 (file)
index 7be00f1..0000000
+++ /dev/null
@@ -1,3 +0,0 @@
-%.bitly:V: $HOME/www/pubs/%.pdf
-       rsync -avP $prereq linux.cs.tufts.edu:www/pubs/$stem.pdf
-       # do nothing
diff --git a/paper/bitly.simonpj.mk b/paper/bitly.simonpj.mk
deleted file mode 100644 (file)
index 33adf52..0000000
+++ /dev/null
@@ -1,3 +0,0 @@
-%.bitly:VQ:
-       # do nothing
\ No newline at end of file
diff --git a/paper/code.sty b/paper/code.sty
deleted file mode 100644 (file)
index 0e787f0..0000000
+++ /dev/null
@@ -1,94 +0,0 @@
-
-\NeedsTeXFormat{LaTeX2e}
-\ProvidesPackage{code}
-
-
-% I have enclosed code.sty, which achieves 99% of what you want without
-% the need for a separate preprocessor. At the start of your document
-% you write "\makeatactive". From then on, inline code is written as @\x
-% -> x_1 & y@. The only difference with what you are used to, is that
-% instead of
-% 
-% @
-%   foo :: Int -> Int
-%   foo = \n -> n+1
-% @
-% 
-% you have to write
-% 
-% \begin{code}
-%   foo :: Int -> Int
-%   foo = \n -> n+1
-% \end{code}
-% 
-% and that you cannot use @ in \section{} and \caption{}. For the paper that occured twice, in which case I had to replace @...@ b y \texttt{...}.
-% 
-% 
-% code.sty  --- nice verbatim mode for code
-
-% To get '@' use \verb+@+
-
-\def\icode{%
-    \relax\ifmmode\hbox\else\leavevmode\null\fi
-    \bgroup
-    %\begingroup
-    \@noligs
-    \verbatim@font
-    \verb@eol@error
-    \let\do\@makeother \dospecials
-    \@vobeyspaces
-    %\frenchspacing
-    %% next two lines provide more sensible spacing 
-    \@tempdima = \fontdimen2\font\relax
-    \spaceskip = 0.65\@tempdima
-    %%
-    \@icode}
-\def\@icode#1{%
-    \catcode`#1\active
-    \lccode`\~`#1%
-    \lowercase{\let~\icode@egroup}}
-\def\icode@egroup{%
-    %\endgroup}
-    \egroup}
-
-% The \makeatactive command:
-% makes @ active, in such a way that @...@ behaves as \icode@...@:
-{
-\catcode`@=\active
-\gdef\makeatactive{
-     \catcode`@=\active \def@{\icode@}
-     % Since @ becomes active, it has to be taken care of in verbatim-modes:
-     \let\olddospecials\dospecials \def\dospecials{\do\@\olddospecials}}
-}
-% \gdef\makeatother{\g@remfrom@specials{\@}\@makeother\@}
-\gdef\makeatother{\@makeother\@}
-
-\newcommand\codetabwidth{42pt}
-{\catcode`\^^I=\active%
-\gdef\@vobeytab{\catcode`\^^I\active\let^^I\@xobeytab}}
-\def\@xobeytab{\leavevmode\penalty10000\hskip\codetabwidth}
-
-\begingroup \catcode `|=0 \catcode `[= 1
-\catcode`]=2 \catcode `\{=12 \catcode `\}=12
-\catcode`\\=12 |gdef|@xcode#1\end{code}[#1|end[code]]
-|endgroup
-\def\@code{\trivlist \item\relax
-  \if@minipage\else\vskip\parskip\fi
-  \leftskip\@totalleftmargin\rightskip\z@skip
-  \parindent\z@\parfillskip\@flushglue\parskip\z@skip
-  \@@par
-  \@tempswafalse
-  \def\par{%
-    \if@tempswa
-      \leavevmode \null \@@par\penalty\interlinepenalty
-    \else
-      \@tempswatrue
-      \ifhmode\@@par\penalty\interlinepenalty\fi
-    \fi}%
-  \obeylines \verbatim@font \@noligs
-  \let\do\@makeother \dospecials
-  \everypar \expandafter{\the\everypar \unpenalty}%
-}
-\def\code{\@code \frenchspacing\@vobeytab\@vobeyspaces \@xcode}
-\def\endcode{\if@newlist \leavevmode\fi\endtrivlist}
-
diff --git a/paper/defuse b/paper/defuse
deleted file mode 100755 (executable)
index e0d5c7f..0000000
+++ /dev/null
@@ -1,463 +0,0 @@
-#!/usr/bin/env lua
-
-local ignore = { }
-for _, i in ipairs(arg) do ignore[i] = true end
-
-local stringf = string.format
-local function fprintf(f, ...) return f:write(string.format(...)) end
-
-----------------------------------------------------------------
--- table utilities
-
-function table.set(t) -- set of list
-  local u = { }
-  for _, v in ipairs(t) do u[v] = true end
-  return u
-end
-
-function table.sorted_keys(t, lt)
-  local u = { }
-  for k in pairs(t) do table.insert(u, k) end
-  table.sort(u, lt)
-  return u
-end
-
-----------------------------------------------------------------
-
-local oldcontexts, context = { }, 'document'
-local function pushcontext(c)
-  --io.stderr:write(string.rep('  ', #oldcontexts), 'PUSH ', c, '\n')
-  table.insert(oldcontexts, context)
-  context = c
-end
-
-local function popcontext(c)
-  --io.stderr:write(string.rep('  ', #oldcontexts-1), 'POP  ', c, '\n')
-  assert(context == c, 'Current context ' .. context .. ' is not popped context ' .. c)
-  context = assert(table.remove(oldcontexts))
-end
-
-----------------------------------------------------------------
-
-local defnrefs = { }  -- maps ident to pageref or lineref of its defn
-local defcontext, usecontext = { }, { }
-local linelabel = { } -- line number of definition if any
-local marker = { } -- how the defn was marked
-local uses = { } -- set of identifiers used
-local typeof = { } -- type of identifier if given
-local omitted = { } -- 
-local reserved =
-  table.set { 'where', 'let', 'in', '_', '|', '->', '--', '=', '=>',
-              'if', 'then', 'else', 'data', 'type', 'newtype', 'module',
-              'class', 'instance', 'family',
-              'import', 'case', 'of', ';', '{', '}', 'do', '<-', 'forall',
-              '...', -- not really a reserved word, but treated as such
-              '@', -- ditto
-              'goto', -- from low-level code examples
-            }
-
-for id in io.lines 'hsprelude' do
-  defnrefs[id] = 'Prelude'
-  defcontext[id] = 'prelude'
-end
-
-local multiples = { }
-
-local specialnames = { [ '\\' ] = ':bs', ['%'] = ':pe', [':'] = ':co', ['_'] = ':un' }
-
-local function labelquote(id)
-  return (id:gsub('%W', specialnames))
-end
-
-local function labelstring(id)
-  return stringf('haskell.def.%s', labelquote(id))
-end
-
-local function uselabelstring(id)
-  return stringf('haskell.firstuse.%s', labelquote(id))
-end
-
-local figcontexts = table.set { 'figure', 'figure*', 'table', 'table*' }
-local figwaiting, figusewaiting = { }, { }
-
-
-local def_written = { }
-
-local function write_defn(id)
-  if def_written[id] then
-    assert(marker[id] == '^', id .. " multiply defined with marker " .. marker[id])
-  elseif figcontexts[context] then
-    table.insert(figwaiting, id)
-  else
-    def_written[id] = true
-    -- fprintf(io.stderr, 'DEF %q (%s)\n', id, context)
-    io.write(stringf([[\label{%s}]], labelstring(id)), '% automated definition\n')
-  end
-end
-
-local codecontexts =
-  table.set { 'code', 'smallcode', 'smallttcode', 'ttcode',
-              'numberedcode', 'fuzzcode', 'smallfuzzcode' }
-local codeusewaiting = { }
-
-local function write_use(id)
-  if figcontexts[context] then
-    table.insert(figusewaiting, id)
-  elseif codecontexts[context] then
-    table.insert(codeusewaiting, id)
-  else
-    -- fprintf(io.stderr, 'USE %q (%s)\n', id, context)
-    io.write(stringf([[\label{%s}]], uselabelstring(id)), '% automated use\n')
-  end
-end
-
-local function add_defn(d, linelab, mark)
-  if defnrefs[d] and mark == '`' or marker[d] == '`' then
-    multiples[d] = true
-  else
-    defnrefs[d] = labelstring(d)
-    defcontext[d] = context
-    linelabel[d] = linelab
-    marker[d] = mark
-  end
-end
-
-local function add_use(u)
-  if not uses[u] then
-    uses[u] = true
-    usecontext[u] = context
-    write_use(u)
-  end
-end
-
-local function add_omit(d, ty)
-  add_defn(d)
-  omitted[d] = true
-  typeof[d] = ty
-end
-
-----------------------------------------------------------------
-
-local symclass = '[%!%#%$%%%&%*%+%.%/%<%=%>%?%@%\\%^%|%-%~]'
-local wordclass = "[%w_'%.]"
-local sym = symclass .. '+'
-local word = wordclass .. '*' .. wordclass:gsub('%%%.', '')
---word = wordclass .. '+'
-local symbacktick = sym:gsub('^%[', '[%`%^')
-local wordbacktick = word:gsub('%[', '[%`%^')
-
---io.stderr:write(word, '\n')
---io.stderr:write(wordbacktick, '\n')
-
-local function is_literal(id)
-  return id:find '^%d+$'
-end
-
-local function is_comment(id)
-  return id:find '^%-%-+$'
-end
-
-local function is_kind(id)
-  return id == '*' or id and is_kind(id:match('^%*%-%>(.*)$'))
-end
-
-local function find_uses(s)
-  s = s:gsub([[\_]], '_') -- copes with \_ in at-sign land
-  for id in s:gmatch(word) do
-    if not (reserved[id] or ignore[id] or is_literal(id)) then add_use(id) end
-  end
-  for id in s:gmatch(sym) do
-    if not (reserved[id] or ignore[id] or is_kind(id) or is_comment(id)) then add_use(id) end
-  end
-end
-
-
-local comment_pat = '%s+%-%-[%s%w]'
-local comment_line_pat = '^%-%-.*$'
-
-local function strip_stringlit(s)
-  local q = s:find '"'
-  local c = s:find(comment_pat)
-  if q and (not c or q < c) then
-    s = s:gsub('".-"', ''):gsub("'.-'", "") -- misses escaped quote
-    return strip_stringlit(s)
-  else
-    return s
-  end
-end
-
-
-local function strip_comment(c)
-  c = strip_stringlit(c)
-  c = c:gsub('^%s*%.%.%.%s+.-%s+%.%.%.%s*$', '')
-  return (c:gsub(comment_line_pat, ''):gsub(comment_pat .. '.*$', ''))
-end
-
-
-local function add_file_uses(filename)
-  io.stderr:write('============ uses in ', filename, '=============\n')
-  local f = assert(io.open(filename) or io.open(filename .. '.tex'),
-                   "Cannot open " .. filename)
-  for l in f:lines() do
-    find_uses(strip_comment(l))
-  end
-  f:close()
-  return
-end
-----------------------------------------------------------------
-
-local function find_definitions(defs, label)
-  local function got_def(d)
-    d = d:gsub([[\_]], '_') -- copes with \_ in at-sign land
-    -- fprintf(io.stderr, "GOT? %q\n", d)
-    if d:find ('^[%`%^]' .. word .. '$') or d:find ('^[%`%^]' .. sym .. '$') then
---      fprintf(io.stderr, "Matched definition %q\n", d)
-      local marker, d = d:match '^(.)(.*)$'
-      table.insert(defs, d)
-      add_defn(d, label, marker)
-      return d
-    else
-      return d
-    end
-  end
-  return function(s)
-           if false and s:find '[`%^]' then
-             io.stderr:write('DEFN? ', s, '\n')
-           end
-           s = s:gsub('[`%^]' .. symbacktick, got_def)
-           s = s:gsub('[`%^]' .. wordbacktick, got_def)
-           return s
-         end
-end
-
-local function find_definitions_ats(defs)
-  return function(s)
-           return '@' .. find_definitions(defs)(s) .. '@'
-         end
-end
-
-local function strip_def_markers(s)
-  local function got_def(d)
-    if d:find ('^[%`%^]' .. word .. '$') or d:find ('^[%`%^]' .. sym .. '$') then
-      local marker, d = d:match '^(.)(.*)$'
-      return d
-    else
-      return d
-    end
-  end
-  s = s:gsub('[`%^]' .. symbacktick, got_def)
-  s = s:gsub('[`%^]' .. wordbacktick, got_def)
-  return s
-end
-
-
-
-
-local function process_at_signs(l)
-  local defns = { }
-  if l:find '^%%' then
-    io.write(l, '\n')
-  else
-    l = l:gsub('[%s%%]%%.*', ''):gsub('@(.-)@', find_definitions_ats(defns))
-    io.write(l, '\n')
-    for _, d in ipairs(defns) do
-      write_defn(d)
-    end
-    l:gsub('@(.-)@', find_uses)
-  end
-end
-
-----------------------------------------------------------------
-
-local in_document = false
-
-local special = { }
-local endspecial = { }
-
-
-function special.document(line)
-  in_document = true
-  io.write(line, '\n')
-end
-
-function special.code(line, env)
-  local defns = { }
-  local endpat = stringf([[^\end{%s}]], env)
-  io.write(line, '\n')
-  line = io.read()
-  while not line:find(endpat) do
-    -- io.stderr:write('CODE ', line, '\n')
-    local label, code = line:match '^!(.-)!(.*)$'
-    local prefix = ''
-    if label then
-      prefix = '!' .. label .. '!'
-    else
-      code = line
-    end
-    line = find_definitions(defns, label)(strip_comment(code))
-    pushcontext(env)
-    find_uses(strip_comment(code))
-    popcontext(env)
-    io.write(prefix, strip_def_markers(code), '\n')
-    line = io.read()
-  end
-  io.write(line, '\n')
-  for _, d in ipairs(defns) do
-    write_defn(d)
-  end
-  while #codeusewaiting > 0 do
-    write_use(table.remove(codeusewaiting))
-  end
-end
-
-function special.verbatim(line, env)
-  io.write(line, '\n')
-  pushcontext 'verbatim'
-end
-function endspecial.verbatim(line, env)
-  io.write(line, '\n')
-  popcontext 'verbatim'
-end
-for _, env in ipairs { 'smallverbatim', 'alltt' } do
-  special[env] = special.verbatim
-  endspecial[env] = endspecial.verbatim
-end
-
-for c in pairs(codecontexts) do
-  special[c] = special[c] or special.code
-end
-
-function special.figure(line, env)
-  io.write(line, '\n')
-  pushcontext 'figure'
-end
-
-function endspecial.figure(line, env)
-  popcontext 'figure'
-  while #figwaiting > 0 do
-    write_defn(table.remove(figwaiting))
-  end
-  while #figusewaiting > 0 do
-    write_use(table.remove(figusewaiting))
-  end
-  io.write(line, '\n')
-end
-
-for _, env in ipairs { 'figure*', 'table', 'table*' } do
-  special   [env] = special.figure
-  endspecial[env] = endspecial.figure
-end
-
-local line = io.read()
-while line do
-  if line:find 'input.*dfoptdu' then -- skip me
-    io.write('% ====> THIS IS A DERIVED FILE; DO NOT EDIT IT <======\n')
-    io.write('% ===========> SIMON, THIS MEANS YOU! <===============\n')
-  else
-    local env      = line:match [[^%s*\begin(%b{})]]
-    env = env and env:sub(2, -2)
-    local endenv   = line:match [[^%s*\end{(.*)}]]
-    local def      = line:match '^%%%s*defn%s+(%S+)%s*$'
-    local localdef = line:match '^%%%s*local%s+(%S+)%s*$'
-    local omit, ty = line:match '^%%%s*omit%s+(%S+)%s+::%s+(.-)%s*$'
-    local input    = line:match [[^%s*\verbatiminput{(.*)}]] or
-                     line:match [[^%s*\smallverbatiminput{(.*)}]]
-                     line:match [[^%s*\smallfuzzverbatiminput{.-}{(.*)}]]
-if line:match 'fuzzcode' then
---  fprintf(io.stderr, "%s: env = %s, endenv = %s\n", line, env or '<nil>', endenv or '<nil>')
-end
-    if env and special[env] then
-      special[env](line, env)
-    elseif endenv and special[endenv] then
-      if endspecial[endenv] then
-        endspecial[endenv](line, endenv)
-      else
-        io.write(line, '\n')
-      end
-    elseif context == 'verbatim' then
-      io.write(line, '\n')  -- do not look for defs or uses in verbatim environments
-    elseif def then
-      add_defn(def, nil, '`')
-      write_defn(def)
-    elseif localdef then
-      add_defn(localdef, nil, '^')
-      write_defn(localdef)
-    elseif omit then
-      add_omit(omit, ty)
-      write_defn(omit)
-    elseif input then
-      add_file_uses(input)
-      io.write(line, '\n')
-    elseif in_document then
-      process_at_signs(line)
-    else
-      io.write(line, '\n')
-    end
-  end
-  line = io.read()
-end
-
-local function caselt(s1, s2)
-  local l1, l2 = s1:gsub('_', ''):lower(), s2:gsub('_', ''):lower()
-  if l1 == l2 then
-    return s1 < s2 -- upper case first
-  else
-    return l1 < l2
-  end
-end
-
-local defseq = { figure = 'hsfigdef', table = 'hstabdef', prelude = 'hsprelude',
-                 numberedcode = 'hslinedef', document = 'hspagedef' }
-for k, v in pairs(defseq) do defseq[k .. '*'] = v end
-setmetatable(defseq, { __index = function() return 'hspagedef' end })
-
-
-local function escape_specials(s)
-  return (s:gsub([[\]], [[\char`\\]]):gsub('[%&%_%^%$%%]', '\\%1'))
-end
-
-local suffix = { ['`'] = '', ['^'] = 'll' }
-
-local f = io.open('defuse.tex', 'w')
-for _, k in ipairs(table.sorted_keys(defnrefs, caselt)) do
-  local full_k = escape_specials(k)
-  if typeof[k] == '*' then
-    full_k = full_k .. [[\textrm{~(a~type)}]]
-  elseif typeof[k] and typeof[k]:find '%*' then
-    full_k = full_k .. [[\textrm{~(a~type of kind }]] .. typeof[k] .. [[\textrm)]]
-  elseif typeof[k] then
-    full_k = full_k .. ' :: ' .. typeof[k]
-  end
-  if omitted[k] then
-    fprintf(f, [[\omit%s%s{%s}{%s}%s]],
-            defseq[defcontext[k]] .. suffix[marker[k] or '`'],
-            linelabel[k] and '[' .. linelabel[k] .. ']' or '',
-            full_k,
-            defnrefs[k], '% context ' .. (defcontext[k] or '??') .. '\n')
-  else
-    fprintf(f, [[\%s%s{%s}{%s}%s]], defseq[defcontext[k]] .. suffix[marker[k] or '`'],
-            linelabel[k] and '[' .. linelabel[k] .. ']' or '',
-            full_k,
-            defnrefs[k], '% context ' .. (defcontext[k] or '??') .. '\n')
-  end
-end
-
-local function nontrivial(id)
-  return id:len() > 1 and not id:find('^[%lL]%d$') and not id:find("^[%lL]'$")
-end
-
-for _, k in ipairs(table.sorted_keys(uses, caselt)) do
-  if not defnrefs[k] and nontrivial(k) then
-    fprintf(f, [[\not%s{%s}{%s}%s]], defseq[usecontext[k]],
-            escape_specials(k), uselabelstring(k), '% used but not defined\n')
-  end
-end
-f:close()
-
-local had_mult = false
-for _, m in ipairs(table.sorted_keys(multiples)) do
-  fprintf(io.stderr, 'Label %q multiply defined.\n', m)
-  had_mult = true
-end
-
-if had_mult then os.exit(1) end
diff --git a/paper/dfopt.bib b/paper/dfopt.bib
deleted file mode 100644 (file)
index dcbb4a3..0000000
+++ /dev/null
@@ -1,250 +0,0 @@
-@article{lerner-grove-chambers:2002,
-  number = {1},
-  bibdate = {Tue Feb 12 10:39:33 MST 2002},
-  acknowledgement = {Acknowledge Nelson H. F. Beebe},
-  author = {Sorin Lerner and David Grove and Craig Chambers},
-  journal = {Conference Record of the 29th Annual ACM Symposium on Principles of Programming Languages, {\em in} SIGPLAN Notices},
-  annote = {Proceedings of the 29th ACM SIGPLAN-SIGACT symposium on Principles of Programming Languages (POPL'02).},
-  year = {2002},
-  title = {Composing dataflow analyses and transformations},
-  month = {January},
-  coden = {SINODQ},
-  xxxissn = {0362-1340},
-  pages = {270--282},
-  volume = {31},
-}
-
-@inproceedings{ramsey-dias:applicative-flow-graph,
-  notselected = {1},
-  refereed = {1},
-  author = {Norman Ramsey and {Jo\~ao} Dias},
-  pages = {101-122},
-  accepted = {10},
-  year = {2005},
-  blurb = {A control-flow graph for doing classical imperative-style optimization in your functional compiler.},
-  title = {An Applicative Control-Flow Graph Based on {Huet}'s Zipper},
-  submitted = {21},
-  booktitle = {ACM SIGPLAN Workshop on ML},
-  topic = {zipcfg:compiler back ends:reusable code generation:pl infrastructure},
-  base = {zipcfg},
-  month = {September},
-}
-
-@article{whalley:isolation,
-  number = {5},
-  subject = {{\bf D.2.5}: Software, SOFTWARE ENGINEERING, Testing and Debugging, Debugging aids. {\bf D.3.4}: Software, PROGRAMMING LANGUAGES, Processors, Compilers. {\bf D.3.4}: Software, PROGRAMMING LANGUAGES, Processors, Optimization.},
-  keywords = {algorithms; languages},
-  author = {David B. Whalley},
-  journal = {ACM Transactions on Programming Languages and Systems},
-  year = {1994},
-  xxxurl = {http://www.acm.org/pubs/toc/Abstracts/0164-0925/186103.html},
-  abstract = {This paper describes a tool called \emph{vpoiso} that was developed to isolate errors automatically in the \emph{vpo} compiler system. The two general types of compiler errors isolated by this tool are optimization and nonoptimization errors. When isolating optimization errors, \emph{vpoiso} relies on the \emph{vpo} optimizer to identify sequences of changes, referred to as transformations, that result in semantically equivalent code and to provide the ability to stop performing \emph{improving} (or unnecessary) transformations after a specified number have been performed. A compilation of a typical program by \emph{% vpo} often results in thousands of \emph{improving} transformations being performed. The \emph{vpoiso} tool can automatically isolate the first \emph{ improving} transformation that causes incorrect output of the execution of the compiled programs by using a binary search that varies the number of \emph{% improving} transformation performed. Not only is the illegal transformation automatically isolated, but \emph{% vpoiso} also identifies the location and instant the transformation is performed in \emph{vpo}. Nonoptimization errors occur from problems in the front end, code generator, and \emph{necessary} transformations in the optimizer. If another compiler is available that can produce correct (but perhaps more inefficient) code, then \emph{vpoiso} can isolate nonoptimization errors to a single function. Automatic isolation of compiler errors facilitates retargeting a compiler to a new machine, maintenance of the compiler, and supporting experimentation with new optimizations.},
-  title = {Automatic Isolation of Compiler Errors},
-  month = {September},
-  coden = {ATPSDT},
-  xxxissn = {0164-0925},
-  pages = {1648--1659},
-  volume = {16},
-}
-
-@book{appel:modern,
-  publisher = {Cambridge University Press},
-  title = {Modern Compiler Implementation},
-  address = {Cambridge, UK},
-  author = {Andrew W. Appel},
-  note = {Available in three editions: C, Java, and ML},
-  year = {1998},
-}
-
-@techreport{cooper-harvey-kennedy:simple-dominance,
-  institution = {Rice University},
-  year = {2001},
-  abstract = {The problem of finding the dominators in a control-flow graph has a long history in the literature. The original algorithms suffered from a large asymptotic complexity but were easy to understand. Subsequent work improved the time bound, but generally sacrificed both simplicity and ease of implementation. This paper returns to a simple formulation of dominance as a global data-flow problem. Some insights into the nature of dominance lead to an implementation of an O(N 2) algorithm that runs faster, in practice, than the classic Lengauer-Tarjan algorithm, which has a timebound of O(E ∗ log(N)). Wecompare the algorithm to Lengauer-Tarjan because it is the best known and most widely used of the fast algorithms for dominance. Working from the same implementation insights, we also rederive (from earlier work on control dependence by Ferrante, et al.) amethod},
-  location = {http://www.scientificcommons.org/42542735},
-  author = {Keith D. Cooper and Timothy J. Harvey and Ken Kennedy},
-  note = {Unpublished report available from \url{http://www.hipersoft.rice.edu/grads/publications/dom14.pdf}},
-  title = {A Simple, Fast Dominance Algorithm},
-}
-
-@article{kam-ullman:global-iterative-analysis,
-  number = {1},
-  bibdate = {2003-11-20},
-  bibsource = {DBLP, http://dblp.uni-trier.de/db/journals/jacm/jacm23.html#KamU76},
-  author = {John B. Kam and Jeffrey D. Ullman},
-  journal = {Journal of the ACM},
-  year = {1976},
-  volume = {23},
-  xxxurl = {http://doi.acm.org/10.1145/321921.321938},
-  pages = {158--171},
-  title = {Global Data Flow Analysis and Iterative Algorithms},
-}
-
-@inproceedings{kildall:unified-optimization,
-  title = {A unified approach to global program optimization},
-  month = {October},
-  booktitle = {Conference Record of the ACM Symposium on Principles of Programming Languages},
-  author = {Gary A. Kildall},
-  pages = {194--206},
-  year = {1973},
-}
-
-@article{kam-ullman:monotone-flow-analysis,
-  title = {Monotone Data Flow Analysis Frameworks},
-  volume = {7},
-  year = {1977},
-  author = {John B. Kam and Jeffrey D. Ullman},
-  journal = {Acta Informatica},
-  pages = {305--317},
-}
-
-@inproceedings{cousot:abstract-interpretation:1977,
-  xxxaddress = {Los Angeles, California},
-  author = {Patrick Cousot and Radhia Cousot},
-  annote = {Very theoretical.},
-  title = {Abstract Interpretation: {A} Unified Lattice Model for Static Analysis of Programs by Construction or Approximation of Fixpoints},
-  month = {January},
-  year = {1977},
-  where = {filed with reprints},
-  pages = {238--252},
-  booktitle = {Conference Record of the 4th ACM Symposium on Principles of Programming Languages},
-}
-
-@inproceedings{cousot:systematic-analysis-frameworks,
-  title = {Systematic Design of Program Analysis Frameworks},
-  month = {January},
-  year = {1979},
-  author = {Patrick Cousot and Radhia Cousot},
-  pages = {269--282},
-  booktitle = {Conference Record of the 6th Annual ACM Symposium on Principles of Programming Languages},
-}
-
-@inproceedings{steffen:data-flow-analysis-model-checking:1991,
-  xxxpublisher = {Springer-Verlag},
-  xxxaddress = {London, UK},
-  title = {Data Flow Analysis as Model Checking},
-  pages = {346--365},
-  year = {1991},
-  booktitle = {TACS '91: Proceedings of the International Conference on Theoretical Aspects of Computer Software},
-  xxxisbn = {3-540-54415-1},
-  author = {Steffen, Bernhard},
-}
-
-@inproceedings{schmidt:data-flow-analysis-model-checking,
-  bibdate = {Mon May 3 12:57:52 MDT 1999},
-  xxxdress = {pub-ACM:adr},
-  acknowledgement = {Nelson H. F. Beebe, University of Utah, Department of Mathematics, 110 LCB, 155 S 1400 E RM 233, Salt Lake City, UT 84112-0090, USA, Tel: +1 801 581 5254, FAX: +1 801 581 4148, e-mail: \path|beebe@math.utah.edu|, \path|beebe@acm.org|, \path|beebe@computer.org| (Internet), URL: \path|http://www.math.utah.edu/~beebe/|},
-  subject = {{\bf D.3.4} Software, PROGRAMMING LANGUAGES, Processors, Optimization. {\bf D.2.2} Software, SOFTWARE ENGINEERING, Design Tools and Techniques, Flow charts. {\bf D.2.4} Software, SOFTWARE ENGINEERING, Software/Program Verification, Model checking. {\bf D.4.8} Software, OPERATING SYSTEMS, Performance, Modeling and prediction.},
-  author = {David A. Schmidt},
-  xxxpublisher = {ACM Press},
-  keywords = {algorithms; verification},
-  editor = {ACM},
-  xxxurl = {http://www.acm.org:80/pubs/citations/proceedings/plan/268946/p38-schmidt/},
-  title = {Data flow analysis is model checking of abstract interpretations},
-  bibsource = {http://www.acm.org/pubs/toc/},
-  year = {1998},
-  xxxisbn = {0-89791-979-3},
-  pages = {38--48},
-  booktitle = {Conference Record of the 25th Annual ACM Symposium on Principles of Programming Languages},
-}
-
-@article{marlowe-ryder:properties-data-flow-frameworks,
-  number = {2},
-  xxxaddress = {Secaucus, NJ, USA},
-  author = {Marlowe, Thomas J. and Ryder, Barbara G.},
-  journal = {Acta Informatica},
-  publisher = {Springer-Verlag New York, Inc.},
-  year = {1990},
-  volume = {28},
-  doi = {http://dx.doi.org/10.1007/BF01237234},
-  xxxissn = {0001-5903},
-  pages = {121--163},
-  title = {Properties of data flow frameworks: a unified model},
-}
-
-@book{muchnick:compiler-implementation,
-  bibdate = {Thu Sep 11 07:11:02 1997},
-  price = {US\$89.95},
-  author = {Steven S. Muchnick},
-  xxxisbn = {1-55860-320-4},
-  publisher = {Morgan Kaufmann},
-  year = {1997},
-  address = {San Mateo, CA},
-  lccn = {QA76.76.C65M8 1997},
-  pages = {1004},
-  title = {Advanced compiler design and implementation},
-}
-
-@inproceedings{hendren:soot:2000,
-  xxxpublisher = {Springer-Verlag},
-  xxxaddress = {London, UK},
-  title = {Optimizing {Java} Bytecode Using the {Soot} Framework: Is It Feasible?},
-  pages = {18--34},
-  year = {2000},
-  booktitle = {CC '00: Proceedings of the 9th International Conference on Compiler Construction},
-  xxxisbn = {3-540-67263-X},
-  author = {Vall\'{e}e-Rai, Raja and Gagnon, Etienne and Hendren, Laurie J. and Lam, Patrick and Pominville, Patrice and Sundaresan, Vijay},
-}
-
-@inproceedings{necula:cil:2002,
-  xxxpublisher = {Springer-Verlag},
-  xxxaddress = {London, UK},
-  title = {{CIL}: Intermediate Language and Tools for Analysis and Transformation of {C}~Programs},
-  pages = {213--228},
-  year = {2002},
-  booktitle = {CC '02: Proceedings of the 11th International Conference on Compiler Construction},
-  xxxisbn = {3-540-43369-4},
-  author = {Necula, George C. and McPeak, Scott and Rahul, Shree Prakash and Weimer, Westley},
-}
-
-@article{knoop:lazy-code-motion,
-  number = {7},
-  bibdate = {Fri Feb 14 18:40:11 MST 1997},
-  bibsource = {Compendex database},
-  affiliation = {Christian-Albrechts-Univ},
-  xxxisbn = {0-89791-475-9},
-  abstract = {We present a bit-vector algorithm for the optimal and economical placement of computations within flow graphs, which is as efficient as standard uni-directional analyses. The point of our algorithm is the decomposition of the bi-directional structure of the known placement algorithms into a sequence of a backward and a forward analysis, which directly implies the efficiency result. Moreover, the new compositional structure opens the algorithm for modification: two further uni-directional analysis components exclude any unnecessary code motion. This laziness of our algorithm minimizes the register pressure, which has drastic effects on the run-time behaviour of the optimized programs in practice, where an economical use of registers is essential.},
-  volume = {27},
-  conference = {Proceedings of the ACM SIGPLAN '92 Conference on Programming Language Design and Implementation},
-  xxxissn = {0362-1340},
-  pages = {224--234},
-  journalabr = {SIGPLAN Not},
-  classification = {723.1},
-  affiliationaddress = {Kiel, Ger},
-  acknowledgement = {Acknowledge Nelson H. F. Beebe},
-  sponsor = {ACM},
-  lccn = {QA76.7.S53 1992},
-  journal = {Proceedings of the ACM SIGPLAN '92 Conference on Programming Language Design and Implementation, {\em in} SIGPLAN Notices},
-  meetingdate2 = {06/17--19/92},
-  meetingdate = {Jun 17--19 1992},
-  keywords = {Bit-vector data flow analyses; Code motion; Computer programming; Data flow analysis; Partial redundancy elimination; Program debugging; Program optimization},
-  title = {Lazy code motion},
-  meetingaddress = {San Francisco, CA, USA},
-  conferenceyear = {1992},
-  author = {Jens Knoop and Oliver Ruething and Bernhard Steffen},
-  coden = {SINODQ},
-  year = {1992},
-}
-
-@article{cocke-kennedy:operator-strength-reduction,
-  number = {11},
-  path = {john-cocke/strength-reduction.pdf},
-  author = {Cocke, John and Kennedy, Ken},
-  journal = {Communications of the ACM},
-  xxxaddress = {New York, NY, USA},
-  xxxpublisher = {ACM},
-  year = {1977},
-  volume = {20},
-  doi = {http://doi.acm.org/10.1145/359863.359888},
-  xxxissn = {0001-0782},
-  pages = {850--856},
-  title = {An Algorithm for Reduction of Operator Strength},
-}
-
-@unpublished{runciman:increasing-prs,
-  note = {Reduceron Memo~50, \url{www.cs.york.ac.uk/fp/reduceron}},
-  title = {Finding and increasing {PRS} candidates},
-  month = {June},
-  author = {Colin Runciman},
-  year = {2010},
-}
-
diff --git a/paper/dfopt.tex b/paper/dfopt.tex
deleted file mode 100644 (file)
index f51fa83..0000000
+++ /dev/null
@@ -1,4043 +0,0 @@
-\newif\ifhaskellworkshop\haskellworkshoptrue
-\newif\ifbanner\bannertrue
-
-
-\iffalse
-
-Payload: alternatives for functions polymorphic in node type
-
-  (n C O -> a, n C O -> b, n C O -> c)
-
-vs
-
-  (forall e x . n e x -> ShapeTag e x, forall e x . n e x -> result e x)
-
-where 
-
-  data ShapeTag e x where
-    First  :: ShapeTag C O
-    Middle :: ShapeTag O O
-    Last   :: ShapeTag O C
-
-  result C O = a
-  result O O = b
-  result O C = c
-
-The function returning ShapeTag can be passed in a type-class
-dictionary. 
-
-
-
-
-Say something about the proliferation of heavyweight type signatures
-required for GADT pattern matches.  When the signature is three times
-the size of the function, something is wrong...
-
-
-I'm going to leave this point out, because in all the client code
-we've written, we are (a) matching only on a node, and (b) matching on
-all cases.  In this scenario the GADT exhaustiveness checker provides
-no additional benefits.  Indeed, GADTs can be an irritant to the
-client: in many pattern matches, GADTs make it impossible to default
-cases.
-
-
-I was thinking again about unwrapped nodes, cons-lists, snoc-lists,
-and tree fringe.  I think there's an analogy with ordinary lists, and
-the analogy is 'concatMap' vs 'fold'.  Just as with lists, the common
-case of 'concatMap (\a -> [a])' does a lot of unnecessary wrapping and
-unwrapping of elements.  We nevertheless prefer 'concatMap' because it
-provides better separation of concerns.  But this analogy suggests
-several ideas:
-
-  - Can block processing be written in higher-order fashion?
-
-  - Can it be done in both styles (concatMap *and* fold)?
-
-  - Once we have framed the problem in these terms, can we write
-    fold-style cold that is not too hard to understand and maintain?
-
-  - Finally, is there an analog of stream fusion that would work for
-    control-flow graphs, enabling us to write some graph combinators
-    that be both perspicuous and efficient?
-
-These are good observations for the paper and for future work.
-
-
-----------------------------------------------------------------
-
-
-P.S. The three of us should have a nice little Skype chat about
-higher-rank types.  A lot of the questions still at issue boil down to
-the following observations:
-
-  - It's really convenient for the *implementation* of Hoopl to put
-    forall to the left of an arrow.  Polymorphic functions as
-    arguments are powerful and keen, and they make it really easy for
-    Hoopl to do its job.
-
-  - It's a bid inconvenient for a *client* of Hoopl to be forced to
-    supply functions that are polymorphic in shape.  All constructors
-    have to be written out by hand; defaulting is not possible.  (Or
-    at least John and I haven't figured out how to do it.)
-
-  - Using higher-rank types in Hoopl's interface makes some very
-    desirable things downright impossible:
-
-      - One can't write a generic dominator analysis with type
-
-           dom :: NonLocal n => FwdPass n Dominators
-
-      - One can't write a generic debugging wrapper of type
-
-           debug :: (Show n, Show f)
-                 => TraceFn -> WhatToTrace -> FwdPass n f -> FwdPass n f
-
-      - One can't write a combinator of type
-
-           product :: FwdPass n f -> FwdPass n f' -> FwdPass n (f, f')
-
-    I submit that these things are all very desirable.
-
-I'm therefore strongly in favor of removing the *requirement* that a
-FwdPass include transfer and rewrite functions that are polymorphic in
-shape.  It will be a bit tedious to return to triples of functions,
-but for those lucky clients who *can* write polymorphic functions and
-who wish to, we can provide injection functions.
-
-I should stress that I believe the tedium can be contained within
-reasonable bounds---for example, the arfXXX functions that are
-internal to Hoopl all remain polymorphic in shape (although not
-higher-rank any longer).
-
-\fi
-
-
-%
-% TODO
-%
-%
-% AGraph = graph under construction
-% Graph = replacement graph
-%
-%%%  Hoopl assumes that the replacement graph for a node open on exit
-%%%  doesn't contain any additional exits
-%%%  
-%%%  introduce replacement graph in section 3, after graph.
-%%%  it has arbitrarily complicated internal control flow, but only
-%%%  one exit (if open on exit)
-%%%  
-%%%  a rquirement on the client that is not checked statically.
-
-
-\input{dfoptdu.tex}
-
-\newif\ifpagetuning \pagetuningtrue  % adjust page breaks
-
-\newif\ifnoauthornotes \noauthornotesfalse
-
-\newif\iftimestamp\timestamptrue  % show MD5 stamp of paper
-
-% \timestampfalse % it's post-submission time
-
-\IfFileExists{timestamp.tex}{}{\timestampfalse}
-
-\newif\ifnotcutting\notcuttingfalse
-
-
-\newif\ifgenkill\genkillfalse  % have a section on gen and kill
-\genkillfalse
-
-
-\newif\ifnotesinmargin \notesinmarginfalse
-\IfFileExists{notesinmargin.tex}{\notesinmargintrue}{\relax}
-
-\documentclass[blockstyle,natbib]{sigplanconf}
-
-\newcommand\ourlib{Hoopl}
-   % higher-order optimization library
-   % ('Hoople' was taken -- see hoople.org)
-\let\hoopl\ourlib
-
-\newcommand\ag{\ensuremath{\mathit{ag}}}
-\renewcommand\ag{\ensuremath{g}}  % not really seeing that 'ag' is helpful here ---NR
-\newcommand\rw{\ensuremath{\mathit{rw}}}
-
-% l2h substitution ourlib Hoopl
-% l2h substitution hoopl Hoopl
-
-\newcommand\fs{\ensuremath{\mathit{fs}}} % dataflow facts, possibly plural
-
-\newcommand\vfilbreak[1][\baselineskip]{%
-  \vskip 0pt plus #1 \penalty -200 \vskip 0pt plus -#1 }
-
-\usepackage{alltt}
-\usepackage{array}
-\usepackage{afterpage}
-\newcommand\lbr{\char`\{}
-\newcommand\rbr{\char`\}}
-\clubpenalty=10000
-\widowpenalty=10000
-
-\usepackage{verbatim} % allows to define \begin{smallcode}
-\newenvironment{smallcode}{\par\unskip\small\verbatim}{\endverbatim}
-\newenvironment{fuzzcode}[1]{\par\unskip\hfuzz=#1 \verbatim}{\endverbatim}
-\newenvironment{smallfuzzcode}[1]{\par\unskip\small\hfuzz=#1 \verbatim}{\endverbatim}
-\newenvironment{smallttcode}{\par\unskip\small\alltt}{\endalltt}
-\newenvironment{ttcode}{\par\unskip\alltt}{\endalltt}
-
-\newcommand\smallverbatiminput[1]{{\par\unskip\small\verbatiminput{#1}}}
-\newcommand\smallfuzzverbatiminput[2]{{\par\unskip\small\hfuzz=#1 \verbatiminput{#2}}}
-
-\newcommand\lineref[1]{line~\ref{line:#1}}
-\newcommand\linepairref[2]{lines \ref{line:#1}~and~\ref{line:#2}}
-\newcommand\linerangeref[2]{\mbox{lines~\ref{line:#1}--\ref{line:#2}}}
-\newcommand\Lineref[1]{Line~\ref{line:#1}}
-\newcommand\Linepairref[2]{Lines \ref{line:#1}~and~\ref{line:#2}}
-\newcommand\Linerangeref[2]{\mbox{Lines~\ref{line:#1}--\ref{line:#2}}}
-
-\makeatletter
-
-\def\ps@plain{%
-  \def \@evenfoot {\scriptsize \hfil \thepage \hfil}%
-  \let\@oddfoot\@evenfoot
-}
-
-\let\old@settitlebanner=\@settitlebanner
-\def\@settitlebanner{\begingroup
-  \@setflag\@preprint=\@true
-  \old@settitlebanner
-  \endgroup
-}
-
-\def \@copyrightspace {%
- \@float{copyrightbox}[b]%
- \vbox to 0.8in{%  less than 1in, please
-   \vfill
-   \parbox[b]{20pc}{%
-     \scriptsize
-     \if \@preprint
-       [Copyright notice will appear here
-        once 'preprint' option is removed.]\par
-     \else
-       \@toappear
-     \fi
-     \if \@reprint
-       \noindent Reprinted from \@conferencename,
-       \@proceedings,
-       \@conferenceinfo,
-       pp.~\number\thepage--\pageref{sigplanconf@finalpage}.\par
-     \fi}}%
- \end@float}
-
-
-\let\c@table=
-           \c@figure % one counter for tables and figures, please
-
-
-\newcommand\setlabel[1]{%
-  \setlabel@#1!!\@endsetlabel
-}
-\def\setlabel@#1!#2!#3\@endsetlabel{%
-  \ifx*#1*% line begins with label or is empty
-     \ifx*#2*% line is empty
-        \verbatim@line{}%
-     \else
-       \@stripbangs#3\@endsetlabel%
-       \label{line:#2}%
-     \fi
-  \else
-     \@stripbangs#1!#2!#3\@endsetlabel%
-  \fi
-}
-\def\@stripbangs#1!!\@endsetlabel{%
-  \verbatim@line{#1}%
-}
-
-
-\verbatim@line{hello mama}
-
-\newcommand{\numberedcodebackspace}{0.5\baselineskip}
-
-\newcounter{codeline}
-\newenvironment{numberedcode}
-  {\endgraf
-     \def\verbatim@processline{%
-        \noindent
-        \expandafter\ifx\expandafter+\the\verbatim@line+  % blank line
-               %{\small\textit{\def\rmdefault{cmr}\rmfamily\phantom{00}\phantom{: \,}}}%
-            \else
-               \refstepcounter{codeline}%
-               {\small\textit{\def\rmdefault{cmr}\rmfamily\phantom{00}\llap{\arabic{codeline}}: \,}}%
-            \fi
-        \expandafter\setlabel\expandafter{\the\verbatim@line}%
-        \expandafter\ifx\expandafter+\the\verbatim@line+  % blank line
-          \vspace*{-\numberedcodebackspace}\par%
-        \else
-          \the\verbatim@line\par
-        \fi}%
-   \verbatim
-   }
-   {\endverbatim}
-
-\makeatother
-
-\newcommand\arrow{\rightarrow}
-
-\newcommand\join{\sqcup}
-\newcommand\slotof[1]{\ensuremath{s_{#1}}}
-\newcommand\tempof[1]{\ensuremath{t_{#1}}}
-\let\tempOf=\tempof
-\let\slotOf=\slotof
-
-\makeatletter
-\newcommand{\nrmono}[1]{%
-  {\@tempdima = \fontdimen2\font\relax
-   \texttt{\spaceskip = 1.1\@tempdima #1}}}
-\makeatother
-
-\usepackage{times}  % denser fonts
-\renewcommand{\ttdefault}{aett} % \texttt that goes better with times fonts
-\usepackage{enumerate}
-\usepackage{url}
-\usepackage{graphicx}
-\usepackage{natbib}  % redundant for Simon
-\bibpunct();A{},
-\let\cite\citep
-\let\citeyearnopar=\citeyear
-\let\citeyear=\citeyearpar
-
-\usepackage[ps2pdf,bookmarksopen,breaklinks,pdftitle=Hoopl]{hyperref}
-\usepackage{breakurl} % enables \burl
-
-\newcommand\naive{na\"\i ve}
-\newcommand\naively{na\"\i vely}
-\newcommand\Naive{Na\"\i ve}
-
-\usepackage{amsfonts}
-\newcommand\naturals{\ensuremath{\mathbb{N}}}
-\newcommand\true{\ensuremath{\mathbf{true}}}
-\newcommand\implies{\supseteq}  % could use \Rightarrow?
-
-\newcommand\PAL{\mbox{C{\texttt{-{}-}}}}
-\newcommand\high[1]{\mbox{\fboxsep=1pt \smash{\fbox{\vrule height 6pt
-   depth 0pt width 0pt \leavevmode \kern 1pt #1}}}}
-
-\usepackage{tabularx}
-
-%%
-%% 2009/05/10: removed 'float' package because it breaks multiple
-%% \caption's per {figure} environment.   ---NR
-%%
-%%  % Put figures in boxes --- WHY??? --NR
-%%  \usepackage{float}
-%%  \floatstyle{boxed}
-%%  \restylefloat{figure}
-%%  \restylefloat{table}
-
-
-
-% ON LINE THREE, set \noauthornotestrue to suppress notes (or not)
-
-%\newcommand{\qed}{QED}
-\ifnotesinmargin
-  \long\def\authornote#1{%
-      \ifvmode
-         \marginpar{\raggedright\hbadness=10000
-         \parindent=8pt \parskip=2pt
-         \def\baselinestretch{0.8}\tiny
-         \itshape\noindent #1\par}%
-      \else
-          \unskip\raisebox{-3.5pt}{\rlap{$\scriptstyle\diamond$}}%
-          \marginpar{\raggedright\hbadness=10000
-         \parindent=8pt \parskip=2pt
-         \def\baselinestretch{0.8}\tiny
-         \itshape\noindent #1\par}%
-      \fi}
-\else
-  % Simon: please set \notesinmarginfalse on the first line
-  \long\def\authornote#1{{\em #1\/}}
-\fi
-\ifnoauthornotes
-  \def\authornote#1{\unskip\relax}
-\fi
-
-\long\def\newtext#1{{\mbox{$\clubsuit$}}{\slshape\ignorespaces#1}{\mbox{$\clubsuit$}}}
-\newenvironment{ntext}{\mbox{$\clubsuit$}\slshape\ignorespaces}{\mbox{$\clubsuit$}}
-
-\newcommand{\simon}[1]{\authornote{SLPJ: #1}}
-\newcommand{\norman}[1]{\authornote{NR: #1}}
-\let\remark\norman
-\def\finalremark#1{\relax}
-%\let \finalremark \remark % uncomment after submission
-\newcommand{\john}[1]{\authornote{JD: #1}}
-\newcommand{\todo}[1]{\textbf{To~do:} \emph{#1}}
-\newcommand\delendum[1]{\relax\ifvmode\else\unskip\fi\relax}
-
-\newcommand\secref[1]{Section~\ref{sec:#1}}
-\newcommand\secreftwo[2]{Sections \ref{sec:#1}~and~\ref{sec:#2}}
-\newcommand\seclabel[1]{\label{sec:#1}}
-
-\newcommand\figref[1]{Figure~\ref{fig:#1}}
-\newcommand\figreftwo[2]{Figures \ref{fig:#1}~and~\ref{fig:#2}}
-\newcommand\figlabel[1]{\label{fig:#1}}
-
-\newcommand\tabref[1]{Table~\ref{tab:#1}}
-\newcommand\tablabel[1]{\label{tab:#1}}
-
-
-\newcommand{\CPS}{\textbf{StkMan}}    % Not sure what to call it.
-
-
-\usepackage{code}   % At-sign notation
-
-\IfFileExists{timestamp.tex}{\input{timestamp}}{}
-\iftimestamp
-\preprintfooter{\mdfivestamp}
-\fi
-
-\hyphenation{there-by op-ti-mi-za-tion poly-mor-phic}
-
-\renewcommand{\floatpagefraction}{0.9} % must be less than \topfraction
-\renewcommand{\topfraction}{0.95}
-\renewcommand{\textfraction}{0.05}
-
-\begin{document}
-%\title{\ourlib: Dataflow Optimization Made Simple}
-\title{\ourlib: A Modular, Reusable Library for\\ Dataflow Analysis and Transformation}
-%\title{Implementing Dataflow Analysis and Optimization by Lifting Node Functions to Basic Blocks and Control-Flow Graphs}
-%\subtitle{Programming pearl}
-
-\titlebanner{\textsf{\mdseries\itshape
-To appear in the 2010 ACM Haskell Symposium (without appendices).
-}}
-
-\conferenceinfo{Haskell'10,} {September 30, 2010, Baltimore, Maryland, USA.}
-\CopyrightYear{2010}
-\copyrightdata{978-1-4503-0252-4/10/09}
-
-\ifnoauthornotes
-\makeatletter
-\let\HyPsd@Warning=
-                \@gobble
-\makeatother
-\fi
-
-% João
-
-
-\authorinfo{Norman Ramsey}{Tufts University}{nr@cs.tufts.edu}
-\authorinfo{Jo\~ao Dias}{Tufts University}{dias@cs.tufts.edu}
-\authorinfo{Simon Peyton Jones}{Microsoft Research}{simonpj@microsoft.com}
-
-
-\maketitle
-\newcommand\webversion{\url{http://bit.ly/cZ7ts1}}.
-
-
-\begin{abstract}
-%\simon{Here is an alternative abstract based on the four-sentence model.}
-%\remark{Four-sentence model?  You must teach me\ldots}
-Dataflow analysis and transformation of control-flow graphs is
-pervasive in optimizing compilers, but it is typically
-entangled with the details of a \emph{particular} compiler.  
-We~describe \ourlib{}, a~reusable library that makes it
-unusually easy to define new analyses and
-transformations for \emph{any} compiler written in Haskell.
-\ourlib's interface is modular and polymorphic,
-and it offers unusually strong static guarantees.
-The implementation encapsulates 
-state-of-the-art algorithms (interleaved analysis and rewriting,
-dynamic error isolation), and it cleanly separates their tricky elements
-so that they can be understood independently.
-%
-%\ourlib\ will be the workhorse of a new
-%back end for the Glasgow Haskell Compiler (version~6.14, forthcoming).
-
-
-%%  \emph{Readers:} code examples are indexed at 
-%%  \iffalse % one more line on page 1 blows up the paper...
-%%  {\url{http://bit.ly/doUJpr}}
-%%  \else
-%%  {\url{http://www.cs.tufts.edu/~nr/pubs/hoopl10-supplement.pdf}} 
-%%  (\url{bit.ly/doUJpr}).
-
-\emph{Readers:} Code examples are indexed at \webversion.
-%{\url{http://www.cs.tufts.edu/~nr/pubs/hoopl10.pdf}}.
-\end{abstract}
-
-\makeatactive   %  Enable @foo@ notation
-
-
-\category{D.3.4}{Processors}{Optimization, Compilers}
-\category{D.3.2}{Language Classifications}{Applicative (functional)
-languages, Haskell}
-
-\terms
-Algorithms, Design, Languages
-
-%\keywords
-%Dataflow analysis
-
-\section{Introduction}
-
-A mature optimizing compiler for an imperative language includes many
-analyses, the results of which justify the optimizer's
-code-improving transformations.
-Many analyses and transformations---constant
-propagation, live-variable analysis, inlining, sinking of loads, 
-and so on---should be regarded as particular cases of
-a single general problem: \emph{dataflow analysis and optimization}.
-%% \remark{I do not feel compelled to cite Muchnick (or anyone else) here}
-Dataflow analysis is over thirty years old,
-but a recent, seminal paper by \citet{lerner-grove-chambers:2002} goes further, 
-describing a powerful but subtle way to
-\emph{interleave} analysis and transformation so that each 
-piggybacks on the other.
-
-Because optimizations based on dataflow analysis 
-share a common intellectual framework, and because that framework is
-subtle, it~is tempting to
-try to build a single, reusable library that embodies the 
-subtle ideas, while
-making it easy for clients to instantiate the library for different
-situations.
-% Tempting, but difficult.
-Although such libraries exist, as we discuss 
-in \secref{related}, they have complex APIs and implementations,
-and none interleaves analysis with transformation.
-
-In this paper we present \ourlib{} (short for ``higher-order
-optimization library''), a new Haskell library for dataflow analysis and
-optimization.  It has the following distinctive characteristics:
-
-\begingroup
-\advance\parskip by 0.0pt plus 0.5pt minus 0.5pt
-\advance\itemsep by 0.0pt plus 0.5pt minus 0.5pt
-\begin{itemize}
-\item
-\ourlib\ is purely functional.  
-Although pure functional languages are not obviously suited to writing
-standard algorithms that
-transform control-flow graphs,
-pure functional code is actually easier to write, and far easier
-to write correctly, than code that is mostly functional but uses a mutable
-representation of graphs
-\cite{ramsey-dias:applicative-flow-graph}.
-When analysis and transformation
-are interleaved, so that graphs must be transformed \emph{speculatively},
-without knowing whether
-a~transformed graph will be retained or discarded,
-pure functional code offers even more benefits.
-
-\item
-\ourlib\ is polymorphic. Just as a list library is
-polymorphic in the list elements, so is \ourlib{} polymorphic, both in
-the nodes that inhabit graphs and in the dataflow facts that 
-analyses compute over these graphs (\secref{using-hoopl}).
-
-\item
-The paper by Lerner, Grove, and Chambers is inspiring but abstract.
-We articulate their ideas in a concrete, simple API,
-which hides 
-a subtle implementation
-(\secreftwo{graph-rep}{using-hoopl}).  
-You~provide a representation for facts, 
-a~transfer function that transforms facts across nodes, 
-and a rewrite function that can use a fact to 
-justify rewriting a node.
-\ourlib\ ``lifts'' these node-level functions to work over
-control-flow graphs, solves recursion equations,
-and interleaves rewriting with analysis.
-Designing APIs is surprisingly
-hard; after a dozen significantly different
-iterations, we offer our API as a contribution.
-
-\item
-\seclabel{liveness-mention}
-Because clients
-can perform very local reasoning (``@y@ is live before
-@x:=y+2@''),
- analyses and transformations built on \ourlib\ 
-are small, simple, and easy to get right.
-Moreover, \ourlib\ helps you write correct optimizations:
-statically, 
-it~rules out transformations that violate invariants
-of the control-flow graph (Sections \ref{sec:graph-rep} and \ref{sec:rewrites}),
-and dynamically, it can help find the first transformation that introduces a fault
-in a test program (\secref{fuel}). 
-%%\finalremark{SLPJ: I wanted to write more about open/closed,
-%%but I like this sentence with its claim to both static and dynamic assistance,
-%%and maybe the open/closed story is hard to understand here.}
-
-% \item \ourlib{} makes use of GADTS and type functions to offer unusually
-% strong static guarantees. In particular, nodes, basic blocks, and
-% graphs are all statically typed by their open or closedness on entry, and
-% their open or closedness on exit (\secref{graph-rep}). For example, an add instruction is
-% open on entry and exit, while a branch is open on entry and closed on exit.
-% Using these types we can statically guarantee that, say, an add instruction
-% is rewritten to a graph that is also open at both entry and exit; and 
-% that the user cannot construct a block where an add instruction follows an
-% unconditional branch.  We know of no other system that offers 
-% static guarantees this strong.
-
-\item \ourlib{} implements subtle algorithms, including 
-(a)~interleaved analysis and rewriting, (b)~speculative rewriting,
-(c)~computing fixed points, and (d)~dynamic fault isolation.
-Previous implementations of these algorithms---including three of our
-own---are complicated and hard to understand, because the tricky pieces
-are implemented all together, inseparably. 
-In~this paper, each tricky piece is handled in just 
-one place, separate from the others (\secref{engine}). 
-We~emphasize this implementation as an object of interest in
-its own right.
-\end{itemize}
-Our work bridges the gap between abstract, theoretical presentations
-and actual compilers. 
-\ourlib{} is available from
-\burl{http://ghc.cs.tufts.edu/hoopl} and also from Hackage (version~3.8.6.0).
-One of \hoopl's clients
-is the Glasgow Haskell Compiler, which uses \hoopl\ to optimize 
-imperative code in GHC's back end.
-
-\ourlib's API is made possible by
-sophisticated aspects of Haskell's type system, such
-as higher-rank polymorphism, GADTs, and type functions.
-\ourlib{} may therefore also serve as a case study in the utility
-of these features.
-\endgroup % tight paragraphs
-
-% \clearpage % Start section 2 on page 2
-
-\section{Dataflow analysis {\&} transformation by \texorpdfstring{\rlap{example}}{example}}
-\seclabel{overview}
-\seclabel{constant-propagation}
-\seclabel{example:transforms}
-\seclabel{example:xforms}
-
-%%  We begin by setting the scene, introducing some vocabulary, and
-%%  showing a small motivating example.
-A \emph{control-flow graph}, perhaps representing the body of a procedure,
-is a collection of \emph{basic blocks}---or just ``blocks.''
-Each block is a sequence of instructions,
-beginning with a label and ending with a
-control-transfer instruction that branches to other blocks.
-% Each block has a label at the beginning,
-% a sequence of 
-%  -- each of which has a label at the 
-% beginning.  Each block may branch to other blocks with arbitrarily
-% complex control flow.
-The~goal of dataflow optimization is to compute valid
-\emph{dataflow facts}, 
-then use those facts to justify code-improving
-transformations (or \emph{rewrites}) on a {control-flow graph}.  
-
-As~a concrete example, we show constant propagation with constant
-folding. 
-On the left we show a basic block; in the middle we show
-facts that hold between statements (or \emph{nodes}) 
-in the block; and on
-the right we show the result of transforming the block 
-based on the facts:
-\begin{verbatim}
-      Before        Facts        After
-          ------------{}-------------
-      x := 3+4                   x := 7
-          ----------{x=7}------------
-      z := x>5                   z := True
-          -------{x=7, z=True}-------
-      if z                       goto L1
-       then goto L1
-       else goto L2
-\end{verbatim}
-Constant propagation works
-from top to bottom.  
-In this example, we start with the empty fact.  
-Given that fact and the node @x:=3+4@, can we make a
-transformation?
-Yes: constant folding can replace the node with @x:=7@.
-Now,~given this transformed node
-and the original fact, what fact flows out of the bottom of
-the transformed node?  
-The~fact~\mbox{\{@x=7@\}}.  
-Given the fact \{@x=7@\} and the node @z:=x>5@, can we make a
-transformation?  Yes: constant propagation can replace the node with @z:=7>5@.
-Now, can we make another transformation?  Yes: constant folding can 
-replace the node with @z:=True@.
-The~process continues to the end of the block, where we
-can replace the conditional branch with an unconditional one, @goto L1@.
-
-The example above is simple because it has only straight-line code;
-control flow makes dataflow analysis more complicated.
-For~example, 
-consider a graph with a conditional statement, 
-starting at~@L1@:
-\begin{verbatim}
-  L1: x=3; y=4; if z then goto L2 else goto L3
-  L2: x=7; goto L3
-  L3: ...
-\end{verbatim}
-Because control flows to @L3@ from two places (@L1@~and~@L2@),
-we~must \emph{join} the facts coming from those two places.
-All paths to @L3@ produce the fact @y=@$4$,
-so we can conclude that @y=@$4$ at~@L3@.
-But depending on the the path to~@L3@, @x@~may have different
-values, so we conclude~``@x=@$\top$'',
-meaning that there is no single value held by~@x@ at~@L3@.
-%\footnote{
-%In this example @x@ really does vary at @L3@, but in general
-%the analysis might be conservative.}
-The final result of joining the dataflow facts that flow to~@L3@
-is the fact $\mathord{@x=@\top\!} \land \mathord{@y=4@} \land \mathord{@z=@\top}$.
-
-\seclabel{const-prop-example}
-
-\paragraph{Forward and backward.}
-Constant propagation works \emph{forward}, and a fact is often an
-assertion about the program state, such as ``variable~@x@ holds value~@7@.''
-Some useful analyses work \emph{backward}.
-A~prime example is live-variable analysis, where a fact takes the~form
-``variable @x@ is live'' and is an assertion about the
-\emph{continuation} of a program point.  For example, the fact ``@x@~is
-live'' at a program point P is an assertion that @x@ is used on some program
-path starting at \mbox{P}.  % TeXbook, exercise 12.6
-The accompanying transformation is called dead-code elimination;
-if @x@~is not live, this transformation 
-replaces the node @x:=e@ with a no-op.
-
-\seclabel{simple-tx}
-\paragraph{Interleaved analysis and transformation.}
-Our first example \emph{interleaves} analysis and transformation.
-% constant propagation is a transformation, not an analysis
-Interleaving makes it easy to write effective analyses.
-If~instead we had to finish analyzing the block
-before transforming~it, analyses would have to ``predict''
-the results of transformations.
-For example, given the incoming fact~\mbox{\{@x=7@\}}
-and the instruction @z:=x>5@,
-a~pure analysis could produce the outgoing fact
-\{@x=7@, @z=True@\} by simplifying @x>5@ to @True@.
-But the subsequent transformation must perform
-\emph{exactly the same simplification} when it transforms the instruction to @z:=True@!
-If~instead we \emph{first} rewrite the node to @z:=True@, 
-\emph{then} apply the transfer function to the new node, 
-the transfer function becomes wonderfully simple: it merely has to see if the
-right hand side is a constant.
-You~can see code in \secref{const-prop-client}.
-
-Another example is the interleaving of liveness analysis and dead-code elimination.
-As mentioned in \secref{liveness-mention},
-it is sufficient for the analysis to~say ``@y@ is live before @x:=y+2@''.
-It is not necessary to have the more complex rule
-``if @x@~is live after @x:=y+2@ then @y@ is live before~it,''
-because if @x@~is \emph{not} live after @x:=y+2@,
-the assignment @x:=y+2@ will be transformed away (eliminated).
-When several
-analyses and transformations can interact,
-interleaving them offers even more compelling
-benefits; for more
-substantial examples, consult \citet{lerner-grove-chambers:2002}.
-
-But the benefits come at a cost.
-To~compute valid facts for a program that has loops,
-an analysis may require multiple iterations.
-Before the final iteration, the analysis may
-compute a~fact that is invalid,
-and a transformation may use the invalid fact to rewrite the program
-(\secref{ckpoint-monad}).
-To~avoid unjustified rewrites,
-any rewrite based on an invalid fact must be rolled back;
-transformations must be \emph{speculative}.
-As~described in \secref{checkpoint-monad},
-\hoopl~manages speculation with minimal cooperation from the client.
-
-
-\seclabel{debugging-introduced}
-
-While it is wonderful that we can create complex optimizations by
-interleaving very simple analyses and transformations,
-it~is not so wonderful that very simple analyses and transformations,
-when interleaved, can exhibit complex emergent behavior.
-Because such behavior is not easily predicted, it is essential to have good
-tools for debugging.
-\hoopl's primary debugging tool is an implementation of
-Whalley's \citeyearpar{whalley:isolation} search technique for
-finding fault-inducing transformations (\secref{whalley-from-s2}).
-
-
-\section{Representing control-flow graphs} \seclabel{graph-rep}
-
-\ourlib{} is a library that makes it easy to define dataflow
-analyses---and transformations driven by these analyses---on
-control-flow graphs. 
-Graphs are composed from smaller units, which we discuss from the
-bottom up:
-\begin{itemize}
-\item A \emph{node} is defined by \ourlib's client;
-\ourlib{} knows nothing about the representation of nodes (\secref{nodes}).
-\item A basic \emph{block} is a sequence of nodes (\secref{blocks}).
-\item A \emph{graph} is an arbitrarily complicated control-flow graph:
-basic blocks connected by edges (\secref{graphs}).
-
-\end{itemize}
-
-\subsection{Shapes: Open and closed}
-
-In \hoopl,
-nodes, blocks, and graphs share an important new property:
-a~\emph{shape}.
-A~thing's shape tells us whether the thing
-is \emph{open or closed on entry}
-and \emph{open or closed on exit}.  
-At~an \emph{open} point, control may implicitly ``fall through;''
-at~a \emph{closed} point, 
-control transfer must be explicit and to a named label.
-For example,
-\begin{itemize}
-\item A shift-left instruction is open on entry (because control can fall into it
-from the preceding instruction), and open on exit (because control falls through
-to the next instruction).
-\item An unconditional branch is open on entry, but closed on exit (because 
-control cannot fall through to the next instruction).
-\item A label is closed on entry (because in \ourlib{} we do not allow
-control to fall through into a branch target), but open on exit.
-\item
-The shape of a function-call node is up to the client.
-If~a call always returns to its inline successor, it could
-be open on entry and  exit.
-But if a call could return in multiple ways---for example by
-returning normally or by raising an exception---then it has to be
-closed on exit.
-GHC~uses calls of both shapes.
-\end{itemize}
-% This taxonomy enables \ourlib{} to enforce invariants:
-% only nodes closed on entry can be the targets of branches, and only nodes closed
-% on exits can transfer control (see also \secref{nonlocal-class}).
-% As~a consequence, all control transfers originate at control-transfer
-% instructions and terminated at labels; this invariant dramatically
-% simplifies analysis and transformation. 
-Blocks and graphs have shapes too.
-For example the block
-\begin{code}
-   x:=7; y:=x+2; goto L
-\end{code}
-is open on entry and closed on exit,
-which we often abbreviate
-``open/closed.''
-We~may also refer to an ``open/closed block.''
-
-The shape of a thing determines that thing's control-flow properties.
-In particular, whenever E is a node, block, or graph,
-% : \simon{Removed the claim about a unique entry point.}
-\begin{itemize}
-\item
-If E is open on entry, it has a unique predecessor; 
-if it is closed, it may have arbitrarily many predecessors---or none.
-\item
-If E is open on exit, it has a unique successor; 
-if it is closed, it may have arbitrarily many successors---or none.
-\end{itemize}
-%%%%    
-%%%%    
-%%%%    % \item Regardless of whether E is open or closed, 
-%%%%    % it has a unique entry point where execution begins.
-%%%%    \item If E is closed on exit, control leaves \emph{only}
-%%%%    by explicit branches from closed-on-exit nodes.
-%%%%    \item If E is open on exit, control \emph{may} leave E
-%%%%    by ``falling through'' from a distinguished exit point.
-%%%%    \remark{If E is a node or block, control \emph{only} leaves E by
-%%%%    falling through, but this isn't so for a graph.  Example: a body of a
-%%%%    loop contains a \texttt{break} statement} \simon{I don't understand.
-%%%%    A break statement would have to be translated as a branch, no?
-%%%%    Can you give a an example? I claim that control only leaves an 
-%%%%    open graph by falling through.}
-%%%%    \end{itemize}
-
-
-\subsection{Nodes} \seclabel{nodes}
-
-The primitive constituents of a control-flow graph are
-\emph{nodes}.
-% , which are defined by the client.     SLPJ: said again very shortly
-For~example, 
-in a back end
-a node might represent a machine instruction, such as
-a~load, a call, or a conditional branch;
-in~a higher-level intermediate form, a node might represent a simple statement.
-\ourlib{}'s graph representation is \emph{polymorphic in the node type},
-so~each client can define nodes as it likes.
-Because they contain nodes defined by the client,
-graphs can include arbitrary data specified by the~client, including
-(say) method calls, C~statements, stack maps, or
-whatever.
-
-
-\begin{figure}
-\begin{fuzzcode}{0.98pt}
-data `Node e x where
-  Label  :: Label                   -> Node C O
-  `Assign :: Var   -> Expr           -> Node O O
-  `Store  :: Expr  -> Expr           -> Node O O
-  `Branch :: Label                   -> Node O C
-  `Cond   :: Expr  -> Label -> Label -> Node O C
-    ... more constructors ...
-\end{fuzzcode}
-\caption{A typical node type as it might be defined by a client} 
-\figlabel{cmm-node}
-\end{figure}
-
-The type of a node specifies its shape \emph{at compile time}.
-Concretely,
-the type constructor for a node has kind @*->*->*@, where the two type parameters
-are type-level flags, one for entry and one for exit.
-Each type parameter may be instantiated only with type @O@~(for
-open) or type~@C@ (for closed).
-
-As an example,
-\figref{cmm-node} shows a typical node type as it might be defined by
-one of \ourlib's {clients}.
-The type parameters are written @e@ and @x@, for
-entry and exit respectively.  
-The type is a generalized algebraic data type;
-the syntax gives the type of each constructor.  
-%%% \cite{peyton-jones:unification-based-gadts}.
-For example, constructor @Label@
-takes a @Label@ and returns a node of type @Node C O@, where
-the~``@C@'' says ``closed on entry'' and the~``@O@''~says ``open on exit''.  
-The types @Label@, @O@, and~@C@ are 
-defined by \ourlib{} (\figref{graph}).  
-In~other examples from \figref{cmm-node}, constructor @Assign@ takes a
-variable and an expression, and it 
-returns a @Node@ open on both entry and exit; constructor @Store@ is
-similar.
-Finally, control-transfer nodes @Branch@ and @Cond@  (conditional
-branch) are open on entry
-and closed on exit.  
-Types~@`Var@ and @`Expr@ are private to the client, and
-\ourlib{} knows nothing about them.  
-
-\newcommand\cbtext{To obey these invariants,
-a node for
-a conditional-branch instruction, which typically either transfers control
-\emph{or} falls through, must be represented as a two-target
-conditional branch, with the fall-through path in a separate block.  
-This representation is standard \cite{appel:modern},
-and it costs nothing in practice:
-such code is easily sequentialized without superfluous branches.
-%a late-stage code-layout pass can readily reconstruct efficient code.
-}
-\ifpagetuning\vspace*{\parskip}\vbox\fi
-{%
-Nodes closed on entry are the only targets of control transfers;
-nodes open on entry and exit never perform control transfers;
-and nodes closed on exit always perform control transfers.\footnote{\cbtext}
-Because of the position each shape of node occupies in a
-basic block,
-we~often call them \emph{first}, \emph{middle}, and \emph{last} nodes
-respectively.
-}\ifpagetuning\footnotetext{\cbtext}\fi
-
-\begin{figure}
-\begingroup
-\def\^{\\[-2pt]}%
-\hfuzz=10.8pt
-\begin{ttcode}
-data `O   -- Open
-data `C   -- Closed\^
-data `Block n e x where
- `BFirst  :: n C O                      -> Block n C O
- `BMiddle :: n O O                      -> Block n O O
- `BLast   :: n O C                      -> Block n O C
- `BCat    :: Block n e O -> Block n O x -> Block n e x\^
-data `Graph n e x where
-  `GNil  :: Graph n O O
-  `GUnit :: Block n O O -> Graph n O O
-  `GMany :: MaybeO e (Block n O C) 
-        -> LabelMap (Block n C C)
-        -> MaybeO x (Block n C O)
-        -> Graph n e x\^
-data `MaybeO ^ex t where
-  `JustO    :: t -> MaybeO O t
-  `NothingO ::      MaybeO C t\^
-newtype `Label -- abstract
-newtype `LabelMap a -- finite map from Label to a
-`addBlock   :: NonLocal n 
-           => Block n C C
-           -> LabelMap (Block n C C)
-           -> LabelMap (Block n C C)
-`blockUnion :: LabelMap a -> LabelMap a -> LabelMap a\^
-class `NonLocal n where
-  `entryLabel :: n C x -> Label
-  `successors :: n e C -> [Label]
-\end{ttcode}
-\endgroup
-\caption{The block and graph types defined by \ourlib} 
-\figlabel{graph} \figlabel{edges}
-\end{figure}
-% omit MaybeC :: * -> * -> *
-
-
-\subsection{Blocks} \seclabel{blocks}
-
-\ourlib\ combines the client's nodes into
-blocks and graphs, which, unlike the nodes, are defined by \ourlib{}
- (\figref{graph}).
-A~@Block@ is parameterized over the node type~@n@
-as well as over the flag types that make it open or closed at
-entry and exit.
-
-The @BFirst@, @BMiddle@, and @BLast@ constructors create one-node
-blocks.  
-Each of these constructors is polymorphic in the node's \emph{representation}
-but monomorphic in its \emph{shape}.
-Why not use a single constructor 
-of type \mbox{@n e x -> Block n e x@}, which would be polymorphic in a
-node's representation \emph{and} 
-shape?
-Because by making the shape known statically, we simplify the
-implementation of analysis and transformation in 
-\secref{dfengine}. 
-%%%  \finalremark{We have no principled answer to the question of what
-%%%  parts of the representation of blocks are exposed.
-%%%  Do we tell our readers or just ignore the question?
-%%%  } 
-%%%  \simon{Just ignore!}
-
-The @BCat@ constructor concatenates blocks in sequence. 
-It~makes sense to concatenate blocks only when control can fall
-through from the first to the second; therefore, 
-two blocks may be concatenated {only} if each block is open at
-the point of concatenation.
-This~restriction is enforced by the type of @BCat@, whose first 
-argument must be open on exit and whose second argument must be open on entry.
-It~is impossible, for example, to concatenate a~@Branch@
-immediately before an~@Assign@.  
-Indeed, the @Block@ type guarantees statically that any
-closed/closed @Block@---which compiler writers normally 
-call a ``basic block''---consists of exactly one first node
-(such as @Label@ in \figref{cmm-node}), 
-followed by zero or more middle nodes (@Assign@ or @Store@), 
-and terminated with exactly one 
-last node (@Branch@ or @Cond@).  
-Enforcing these invariants by using GADTs is one of 
-\ourlib{}'s innovations.
-
-
-\subsection{Graphs} \seclabel{graphs}
-
-\ourlib{} composes blocks into graphs, which are also defined 
-in  \figref{graph}.
-Like @Block@, the data type @Graph@ is parameterized over
-both nodes @n@ and over its shape at entry and exit (@e@ and @x@).
-@Graph@ has three constructors.  The first two
-deal with the base cases of open/open graphs:
-an empty graph is represented by @GNil@ while a single-block graph
-is represented by @GUnit@.
-
-More general graphs are represented by @GMany@, which has three
-fields: an optional entry sequence, a body, and an optional exit
-sequence.
-\begin{itemize}
-\item 
-If the graph is open on entry, it contains an \emph{entry sequence} of type 
-@Block n O C@.
-We could represent this sequence as a value of type
-@Maybe (Block n O C)@, but we can do better: 
-a~value of @Maybe@ type requires a \emph{dynamic} test,
-but we know \emph{statically}, at compile time, that the sequence is present if and only
-if the graph is open on entry.
-We~express our compile-time knowledge by using the type
-@MaybeO e (Block n O C)@, a type-indexed version of @Maybe@
-which is also defined in \figref{graph}:
-the type @MaybeO O a@ is isomorphic to~@a@, while 
-the type @MaybeO C a@ is isomorphic to~@()@.
-\item 
-The \emph{body} of the graph is a collection of  closed/closed blocks.  
-To~facilitate traversal of the graph, we represent the body as a finite
-map from label to block. 
-\item 
-The \emph{exit sequence} is dual to the entry sequence, and like the entry
-sequence, its presence or absence is deducible from the static type of the graph.
-\end{itemize}
-
-\seclabel{gSplice}
-
-Graphs can be spliced together nicely; the cost is logarithmic in the
-number of closed/closed blocks.
-Unlike blocks, two graphs may be spliced together
-not only when they are both open
- at splice point but also
-when they are both 
-%
-%
-closed---and not
-% to understand why 'and not' is better than 'but not' here, 
-% see Jacques Barzun's rhetoric, *Simple and Direct*
-%
-in the other two cases:
-\begingroup
-\def\^{\\[-3pt]}%
-\hfuzz=10.8pt
-\begin{smallttcode}
-`gSplice :: Graph n e a -> Graph n a x -> Graph n e x
-gSplice GNil g2 = g2
-gSplice g1 GNil = g1\^
-gSplice (GUnit ^b1) (GUnit ^b2) = GUnit (b1 `BCat` b2)\^
-gSplice (GUnit b) (GMany (JustO e) bs x) 
-  = GMany (JustO (b `BCat` e)) bs x\^
-gSplice (GMany e ^bs (JustO x)) (GUnit b2) 
-  = GMany e bs (JustO (x `BCat` b2))\^
-gSplice (GMany e1 ^bs1 (JustO x1)) (GMany (JustO e2) ^bs2 x2)
-  = GMany e1 (bs1 `blockUnion` (b `addBlock` bs2)) x2
-  where b = x1 `BCat` e2\^
-gSplice (GMany e1 bs1 NothingO) (GMany NothingO bs2 x2)
-  = GMany e1 (bs1 `blockUnion` bs2) x2
-\end{smallttcode}
-\endgroup
-This definition illustrates the power of GADTs: the
-pattern matching is exhaustive, and all the shape invariants are
-checked statically.  For example, consider the second-to-last equation for @gSplice@.
-Since the exit sequence of the first argument is @JustO x1@,
-we know that type parameter~@a@ is~@O@, and hence the entry sequence of the second 
-argument must be @JustO e2@.
-Moreover, block~@x1@ must be
-closed/open, and block~@e2@ must be open/closed.  
-We can therefore concatenate 
-@x1@~and~@e2@
-with @BCat@ to produce a closed/closed block~@b@, which is
-added to the body of the result.
-
-\iftrue % notcutting
-We~have carefully crafted the types so that if @BCat@ 
-is considered as an associative operator, 
-every graph has a unique representation.
-%\finalremark{This \P\ was a candidate to be cut, but we decided to
-%keep it---such a nice page break here.
-%
-%%  \simon{Well, you were the one who was so keen on a unique representation!
-%%  And since we have one, I think tis useful to say so. Lastly, the representation of
-%%  singleton blocks is not entirely obvious.}
-%
-%%%%    
-%%%%    An empty open/open graph is represented
-%%%%    by @GNil@, while a closed/closed one is @gNilCC@:
-%%%%    \par {\small
-%%%%    \begin{code}
-%%%%      gNilCC :: Graph C C
-%%%%      gNilCC = GMany NothingO BodyEmpty NothingO
-%%%%    \end{code}}
-%%%%    The representation of a @Graph@ consisting of a single block~@b@ 
-%%%%    depends on the shape of~@b@:\remark{Does anyone care?}
-%%%%    \par{\small
-%%%%    \begin{code}
-%%%%      gUnitOO :: Block O O -> Graph O O
-%%%%      gUnitOC :: Block O C -> Graph O C
-%%%%      gUnitCO :: Block O C -> Graph C O
-%%%%      gUnitCC :: Block O C -> Graph C C
-%%%%      gUnitOO b = GUnit b
-%%%%      gUnitOC b = GMany (JustO b) BodyEmpty   NothingO
-%%%%      gUnitCO b = GMany NothingO  BodyEmpty   (JustO b)
-%%%%      gUnitCC b = GMany NothingO  (BodyUnit b) NothingO
-%%%%    \end{code}}
-%%%%    Multi-block graphs are similar.
-%%%%    From these definitions
-To guarantee uniqueness, @GUnit@ is restricted to open/open
-blocks.
-If~@GUnit@ were more polymorphic, there would be 
-more than one way to represent some graphs, and it wouldn't be obvious
-to a client which representation to choose---or if the choice made a~difference.
-{\hfuzz=1.8pt\par}
-\fi
-
-\subsection{Edges, labels and successors} 
-
-\seclabel{nonlocal-class}
-\seclabel{edges}
-
-
-
-
-Although \ourlib{} is polymorphic in the type of nodes, 
-it~still needs to know how control may be transferred from one node to another.
-Within a~block, a control-flow edge is implicit in every application of
-the @BCat@ constructor.
-An~implicit edge originates in a first node or a middle node and flows
-to a middle node or a last node.
-
-Between blocks, a~control-flow edge is represented as chosen by the client.
-An~explicit edge originates in a last node and flows to a (labelled)
-first node. 
-If~\hoopl\ is polymorphic in the node type,
-how can it{} follow such edges?
-\hoopl\ requires the client to make the node type an instance of 
-\ourlib's @NonLocal@ type class, which is defined in \figref{edges}.
-The @entryLabel@ method takes a first node (one closed on entry, as
-per \secref{nodes})
-and returns its @Label@;
-the~@successors@ method takes a last node (closed on exit) and returns
-the @Label@s to 
-which it can transfer control.  
-%%A~middle node, which is open on both entry and exit, transfers control
-%%only locally, to its successor within a basic block,
-%%so no corresponding interrogation function is needed.
-
-%% A node type defined by a client must be an instance of @NonLocal@.
-In~\figref{cmm-node},
-the client's instance declaration for @Node@ would be
-\begin{code}
-instance NonLocal Node where
-  entryLabel (Label l)  = l
-  successors (Branch b) = [b]
-  successors (Cond e b1 b2) = [b1, b2]
-\end{code}
-Again, the pattern matching for both functions is exhaustive, and
-the compiler checks this fact statically.  
-Here, @entryLabel@ 
-cannot be applied to an @Assign@ or @Branch@ node,
-and any attempt to define a case for @Assign@ or @Branch@ would result
-in a type error.
-
-While the client provides this information about
-nodes, it is convenient for \ourlib\ to get the same information
-about blocks.
-Internally,
-\ourlib{} uses this instance declaration for the @Block@ type:
-% can't use the real code because @BCat@ has the wrong type
-\begin{code}
-instance NonLocal n => NonLocal (Block n) where
-  entryLabel (BFirst n) = entryLabel n
-  entryLabel (BCat b _) = entryLabel b
-  successors (BLast  n) = successors n
-  successors (BCat _ b) = successors b
-\end{code}
-Because the functions @entryLabel@ and @successors@ are used to track control
-flow \emph{within} a graph, \ourlib\ does not need to ask for the
-entry label or successors of a @Graph@ itself.
-Indeed, @Graph@ \emph{cannot} be an instance of @NonLocal@, because even
-if a @Graph@ is closed on entry, it need not have a unique entry label.
-%
-% A slight infelicity is that we cannot make @Graph@ an instance of @NonLocal@,
-% because a graph closed on entry has no unique label.  Fortunately, we never
-% need @Graph@s to be in @NonLocal@.
-%
-% ``Never apologize.  Never confess to infelicity.'' ---SLPJ
-
-
-
-\begin{table}
-\centerline{%
-\begin{tabular}{@{}>{\raggedright\arraybackslash}p{1.03in}>{\scshape}c>{\scshape
-}
-      c>{\raggedright\arraybackslash}p{1.29in}@{}}
-&\multicolumn1{r}{\llap{\emph{Specified}}\hspace*{-0.3em}}&
-\multicolumn1{l}{\hspace*{-0.4em}\rlap{\emph{Implemented}}}&\\
-\multicolumn1{c}{\emph{Part of optimizer}}
-&\multicolumn1{c}{\emph{by}}&
-\multicolumn1{c}{\emph{by}}&
-\multicolumn1{c}{\emph{How many}}%
-\\[5pt]
-Control-flow graphs& Us & Us & One \\
-Nodes in a control-flow graph & You & You & One type per intermediate language \\[3pt]
-Dataflow fact~$F$    & You & You & One type per logic \\
-Lattice operations & Us & You & One set per logic \\[3pt]
-Transfer functions & Us & You & One per analysis \\
-Rewrite functions & Us & You & One per \rlap{transformation} \\[3pt]
-Analyze-and-rewrite functions & Us & Us & Two (forward, backward) \\
-\end{tabular}%
-}
-\caption{Parts of an optimizer built with \ourlib}
-\tablabel{parts}
-\end{table}
-
-
-
-
-\section {Using \ourlib{} to analyze and transform graphs} \seclabel{using-hoopl}
-\seclabel{making-simple}
-\seclabel{create-analysis}
-\seclabel{api}
-
-Now that we have graphs, how do we optimize them?
-\ourlib{} makes it easy;
-a~client must supply these pieces:
-\begin{itemize}
-\item A \emph{node type} (\secref{nodes}).  
-\ourlib{} supplies the @Block@ and @Graph@ types
-that let the client build control-flow graphs out of nodes.
-\item A \emph{data type of facts} and some operations over 
-those facts (\secref{facts}).
-Each analysis uses facts that are specific to that particular analysis,
-which \ourlib{} accommodates by being polymorphic in 
-the fact type.   
-\item A \emph{transfer function} that takes a node and returns a
-\emph{fact transformer}, which takes a fact flowing into the node and
-returns the transformed fact that flows out of the node (\secref{transfers}).  
-\item A \emph{rewrite function} that takes a node and an input fact,
-performs a monadic action, 
-and returns either @Nothing@
-or @Just g@,
-where @g@~is a graph that should
-replace the node
-(\secreftwo{rewrites}{shallow-vs-deep}).
-For many code-improving transformations,
-The ability to replace a \emph{node} by a \emph{graph} 
-%  that may include internal control flow 
-is crucial.
-%We discuss the rewrite function
-%in Sections \ref{sec:rewrites} and \ref{sec:shallow-vs-deep}.
-\end{itemize}
-These requirements are summarized in \tabref{parts}.
-Because facts, transfer functions, and rewrite functions work together,
-we~combine them in a single record of type @FwdPass@ (\figref{api-types}).
-
-
-
-
-Given a node type~@n@ and a @FwdPass@,
-a client can ask \ourlib{}\ to analyze and rewrite a 
-graph.
-\hoopl\ provides a fully polymorphic interface, but for purposes of
-exposition, we present a function that is specialized to a
-closed/closed graph:
-% not using the real code because we're hiding the truth about entry points
-\begin{fuzzcode}{10.5pt}
-`analyzeAndRewriteFwdBody
- :: ( CkpointMonad m -- Roll back speculative actions
-    , NonLocal n )   -- Extract non-local flow edges
- => FwdPass m n f    -- Lattice, transfer, rewrite
- -> [Label]          -- Entry point(s)
- -> Graph n C C      -- Input graph
- -> FactBase f       -- Input fact(s)
- -> m ( Graph n C C  -- Result graph
-      , FactBase f ) -- ... and its facts
-\end{fuzzcode}
-Given a @FwdPass@ and a list of entry points, the 
-analyze-and-rewrite function transforms a graph into
-an optimized graph.
-As its type shows, this function
-is polymorphic in the types of nodes~@n@ and facts~@f@;
-these types are chosen by the client.
-The type of the monad~@m@ is also chosen by the client.
-
-As well as taking and returning a graph, the
-function also takes input facts (the @FactBase@) and produces output facts. 
-A~@FactBase@ is a finite mapping from @Label@ to facts (\figref{api-types});
-if~a @Label@ is not in the domain of the @FactBase@, its fact is the
-bottom element of the lattice.
-For example, in our constant-propagation example from \secref{const-prop-example},
-if the graph
-represents the body of a procedure 
-with parameters $x,y,z$, we would map the entry @Label@ to a fact
-\mbox{$x=\top \land y=\top \land z=\top$}, to specify that the procedure's
-parameters are not known to be constants.
-%%  
-%%  The
-%%  output @FactBase@ maps each @Label@ in the body to its fact
-
-The client's model of @analyzeAndRewriteFwdBody@ is as follows:
-\ourlib\ walks forward over each block in the graph.
-At~each node, \ourlib\ applies the
-rewrite function to the node and the incoming~fact.  If the rewrite
-function returns @Nothing@, the node is retained as part of the output
-graph, the transfer function is used to compute the outgoing fact,
-and \ourlib\ moves on to the next node.
-But~if the rewrite function returns @Just g@,
-indicating that it wants to rewrite the node to the replacement graph~@g@, 
-\ourlib\ recursively analyzes and may further rewrite~@g@
-before moving on to the next node. 
-A~node following a rewritten node sees 
-\emph{up-to-date} facts; that~is, its~input fact is computed by
-analyzing the replacement graph.
-
-A~rewrite function may take any action that is justified by
-the incoming fact.
-If~further analysis invalidates the fact, \hoopl\ rolls
-back the action.
-Because graphs cannot be mutated,
-rolling back to the original graph is easy.
-But~rolling back a rewrite function's {monadic} action
-requires cooperation from the client:
-the~client must  provide @checkpoint@ and
-@restart@ operations, which
-make~@m@ an instance of
-\hoopl's @CkpointMonad@ class
-(\secref{checkpoint-monad}). 
-
-
-Below we flesh out the
-interface to @analyzeAndRewriteFwdBody@, leaving the implementation for
-\secref{engine}.  
-%{\hfuzz=7.2pt\par}
-
-\begin{figure}
-\begingroup
-\def\^{\\[-1pt]}%
-\hfuzz=25pt
-\begin{ttcode}
-data `FwdPass m n f
-  = FwdPass { `fp_lattice  :: DataflowLattice f
-            , `fp_transfer :: FwdTransfer n f
-            , `fp_rewrite  :: FwdRewrite m n f }\^
-------- Lattice ----------
-data `DataflowLattice f = DataflowLattice
- { `fact_bot  :: f
- , `fact_join :: JoinFun f }
-type `JoinFun f = 
-  OldFact f -> NewFact f -> (ChangeFlag, f)
-newtype `OldFact f = OldFact f
-newtype `NewFact f = NewFact f
-data `ChangeFlag = `NoChange | `SomeChange\^
-------- Transfers ----------
-newtype `FwdTransfer n f      -- abstract type
-`mkFTransfer
- :: (forall e x . n e x -> f -> Fact x f)
- -> FwdTransfer n f\^
-------- Rewrites ----------
-newtype `FwdRewrite m n f     -- abstract type
-`mkFRewrite :: FuelMonad m 
- => (forall e x . n e x -> f -> m (Maybe (Graph n e x)))
- -> FwdRewrite m n f
-`thenFwdRw :: FwdRewrite m n f -> FwdRewrite m n f
- -> FwdRewrite m n f
-`iterFwdRw :: FwdRewrite m n f -> FwdRewrite m n f
-`noFwdRw   :: Monad m          => FwdRewrite m n f\^
-------- Fact-like things, aka "fact(s)" -----
-type family   `Fact x f :: *
-type instance Fact O f = f
-type instance Fact C f = FactBase f\^
-------- FactBase -------
-type `FactBase f = LabelMap f
- -- A finite mapping from Labels to facts f
-mkFactBase 
- :: DataflowLattice f -> [(Label, f)] -> FactBase f\^
-------- Rolling back speculative rewrites ----
-class Monad m => CkpointMonad m where
-  type Checkpoint m
-  checkpoint :: m (Checkpoint m)
-  restart    :: Checkpoint m -> m () \^
-------- Optimization fuel ----
-type `Fuel = Int
-class Monad m => `FuelMonad m where
-  `getFuel :: m Fuel
-  `setFuel :: Fuel -> m ()
-\end{ttcode}
-\endgroup
-\caption{\ourlib{} API data types}
-  \figlabel{api-types}
-  \figlabel{lattice-type} \figlabel{lattice}
-  \figlabel{transfers}  \figlabel{rewrites}
-\end{figure}
-%%%%  \simon{We previously renamed @fact\_join@ to @fact\_extend@ because it really
-%%%%  is not a symmetrical join; we're extending an old fact with a new one.
-%%%%  NR: Yes, but the asymmetry is now explicit in the \emph{type}, so it
-%%%%  needn't also be reflected in the \emph{name}.}
-
-\subsection{Dataflow lattices} \seclabel{lattices} \seclabel{facts}
-
-For each analysis or transformation, the client must define a type
-of dataflow facts.
-A~dataflow fact often represents an assertion
-about a program point,
-but in general, dataflow analysis establishes properties of \emph{paths}:
-\begin{itemize}
-\item An assertion about all paths \emph{to} a program point is established
-by a \emph{forward analysis}. For example the assertion ``$@x@=@3@$'' at point P 
-claims that variable @x@ holds value @3@ at P, regardless of the
-path by which P is reached.
-\item An assertion about all paths \emph{from} a program point is 
-established by a \emph{backward analysis}. For example, the 
-assertion ``@x@ is dead'' at point P claims that no path from P uses 
-variable @x@.
-\end{itemize}
-
-A~set of dataflow facts must form a lattice, and \ourlib{} must know
-(a)~the bottom element of the lattice and (b)~how to take 
-the least upper bound (join) of two elements.
-To ensure that analysis
-terminates, it is enough if every fact has a finite number of
-distinct facts above it, so that repeated joins
-eventually reach a fixed point.
-%% \simon{There is no mention here of the @OldFact@ and @NewFact@ types.
-%% Shall we nuke them for the purposes of the paper?
-%% NR: They should definitely not be nuked; they're needed if the reader
-%% wants to understand the asymmetrical behavior of @fact\_join@.
-%% I'm~also mindful that this paper will be the primary explanation of
-%% \hoopl\ to its users, and I don't want to hide this part of the
-%% interface.
-%% As for mentions in the text, 
-%% if you look carefully, you'll
-%% see that I've changed the subscripts in the text to ``old'' and
-%% ``new''.
-%% Together with the code, I believe that's enough to get the point across.
-%% SLPJ -- OK.  I don't agree that it's enough, but we have more important fish to fry.
-%% }
-
-In practice, joins are computed at labels.
-If~$f_{\mathit{old}}$ is the fact currently associated with a
-label~$L$, 
-and if a transfer function propagates a new fact~$f_{\mathit{new}}$
-into label~$L$, 
-\hoopl\ replaces $f_{\mathit{old}}$ with
-the join  \mbox{$f_{\mathit{old}} \join f_{\mathit{new}}$}.
-And \hoopl\ needs to know 
-if \mbox{$f_{\mathit{old}} \join f_{\mathit{new}} = f_{\mathit{old}}$},
-because if not, the analysis has not reached a fixed point.
-
-The bottom element and join operation of a lattice of facts of
-type~@f@ are stored in a value of type @DataflowLattice f@
-(\figref{lattice}). 
-%%%% \simon{Can we shorten ``@DataflowLattice@'' to just
-%%%% ``@Lattice@''?} % bigger fish ---NR
-%%Such a value is part of the  @FwdPass n f@ that is passed to
-%%@analyzeAndRewriteFwd@ above.
-As~noted in the previous paragraph, 
-\ourlib{} needs to know when the result of a join is equal
-to the old fact.
-It~is often easiest to answer this question while the join itself is
-being computed.
-By~contrast, a \emph{post facto} equality test on facts might cost
-almost as much as a~join.
-For these reasons, \ourlib\ does not
-require a separate equality test on facts.
-Instead, \ourlib\ requires that @fact_join@ return a~@ChangeFlag@ as
-well as the join.
-If~the join is the same as the old fact, 
-the @ChangeFlag@ should be @NoChange@;
-if~not, the @ChangeFlag@ should be @SomeChange@.
-
-\seclabel{WithTop}
-
-To help clients create lattices and join functions,
-\hoopl\ includes functions and constructors that can extend a fact type~@f@
-with top and bottom elements.
-In this paper, we use only type @`WithTop@, which comes with value
-constructors that have these types:
-\begin{code}
-  `PElem :: f -> WithTop f
-  `Top   ::      WithTop f
-\end{code}
-\hoopl\ provides combinators which make it easy to create join
-  functions that use @Top@.
-The most useful is @extendJoinDomain@, which uses auxiliary types
-defined in \figref{lattice}:
-\begin{smallcode}
-`extendJoinDomain
- :: (OldFact f -> NewFact f -> (ChangeFlag, WithTop f))
- -> JoinFun (WithTop f)
-\end{smallcode}
-A~client supplies a join function that \emph{consumes} only facts of
-type~@f@, but may produce either @Top@ or a fact of type~@f@---as
-in the example of \figref{const-prop} below.
-Calling @extendJoinDomain@ extends the client's function to a proper
-join function on the type @WithTop a@,
-guaranteeing that joins
-involving @Top@ obey the appropriate algebraic laws.
-
-\hoopl\ also provides a value constructor @`Bot@ and type constructors
-@`WithBot@ and @`WithTopAndBot@, along with similar functions.
-Constructors @Top@ and @Bot@ are polymorphic, so for example,
-@Top@~also has type @WithTopAndBot a@.
-
-It is also common to use a lattice that takes the form of a
-finite~map.
-In~such lattices it is typical to join maps pointwise, and \hoopl\
-provides a function that makes it convenient to do so:
-\begin{smallcode}
- `joinMaps :: Ord k => JoinFun f -> JoinFun (Map.Map k f)
-\end{smallcode}
-
-
-\subsection{The transfer function} \seclabel{transfers}
-
-A~forward transfer function is presented with the dataflow fact
-coming 
-into a node, and it computes dataflow fact(s) on the node's outgoing edge(s).
-In a forward analysis, \hoopl\ starts with the fact at the
-beginning of a block and applies the transfer function to successive 
-nodes in that block, until eventually the transfer function for the last node
-\ifpagetuning\vadjust{\break}\fi
-computes the facts that are propagated to the block's successors.
-For example, consider doing constant propagation (\secref{constant-propagation}) on 
-the following graph, whose entry point is @L1@:
-\begin{code}
-  L1: x=3; goto L2
-  L2: y=x+4; x=x-1; 
-      if x>0 then goto L2 else return
-\end{code}
-Forward analysis starts with the bottom fact \{\} at every label
-except the entry~@L1@.
-The initial fact at~@L1@ is \{@x=@$\top$@,y=@$\top$\}.
-Analyzing~@L1@ propagates this fact forward, applying the transfer 
-function successively to the nodes
-of~@L1@, and propagating the new fact \{@x=3,y=@$\top$\} to~@L2@.
-This new fact is joined with the existing (bottom) fact at~@L2@.
-Now~the analysis propagates @L2@'s fact forward, again applying the transfer
-function, and propagating the new fact \mbox{\{@x=2@, @y=7@\}} to~@L2@.
-Again the new fact is joined with the existing fact at~@L2@, and the process
-repeats until the facts reach a fixed point.
-
-A~transfer function has an unusual sort of type:
-not quite a dependent type, but not a bog-standard polymorphic type either.
-The~result type of the transfer function is \emph{indexed} by the shape (i.e.,
-the type) of the node argument:
-If the node is open on exit, the transfer function produces a single fact.
-But if the node is \emph{closed} on exit,
-the transfer function 
-produces a collection of (@Label@,fact) pairs: one for each outgoing edge.  
-The~collection is represented by a @FactBase@;
-auxiliary function @`mkFactBase@ (\figref{api-types}) joins facts on
-distinct outgoing edges 
-that target the same label.
-
-The~indexing is expressed by
-% type constructor @Fact@ in
-% \figref{transfers}, an example of
- Haskell's (recently added) 
-\emph{indexed type families}.
-A~forward transfer function supplied by a client, 
-which is passed to @mkFTransfer@,
-is polymorphic in @e@~and~@x@ (\figref{transfers}).
-It~takes a 
-node of type \mbox{@n@ @e@ @x@},
-and it returns a \emph{fact transformer} of type
-@f -> Fact x f@.
-Type constructor @Fact@
-is a species of type-level function: its signature is given in the
-@type family@ declaration, and its definition is given by two @type instance@
-declarations.  The first declaration says that a @Fact O f@, which
-comes out of a node
-\emph{open} on exit, is just a fact~@f@. 
-The second declaration says that a @Fact C f@, which comes out of a
-node \emph{closed} on exit, is a mapping from @Label@ to facts.
-
-%%  
-%%  \begin{code}
-%%    `transfer_fn :: forall e x . n e x -> f -> Fact x f
-%%    `node        :: n e x
-%%  \end{code}
-%%  then @(transfer_fn node)@ is a fact transformer:
-%%  \begin{code}
-%%    transfer_fn node :: f -> Fact x f
-%%  \end{code}
-%%  
-
-
-\subsection{The rewrite function and the client's monad} 
- \seclabel{rewrites} 
- \seclabel{example-rewrites}
-
-
-We compute dataflow facts in order to enable code-improving
-transformations.
-In our constant-propagation example,
-the dataflow facts may enable us
-to simplify an expression by performing constant folding, or to 
-turn a conditional branch into an unconditional one.
-Similarly, facts about liveness may allow us to 
-replace a dead assignment with a no-op.
-
-A @FwdPass@ therefore includes a \emph{rewrite function}, whose
-type, @FwdRewrite@, is abstract (\figref{api-types}).
-A~programmer creating a rewrite function chooses the type of a node~@n@ and
-a dataflow fact~@f@.
-A~rewrite function might also want to consume fresh
-names (e.g.,~to label new blocks) or take other actions (e.g., logging
-rewrites). 
-So~that a rewrite function may take actions, \hoopl\
-requires that a programmer creating a rewrite function also choose a
-monad~@m@.
-So~that \hoopl\ may roll back actions taken by speculative rewrites, the monad
-must satisfy the constraint @CkpointMonad m@, as explained in
-\secref{checkpoint-monad} below. 
-The programmer may write code that works with any such monad,
-may create a monad just for the client,
-or may use a monad supplied by \hoopl. 
-
-
-When these choices are made, the easy way to create a rewrite
-function is to call the function @mkFRewrite@ in \figref{api-types}.
-The client supplies a function~$r$, which is specialized to a particular
-node, fact, and monad, but is polymorphic in the
-\emph{shape} of the node to be rewritten.
-Function~$r$ takes a node and a fact and returns a monadic
-computation, but what result should that computation return?
-Returning a new node is not good enough:
-in~general, it~must be possible for rewriting to result in a graph.
-For example,
-we might want to remove a node by returning the empty graph,
-or more ambitiously, we might want to replace a high-level operation
-with a tree of conditional branches or a loop, which would entail
-returning a graph containing new blocks with internal control flow.
-
-
-It~must also be possible for a rewrite function to decide to do nothing.
-The result of the monadic computation returned by~$r$ may therefore be
-@Nothing@, indicating that the node should
-not be rewritten,
-or $@Just@\;\ag$, indicating that the node should
-be replaced with~\ag: the replacement graph. 
-%%The additional value $\rw$ tells \hoopl\ whether
-%%and how the replacement graph~$\ag$ should be analyzed and rewritten
-%%further;
-%%we explain~$\rw$ in \secref{shallow-vs-deep}.
-
-
-The type of @mkFRewrite@ in \figref{api-types} guarantees
-that
-the replacement graph $\ag$ has
-the {same} \emph{shape} as the node being rewritten.
-For~example, a branch instruction can be replaced only by a graph 
-closed on exit.
-%%  Moreover, because only an open/open graph can be 
-%%  empty---look at the type of @GNil@ in \figref{graph}---the type 
-%%  of @FwdRewrite@ 
-%%  guarantees, at compile time, that no head of a block (closed/open)
-%%  or tail of a block (open/closed) can ever be deleted by being
-%%  rewritten to an empty graph.
-
-\subsection{Shallow rewriting, deep rewriting, rewriting combinators,
-and the meaning of {\textmd\texttt{FwdRewrite}}}
-
- \seclabel{shallow-vs-deep}
-
-When a node is rewritten, the replacement graph~$g$
-must itself be analyzed, and its nodes may be further rewritten.
-\hoopl\ can make a recursive call to 
-@analyzeAndRewriteFwdBody@---but how should it rewrite the
-replacement graph~$g$?
-There are two common cases:
-\begin{itemize}
-\item
-Rewrite~$g$ using the same rewrite function that produced~$g$.
-This procedure is
-called \emph{deep rewriting}. 
-When deep rewriting is used, the client's rewrite function must
-ensure that the graphs it produces are not rewritten indefinitely
-(\secref{correctness}). 
-\item
-Analyze~$g$ {without} rewriting it.
-This procedure is called \emph{shallow rewriting}.
-\end{itemize}
-Deep rewriting is essential to achieve the full benefits of
-interleaved analysis and transformation
-\citep{lerner-grove-chambers:2002}.
-But shallow rewriting can be vital as well; 
-for example, a backward dataflow pass that inserts
-a spill before a call must not rewrite the call again, lest it attempt
-to insert infinitely many spills.
-
-
-
-\seclabel{rewrite-model}
-
-An~innovation of \hoopl\ is to build the choice of shallow or deep
-rewriting into each rewrite function, through the use of the four
-combinators
-@mkFRewrite@, @thenFwdRw@, @iterFwdRw@, and @noFwdRw@ shown in
-\figref{api-types}. 
-Every rewrite function is made with these combinators,
-and its behavior is characterized by the answers to two questions:
-Does the function rewrite a~node to a replacement graph?
-If~so, what rewrite function
-should be used to analyze the replacement graph recursively?
-To~answer these questions, we~present an
-algebraic datatype that models @FwdRewrite@
-with one constructor for each combinator:
-\begin{smallcode}
-data `Rw r = `Mk r | `Then (Rw r) (Rw r) | `Iter (Rw r) | `No
-\end{smallcode}
-Using this model, we specify how a rewrite function works by
-giving a reference implementation:
-the function @rewrite@, below,
-computes the replacement graph and rewrite function
-that result from applying a rewrite function~@r@
-to~a~@node@ and a fact~@f@.
-The~code is in continuation-passing style;
-when the node is rewritten,
-the first continuation~@j@ accepts a pair containing the replacement
-graph and the new rewrite function to be used to transform~it.
-When the node is not rewritten, 
-the second continuation~@n@ is the (lazily evaluated) result.
-\begin{smallfuzzcode}{10.8pt}
-rewrite :: Monad m => FwdRewrite m n f -> n e x -> f
-        -> m (Maybe (Graph n e x, FwdRewrite m n f))
-`rewrite ^r node f = rew r (return . Just) (return Nothing)
- where
-  `rew (Mk ^rw) j n = do { ^mg <- rw node f
-                       ; case mg of Nothing -> n
-                                    Just g  -> j (g, No) }
-  rew (r1 `Then` r2) j n = rew r1 (j . add r2) (rew r2 j n)
-  rew (Iter r)       j n = rew r  (j . add (Iter r)) n
-  rew No             j n = n
-  `add ^nextrw (g, r) = (g, r `Then` nextrw)
-\end{smallfuzzcode}
-Appealing to this model, we see that
-\begin{itemize}
-\item
-A~function @mkFRewrite rw@ never rewrites a replacement
-graph; this behavior is shallow rewriting.{\hfuzz=0.7pt \par}
-\item
-When a~function @r1 `thenFwdRw` r2@ is applied to a node,
-if~@r1@ replaces the node, then @r2@~is used to transform the
-replacement graph.
-And~if @r1@~does not replace the node, \hoopl\ tries~@r2@.
-\item
-When a~function @iterFwdRw r@ rewrites a node, @iterFwdRw r@ is
-used to transform the replacement graph; this behavior is deep
-rewriting.
-If~@r@~does not rewrite a~node, neither does @iterFwdRw r@.
-\item
-Finally, @noFwdRw@ never replaces a graph.
-\end{itemize}
-For~convenience, we~also provide the~function @`deepFwdRw@,
-which is the composition of @iterFwdRw@ and~@mkFRewrite@.
-%  \remark{maybe some of the real type signatures ought to be repeated?}
-
-%%  \begin{code}
-%%   `iterFwdRw :: FwdRewrite m n f -> FwdRewrite m n f
-%%  \end{code}
-
-%%  To try multiple rewrite functions in sequence,
-%%  provided they all use the same type of fact, \hoopl\ combines them with
-%%  \verbatiminput{comb1}
-%%  % defn thenFwdRw
-%%  Rewrite function @r1 `thenFwdRw` r2@ first does the rewrites of~@r1@,
-%%  then the rewrites of~@r2@.
-
-%%  
-%%  
-%%  by using
-%%  Rewrite functions are potentially more plentiful than transfer
-%%  functions, because
-%%  a~single dataflow fact might justify more than one kind of rewrite.
-%%  \hoopl\ makes it easy for a client to combine multiple rewrite
-%%  functions that use the same fact:
-
-Our combinators satisfy the algebraic laws that you would expect;
-for~example,
-@noFwdRw@ is a left and right identity of @thenFwdRw@.
-A~more interesting law is
-\begin{code}
-  iterFwdRw r = r `thenFwdRw` iterFwdRw r
-\end{code}
-Unfortunately, this law cannot be used to \emph{define}
-@iterFwdRw@:
-if~we used this law to define @iterFwdRw@, then when @r@ returned @Nothing@,
-@iterFwdRw r@ would diverge.
-
-
-
-%%%%  \hoopl\ provides
-%%%%  a function that makes a shallow rewrite deep:\finalremark{algebraic
-%%%%  law wanted!}
-%%%%  \remark{Do we really care about @iterFwdRw@ or can we just drop it?}
-%%%%  \verbatiminput{iterf}
-%%%%  % defn iterFwdRw
-
-
-\subsection{When the type of nodes is not known}
-
-We note above (\secref{transfers}) that
-the type of a transfer function's result 
-depends on the argument's shape on exit.
-It~is easy for a client to write a type-indexed transfer function,
-because the client defines the constructor and shape for each node.
-The client's transfer functions discriminate on the constructor
-and so can return a result that is indexed by each node's shape.
-
-What if you want to write a transfer function that
-{does \emph{not} know the type of the node}?
-%
-For example, a dominator analysis need not scrutinize nodes;
-it needs to know only about
-labels and edges in the graph.
-Ideally, a dominator analysis would work
-with \emph{any} type of node~@n@, 
-provided only that @n@~is an
-instance of the @NonLocal@ type class.
-But if we don't know
-the type of~@n@, 
-we can't write a function of type 
-@n e x -> f -> Fact x f@,
-because the only way to get the result type right is to 
-scrutinize the constructors of~@n@.
-
-\seclabel{triple-of-functions}
-
-There is another way;
-in place of a single function that is polymorphic in shape,
-\hoopl\ also accepts a triple of functions, each of which is
-polymorphic in the node's type but monomorphic in its
-shape:
-\begin{code}
-`mkFTransfer3 :: (n C O -> f -> Fact O f)
-             -> (n O O -> f -> Fact O f)
-             -> (n O C -> f -> Fact C f)
-             -> FwdTransfer n f
-\end{code}
-We have used this interface to write a number of functions that are
- polymorphic in the node type~@n@:
-\begin{itemize}
-\item
-A function that takes a @FwdTransfer@ and wraps it in logging code, so
-an analysis can be debugged by watching facts flow through 
-nodes
-\item
-A pairing function that runs two passes interleaved, not sequentially,
-potentially producing better results than any sequence:
-\verbatiminput{pairf}
-% defn pairFwd
-\item
- An efficient dominator analysis
-in the style of 
-\citet{cooper-harvey-kennedy:simple-dominance},
-whose transfer function is implemented 
-using only the
-functions in the \texttt{NonLocal} type class
-\end{itemize}
-
-
-%%  Or, you might want to write a combinator that
-%%  computes the pairwise composition of any two analyses
-%%  defined on any node type.
-%%  
-%%  You cannot write either of these examples
-%%  using the polymorphic function described in \secref{transfers}
-%%  because these examples require the ability
-%%  to inspect the shape of the node.
-%%  
-%%  
-%%  \subsection{Stuff cut from 4.2 that should disappear when the previous section is finished}
-%%  
-%%  So much for the interface.
-%%  What about the implementation?
-%%  The way GADTs work is that the compiler uses the value constructor for
-%%  type \mbox{@n@ @e@ @x@} to determine whether @e@~and~@x@ are open or
-%%  closed.
-%%  But we want to write functions that are \emph{polymorphic} in the node
-%%  type~@n@!
-%%  Such functions include
-%%  \begin{itemize}
-%%  \item
-%%  A function that takes a pair of @FwdTransfer@s for facts @f@~and~@f'@,
-%%  and returns a single @FwdTransfer@ for the fact @(f, f')@
-%%  \end{itemize}
-%%  \simon{These bullets are utterly opaque. They belong in 4.5.  The rest of this section 
-%%  is also very hard to understand without more explanation. See email.  }
-%%  Such functions may also be useful in \hoopl's \emph{clients}:
-%%  % may need
-%%  %functions that are polymorphic in the node type~@n@:
-%%  \begin{itemize}
-%%  \item
-%%  A dominator analysis in the style of
-%%  \citet{cooper-harvey-kennedy:simple-dominance} requires only the
-%%  functions in the \texttt{NonLocal} type class; 
-%%  we have written such an analysis using transfer functions that are 
-%%  polymorphic in~@n@.
-%%  \end{itemize}
-%%  Because the mapping from
-%%  value constructors to shape is different for each node type~@n@, transfer
-%%   functions cannot be polymorphic in both
-%%  the representation and the shape of nodes.
-%%   Our implementation therefore sacrifices polymorphism in shape:
-%%  internally, \hoopl\ represents
-%%  a~@FwdTransfer n f@ as a \emph{triple} of functions,
-%%  each polymorphic in~@n@ but monomorphic in shape:
-%%  \begin{code}
-%%  newtype FwdTransfer n f 
-%%    = FwdTransfers ( n C O -> f -> f
-%%                   , n O O -> f -> f
-%%                   , n O C -> f -> FactBase f
-%%                   )
-%%  \end{code}
-%%  \simon{I argue strongly that the implementation should be 
-%%  polymorphic too, using a shape classifier where necessary.
-%%  Regardless of how this debate pans out, though, I think it's 
-%%  a bad idea to introduce triples here. They are simply confusing.}
-%%  Such triples can easily be composed and wrapped without requiring a
-%%  pattern match on the value constructor of an unknown node
-%%  type.\remark{Need to refer to this junk in the conclusion}
-%%  Working with triples is tedious, but only \hoopl\ itself is forced to
-%%  work with triples; each client, which knows the node type, may supply
-%%  a triple,
-%%  but it typically supplies a single function polymorphic in the shape
-%%  of the (known) node.  
-%%  
-%%  
-
-%%    \subsection{Composing rewrite functions and dataflow passes} \seclabel{combinators}
-%%    
-%%    Requiring each rewrite to return a new rewrite function has another
-%%    advantage, beyond controlling the shallow-vs-deep choice: it
-%%    enables a variety of combinators over rewrite functions. 
-%%    \remark{This whole subsection needs to be redone in light of the new
-%%    (triple-based) representation.  It's not pretty any more.}
-%%    For example, here is a function
-%%    that combines two rewrite functions in sequence:
-%%    \remark{This code must be improved}
-%%    What a beautiful type @thenFwdRw@ has! 
-%%    \remark{And what an ugly implementation!  Implementations must go.}
-%%    It tries @rw1@, and if @rw1@
-%%    declines to rewrite, it behaves like @rw2@.  But if
-%%    @rw1@ rewrites, returning a new rewriter @rw1a@, then the overall call also
-%%    succeeds, returning a new rewrite function obtained by combining @rw1a@
-%%    with @rw2@.  (We cannot apply @rw1a@ or @rw2@ 
-%%    directly to the replacement graph~@g@, 
-%%    because @r1@~returns a graph and @rw2@~expects a node.)
-%%    The rewriter @noFwdRw@ is the identity of @thenFwdRw@.
-%%    Finally, @thenFwdRw@ can 
-%%    combine a deep-rewriting function and a shallow-rewriting function,
-%%    to produce a rewrite function that is a combination of deep and shallow.
-%%    %%This is something that the Lerner/Grove/Chambers framework could not do,
-%%    %%because there was a global shallow/deep flag.
-%%    %% Our shortsightedness; Lerner/Grove/Chambers is deep only ---NR
-%%    
-%%    
-%%    A shallow rewrite function can be made deep by iterating
-%%    it:\remark{Algebraic law wanted!}
-%%    If we have shallow rewrites $A$~and~$B$ then we can build $AB$,
-%%    $A^*B$, $(AB)^*$, 
-%%    and so on: sequential composition is @thenFwdRw@ and the Kleene star
-%%    is @iterFwdRw@.\remark{Do we still believe this claim?}
-%%    \remark{We can't define @iterFwdRew@ in terms of @thenFwdRew@ because
-%%    the second argument to @thenFwdRew@ would have to be the constant
-%%    nothing function when applied but would have to be the original triple
-%%    when passed to @thenFwdRew@ as the second argument (in the recursive
-%%    call).}
-%%    
-%%    
-%%    The combinators above operate on rewrite functions that share a common
-%%    fact type and transfer function.
-%%    It~can also be useful to combine entire dataflow passes that use
-%%    different facts.
-%%    We~invite you to write one such combinator, with type
-%%    \begin{code}
-%%      `pairFwd :: Monad m
-%%              => FwdPass m n f1 
-%%              -> FwdPass m n f2
-%%              -> FwdPass m n (f1,f2)
-%%    \end{code}
-%%    The two passes run interleaved, not sequentially, and each may help
-%%    the other,
-%%    yielding better results than running $A$~and then~$B$ or $B$~and then~$A$
-%%    \citep{lerner-grove-chambers:2002}.
-%%    %%  call these passes. ``super-analyses;''
-%%    %%  in \hoopl, construction of super-analyses is
-%%    %%  particularly concrete.
-
-\subsection{Example: Constant propagation and constant folding} 
-  \seclabel{const-prop-client}
-
-% omit Binop :: Operator -> Expr -> Expr -> Expr
-% omit Add :: Operator
-
-\begin{figure}
-\smallfuzzverbatiminput{2.5pt}{cprop}
-% local node
-% defn ConstFact
-% defn constLattice
-% defn constFactAdd
-% defn varHasLit
-% local ft
-% defn constProp
-% local cp
-% local lookup
-% defn simplify
-% local simp
-% local s_node
-% local s_exp
-% defn constPropPass
-% local new
-% local old
-% local tl
-% local fl
-\caption{The client for constant propagation and constant folding\break (extracted automatically from code distributed with Hoopl)}
-\figlabel{const-prop}
-\end{figure}
-
-
-\figref{const-prop} shows client code for
-constant propagation and constant folding.
-For each variable, at each program point, the analysis concludes one
-of three facts: 
-the variable holds a constant value of type~@`Lit@,
-the variable might hold a non-constant value,
-or what the variable holds is unknown.
-We~represent these facts using a finite map from a variable to a
-fact of type @WithTop Lit@ (\secref{WithTop}).
-% Any one procedure has only
-% finitely many variables; only finitely many facts are computed at any
-% program point; and in this lattice any one fact can increase at most
-% twice.  These properties ensure that the dataflow engine will reach a
-% fixed point.
-A~variable with a constant value maps to @Just (PElem k)@, where
-@k@ is the constant value; 
-a variable with a non-constant value maps to @Just Top@;
-and a variable with an unknown value maps to @Nothing@ (it is not
-in the domain of the finite map).
-
-% \afterpage{\clearpage}
-
-The definition of the lattice (@constLattice@) is straightforward.
-The bottom element is an empty map (nothing is known about what
-any variable holds). 
-%
-The join function is implemented with the help of combinators provided
-by \hoopl.
-The client writes a simple function, @constFactAdd@, which 
-compares two values of type @Lit@ and returns a result of type
-@WithTop Lit@.
-The client uses @extendJoinDomain@ to lift @constFactAdd@ into a join
-function on @WithTop Lit@, then uses
-@joinMaps@ to lift \emph{that} join function up to the map
-containing facts for all variables.
-
-The forward transfer function @varHasLit@ is defined using the
-shape-polymorphic auxiliary function~@ft@.
-For most nodes~@n@, @ft n@ simply propagates the input fact forward.
-But for an assignment node, if a variable~@x@ gets a constant value~@k@,
-@ft@ extends the input fact by mapping @x@ to~@PElem k@.
-And if a variable~@x@ is assigned a non-constant value,
-@ft@ extends the input fact by mapping @x@ to~@Top@.
-There is one other interesting case:
-a conditional branch where the condition
-is a variable.
-If the conditional branch flows to the true successor,
-the variable holds @True@, and similarly for the false successor,
-\emph{mutatis mutandis}.
-Function @ft@ updates the fact flowing to each successor accordingly.
-Because~@ft@ scrutinizes a GADT, it cannot
-use a wildcard to default the uninteresting cases.
-
-The transfer function need not consider complicated cases such as 
-an assignment @x:=y@ where @y@ holds a constant value~@k@.
-Instead, we rely on the interleaving of transformation
-and analysis to first transform the assignment to @x:=k@,
-which is exactly what our simple transfer function expects.
-As we mention in \secref{simple-tx},
-interleaving makes it possible to write
-very simple transfer functions without missing
-opportunities to improve the code.
-
-\figref{const-prop}'s rewrite function for constant propagation, @constProp@,
-rewrites each use of a variable to its constant value.
-The client has defined auxiliary functions that may change expressions
-or nodes:
-\begin{smallcode}
-type `MaybeChange a = a -> Maybe a
-`mapVE :: (Var  -> Maybe Expr) -> MaybeChange Expr
-`mapEE :: MaybeChange Expr     -> MaybeChange Expr
-`mapEN :: MaybeChange Expr     -> MaybeChange (Node e x)
-`mapVN :: (Var  -> Maybe Expr) -> MaybeChange (Node e x)
-`nodeToG :: Node e x -> Graph Node e x
-\end{smallcode}
-The client composes @map@\emph{XX} functions
-to apply @lookup@ to each use of a variable in each kind of node;
-@lookup@ substitutes for each variable that has a constant value.
-Applying @liftM nodeToG@ lifts the final node, if present, into a~@Graph@.
-
-
-\figref{const-prop} also gives another, distinct function 
-for constant
-folding: @simplify@.
-This function
-rewrites constant expressions to their values,
-and it rewrites a conditional branch on a
-boolean constant to an unconditional branch.
-To~rewrite constant expressions, 
-it runs @s_exp@ on every subexpression.
-Function @simplify@ does not check whether a variable holds a
-constant value; it relies on @constProp@ to have replaced the
-variable by the constant.
-Indeed, @simplify@ does not consult the
-incoming fact, so it is polymorphic in~@f@.
-
-
-The @FwdRewrite@ functions @constProp@ and @simplify@
-are useful independently.
-In this case, however, we
-want \emph{both} of them,
-so we compose them with @thenFwdRw@.
-The composition, along with the lattice and the
-transfer function,
-goes into @constPropPass@ (bottom of \figref{const-prop}).
-Given @constPropPass@, we can
-improve a graph~@g@ by passing @constPropPass@ and~@g@
-to
-@analyzeAndRewriteFwdBody@.
-
-
-
-%%%%    \subsection{Fixed points and speculative rewrites} \seclabel{fixpoints}
-%%%%    
-%%%%    Are rewrites sound, especially when there are loops?
-%%%%    Many analyses compute a fixed point starting from unsound
-%%%%    ``facts''; for example, a live-variable analysis starts from the
-%%%%    assumption that all variables are dead.  This means \emph{rewrites
-%%%%    performed before a fixed point is reached may be unsound, and their results
-%%%%    must be discarded}.  Each iteration of the fixed-point computation must
-%%%%    start afresh with the original graph.  
-%%%%    
-%%%%    
-%%%%    Although the rewrites may be unsound, \emph{they must be performed}
-%%%%    (speculatively, and possibly recursively), 
-%%%%    so that the facts downstream of the replacement graphs are as accurate
-%%%%    as possible.
-%%%%    For~example, consider this graph, with entry at @L1@:
-%%%%    \par{\small
-%%%%    \begin{code}
-%%%%      L1: x=0; goto L2
-%%%%      L2: x=x+1; if x==10 then goto L3 else goto L2
-%%%%    \end{code}}
-%%%%    The first traversal of block @L2@ starts with the unsound ``fact'' \{x=0\};
-%%%%    but analysis of the block propagates the new fact \{x=1\} to @L2@, which joins the
-%%%%    existing fact to get \{x=$\top$\}.
-%%%%    What if the predicate in the conditional branch were @x<10@ instead
-%%%%    of @x==10@?
-%%%%    Again the first iteration would begin with the tentative fact \{x=0\}.
-%%%%    Using that fact, we would rewrite the conditional branch to an unconditional
-%%%%    branch @goto L3@.  No new fact would propagate to @L2@, and we would
-%%%%    have successfully (and soundly) eliminated the loop.
-%%%%    This example is contrived, but it illustrates that 
-%%%%    for best results we should
-%%%%    \begin{itemize}
-%%%%    \item Perform the rewrites on every iteration.
-%%%%    \item Begin each new iteration with the original, virgin graph.
-%%%%    \end{itemize}
-%%%%    This sort of algorithm is hard to implement in an imperative setting, where rewrites
-%%%%    mutate a graph in place.
-%%%%    But  with an immutable graph, implementing the algorithm
-%%%%    is trivially easy: we simply revert to the original graph at the start
-%%%%    of each fixed-point iteration.
-
-\subsection{Checkpointing the client's monad}
-
-\seclabel{ckpoint-monad} \seclabel{checkpoint-monad}
-
-When analyzing a program with loops, a rewrite function could make a change
-that later has to be rolled back.
-For example, consider constant propagation in this loop, which
-computes factorial: 
-\begin{code}
-     i = 1; `prod = 1;
- L1: if (i >= n) goto L3 else goto L2;
- L2: i = i + 1; prod = prod * i;
-     goto L1;
- L3: ...
-\end{code}
-Function @analyzeAndRewriteFwdBody@ iterates through this graph until
-the dataflow facts stop changing.
-On~the first iteration, the assignment @i = i + 1@ is
-analyzed with an incoming fact @i=1@, and the assignment is
-rewritten to the graph @i = 2@.
-But~on a later iteration, the incoming fact increases to @i=@$\top$,
-and the~rewrite is no longer justified.
-After each iteration, \hoopl\ starts the next iteration with
-\emph{new} facts but with the \emph{original} graph---by~virtue
-of using purely functional data structures, rewrites from
-previous iterations are automatically rolled back.
-{\hfuzz=1.5pt\par}
-
-But a rewrite function doesn't only produce new graphs; it
-can also take \emph{monadic actions}, such as
-acquiring a fresh name.
-These~actions must also be rolled back, and because the~client chooses
-the monad in which the actions take place, the client must provide the
-means to roll back the actions.
-\hoopl\ therefore defines a rollback \emph{interface}, which each
-client must implement; 
-it is the type class @CkpointMonad@ from
-\figref{api-types}:
-\begin{code}
-class Monad m => `CkpointMonad m where
-  type `Checkpoint m
-  `checkpoint :: m (Checkpoint m)
-  `restart    :: Checkpoint m -> m () 
-\end{code}
-\hoopl\ calls the @checkpoint@ method at the beginning of an
-iteration, then calls the @restart@ method if another iteration is
-necessary. 
-These operations must obey the following algebraic law:
-\begin{code}
- do { s <- checkpoint; m; restart s } == return ()
-\end{code}
-where @m@~represents any combination of monadic actions that might be
-taken by rewrite functions.
-(The safest course is to make sure the law holds for any action in the
-monad.)
-The~type of the saved checkpoint~@s@ is up to the client;
-it~is specified as an associated type of the @CkpointMonad@ class.
-
-\subsection{Correctness} \seclabel{correctness}
-
-% Facts computed by @analyzeAndRewriteFwdBody@ depend on graphs produced by the rewrite
-Facts computed by the transfer function depend on graphs produced by the rewrite
-function, which in turn depend on facts computed by the transfer function.
-How~do we know this algorithm is sound, or~if it terminates?
-A~proof requires a POPL paper
-\cite{lerner-grove-chambers:2002};
-here we merely state the conditions for correctness as applied to \hoopl:
-\begin{itemize}
-\item 
-The lattice must have no \emph{infinite ascending chains}; that is,
-every sequence of calls to @fact_join@ must eventually return @NoChange@.
-\item 
-The transfer function must be 
-\emph{monotonic}: given a more informative fact in,
-it must produce a more informative fact out.
-\item 
-The rewrite function must be \emph{sound}:
-if it replaces a node @n@ by a replacement graph~@g@, then @g@~must be
-observationally equivalent to~@n@ under the  
-assumptions expressed by the incoming dataflow fact~@f@.
-%%\footnote{We do not permit a transformation to change
-%%  the @Label@ of a node. We have not found any optimizations
-%%  that are prevented (or even affected) by this restriction.}
-%
-Moreover, analysis of~@g@ must produce output fact(s)
-that are at least as informative as the fact(s) produced by applying
-the transfer function to~@n@.
-%%  \item 
-%%  The rewrite function must be \emph{consistent} with the transfer function;
-%%  that is, \mbox{@`transfer n f@ $\sqsubseteq$ @transfer g f@}.
-For example, if the transfer function says that @x=7@ after the node~@n@,
-then after analysis of~@g@,
- @x@~had better still be~@7@.
-\item 
-%  To ensure termination, 
-A transformation that uses deep rewriting
-must not return a replacement graph which
-contains a node that could be rewritten indefinitely.
-\end{itemize}
-%%  Without the conditions on monotonicity and consistency,
-%%  our algorithm will terminate, 
-%%  but there is no guarantee that it will compute
-%%  a fixed point of the analysis.  And that in turn threatens the
-%%  soundness of rewrites based on possibly bogus ``facts''.
-Under these conditions, the algorithm terminates and is
-sound.
-%%  
-%%  \begin{itemize} 
-%%  \item
-%%  The algorithm terminates.  The fixed-point loop must terminate because the 
-%%  lattice has no infinite ascending chains. And the client is responsible
-%%  for avoiding infinite recursion when deep rewriting is used.
-%%  \item 
-%%  The algorithm is sound.  Why? Because if each rewrite is sound (in the sense given above), 
-%%  then applying a succession of rewrites is also sound.
-%%  Moreover, a~sound analysis of the replacement graph
-%%  may generate only dataflow facts that could have been
-%%  generated by a more complicated analysis of the original graph.
-%%  \end{itemize}
-%%  
-%%  \finalremark{Doesn't the rewrite have to be have the following property:
-%%  for a forward analysis/transform, if (rewrite P s) = Just s',
-%%  then (transfer P s $\sqsubseteq$ transfer P s').
-%%  For backward: if (rewrite Q s) = Just s', then (transfer Q s' $\sqsubseteq$ transfer Q s).
-%%  Works for liveness.
-%%  ``It works for liveness, so it must be true'' (NR).
-%%  If this is true, it's worth a QuickCheck property!
-%%  }%
-%%  \finalremark{Version 2, after further rumination.  Let's define
-%%  $\scriptstyle \mathit{rt}(f,s) = \mathit{transform}(f, \mathit{rewrite}(f,s))$.
-%%   Then $\mathit{rt}$ should
-%%  be monotonic in~$f$.  We think this is true of liveness, but we are not sure
-%%  whether it's just a generally good idea, or whether it's actually a 
-%%  precondition for some (as yet unarticulated) property of \ourlib{} to hold.}%
-
-%%%%    \simon{The rewrite functions must presumably satisfy
-%%%%    some monotonicity property.  Something like: given a more informative
-%%%%    fact, the rewrite function will rewrite a node to a more informative graph
-%%%%    (in the fact lattice.).
-%%%%    \textbf{NR}: actually the only obligation of the rewrite function is
-%%%%    to preserve observable behavior.  There's no requirement that it be
-%%%%    monotonic or indeed that it do anything useful.  It just has to
-%%%%    preserve semantics (and be a pure function of course).
-%%%%    \textbf{SLPJ} In that case I think I could cook up a program that
-%%%%    would never reach a fixed point. Imagine a liveness analysis with a loop;
-%%%%    x is initially unused anywhere.
-%%%%    At some assignment node inside the loop, the rewriter behaves as follows: 
-%%%%    if (and only if) x is dead downstream, 
-%%%%    make it alive by rewriting the assignment to mention x.
-%%%%    Now in each successive iteration x will go live/dead/live/dead etc.  I
-%%%%    maintain my claim that rewrite functions must satisfy some
-%%%%    monotonicity property.
-%%%%    \textbf{JD}: in the example you cite, monotonicity of facts at labels
-%%%%    means x cannot go live/dead/live/dead etc.  The only way we can think
-%%%%    of not to terminate is infinite ``deep rewriting.''
-%%%%    }
-
-
-
-
-\section{\ourlib's implementation}
-\seclabel{implementation}
-\seclabel{engine}
-\seclabel{dfengine}
-
-\secref{making-simple}
-gives a client's-eye view of \hoopl, showing how to 
-create analyses and transformations.
-\hoopl's interface is simple, but 
-the \emph{implementation} of interleaved analysis and rewriting is~not.  
-\citet{lerner-grove-chambers:2002} 
-do not describe their implementation.  We have written
-at least three previous implementations, all of which
-were long and hard to understand, and only one of which
-provided compile-time guarantees about open and closed shapes.
-We are not confident that any of these implementations are correct.
-
-In this paper we describe a new implementation.  It is elegant and short
-(about a third of the size of our last attempt), and it offers
-strong compile-time guarantees about shapes.  
-\finalremark{Wanted: enumerate the critical components and give each one's size}%
-%
-We describe only the implementation of \emph{forward} 
-analysis and transformation.
-The implementations of backward analysis and transformation are
-exactly analogous and are included in \hoopl.
-
-We~also explain, in \secref{first-debugging-section},  how we
-isolate errors in faulty optimizers, and how the fault-isolation
-machinery is integrated with the rest of the implementation.
-
-
-
-
-
-\subsection{Overview}
-
-
-%%  We  on @analyzeAndRewriteFwd@, whose type is more general
-%%  than that of  @analyzeAndRewriteFwdBody@:
-%%  \begin{smallcode}
-%%  `analyzeAndRewriteFwd
-%%   :: forall m n f e x. (FuelMonad m, NonLocal n)
-%%   => FwdPass m n f    -- lattice, transfers, rewrites
-%%   -> MaybeC e [Label] -- entry points for a closed graph
-%%   -> Graph n e x      -- the original graph
-%%   -> Fact e f         -- fact(s) flowing into the entry/entries
-%%   -> m (Graph n e x, FactBase f, MaybeO x f)
-%%  \end{smallcode}
-%%  We analyze graphs of all shapes; a single @FwdPass@ may be used with
-%%  multiple shapes.
-%%  If a graph is closed on entry, a list of entry points must be
-%%  provided;
-%%  if the graph is open on entry, it must be the case that the
-%%  implicit entry point is the only entry point.
-%%  The fact or set of facts flowing into the entries is similarly
-%%  determined by the shape of the entry point.
-%%  Finally, the result is a rewritten graph, a @FactBase@ that gives a
-%%  fixed point of the analysis on the rewritten graph, and if the graph
-%%  is open on exit, an ``exit  fact'' flowing out.
-
-Instead of the interface function @analyzeAndRewriteFwdBody@, we present
-the more polymorphic,  private function @arfGraph@, which is short for
-``analyze and rewrite forward graph:''
-\begin{smallfuzzcode}{15.1pt}
-`arfGraph
- :: forall m n f e x. (CkpointMonad m, NonLocal n)
- => FwdPass m n f    -- lattice, transfers, rewrites
- -> MaybeC e [Label] -- entry points for a closed graph
- -> Graph n e x      -- the original graph
- -> Fact e f         -- fact(s) flowing into entry/entries
- -> m (DG f n e x, Fact x f)
-\end{smallfuzzcode}
-Function @arfGraph@ has a more general type than
-the function @analyzeAndRewriteFwdBody@ % praying for a decent line break
-because @arfGraph@ is used recursively
-to analyze graphs of all shapes.
-If a graph is closed on entry, a list of entry points must be
-provided;
-if the graph is open on entry,
-the graph's entry sequence must be the only entry point.
-The~graph's shape on entry also determines the type of fact or facts
-flowing in.
-Finally, the result is a ``decorated graph''
-@DG f n e x@,
-and if the graph
-is open on exit, an ``exit  fact'' flowing out.
-
-%% \simon{I suggest (a) putting the paragraph break one sentence earlier,
-%%% so that this para is all about DGs.}
-%%%  NR: previous para is about the type of arfGraph; I don't want to
-%%%  leave the result type dangling.  I hope the opening sentence of
-%%%  this para suggests that the para is all about DGs.
-A~``decorated graph'' is one in which each block is decorated with the
-fact that holds at the start of the block.
-@DG@ actually shares a representation with @Graph@,
-which is possible because the definition of
-@Graph@ in \figref{graph} contains a white lie: @Graph@~is a type
-synonym for an underlying type @`Graph'@, which takes the type of block
-as an additional parameter.
-(Similarly, function @gSplice@ in \secref{gSplice} is actually a
-higher-order function that takes a block-concatenation function as a
-parameter.) 
-The truth about @Graph@ and @DG@ is as follows:
-\smallverbatiminput{dg}
-% defn DG
-% defn DBlock
-Type~@DG@ is internal to \hoopl; it is not seen by any client.
-To~convert a~@DG@ to the @Graph@ and @FactBase@
-that are returned by the API function @analyzeAndRewriteFwdBody@,
-we use a 12-line function:
-\begin{smallfuzzcode}{2.5pt}
-`normalizeGraph
- :: NonLocal n => DG f n e x -> (Graph n e x, FactBase f)
-\end{smallfuzzcode}
-
-Function @arfGraph@ is implemented as follows:
-\begingroup
-\def\^{\\[-6pt]}%
-\hfuzz=15.1pt
-\begin{smallttcode}
-arfGraph ^pass entries = graph
- where\^
- node :: forall e x . (ShapeLifter e x) 
-      => n e x       -> f        -> m (DG f n e x, Fact x f)\^
- block:: forall e x . 
-         Block n e x -> f        -> m (DG f n e x, Fact x f)\^
- body :: [Label] -> LabelMap (Block n C C)
-                     -> Fact C f -> m (DG f n C C, Fact C f)\^
- `graph:: Graph n e x -> Fact e f -> m (DG f n e x, Fact x f)\^
- ... definitions of 'node', 'block', 'body', and 'graph' ...
-\end{smallttcode}
-The four auxiliary functions help us separate concerns: for example, only 
-\endgroup
-@node@ knows about rewrite functions,
-and only @body@ knows about fixed points.
-%%  All four functions have access to the @FwdPass@ and any entry points
-%%  that are passed to @arfGraph@.
-%%  These functions also have access to type variables bound by
-%%  @arfGraph@:
-%%  @n@~is the type of nodes; @f@~is the type of facts;
-%%  @m@~is the monad used in the rewrite functions of the @FwdPass@;
-%%  and
-%%  @e@~and~@x@ give the shape of the graph passed to @arfGraph@.
-%%  The types of the inner functions are 
-%%  \begin{smallcode}
-%%  \end{smallcode}
-Each auxiliary function works the same way: it~takes a ``thing'' and
-returns an \emph{extended fact transformer}.
-An~extended fact transformer takes dataflow fact(s) coming into
-the ``thing,'' and it returns an output fact.
-It~also returns a decorated graph representing the (possibly
-rewritten) ``thing''---that's the \emph{extended} part.
-Finally, because rewrites are monadic,
-every extended fact transformer is monadic.
-
-%%%%    \begin{figure}
-%%%%    SIMON HAS ASKED IF TYPE SYNONYMS MIGHT IMPROVE THINGS FOR EXTENDED
-%%%%    FACT TRANSFORMERS.  JUDGE FOR YOURSELF.
-%%%%    FIRST, SOMETHING THAT IS SOMEWHAT READABLE BUT IS NOT LEGAL HASKELL:
-%%%%    \begin{smallcode}
-%%%%     type EFFX ipt e x = ipt -> m (DG f n e x, Fact x f) 
-%%%%        -- extended forward fact transformer
-%%%%    
-%%%%     node  :: forall e x . (ShapeLifter e x) 
-%%%%           => n e x       -> EFFX f          e x
-%%%%     block :: forall e x . 
-%%%%              Block n e x -> EFFX f          e x
-%%%%     body  :: [Label] -> LabelMap (Block n C C)
-%%%%                          -> EFFX (Fact C f) C C
-%%%%     graph :: Graph n e x -> EFFX (Fact e f) e x
-%%%%    \end{smallcode}
-%%%%    IF WE MAKE IT LEGAL HASKELL, IT BECOMES COMPLETELY HOPELESS:
-%%%%    \begin{smallcode}
-%%%%     type EFFX m n f ipt e x = ipt -> m (DG f n e x, Fact x f) 
-%%%%        -- extended forward fact transformer
-%%%%    
-%%%%     node  :: forall e x . (ShapeLifter e x) 
-%%%%           => n e x       -> EFFX m n f f e x
-%%%%     block :: forall e x . 
-%%%%              Block n e x -> EFFX m n f f e x
-%%%%     body  :: [Label] -> LabelMap (Block n C C)
-%%%%                          -> EFFX m n f (Fact C f) C C
-%%%%     graph :: Graph n e x -> EFFX m n f (Fact e f) e x
-%%%%    \end{smallcode}
-%%%%    \caption{EXPERIMENTS WITH TYPE SYNONYMS}
-%%%%    \end{figure}
-%%%%    
-
-
-The types of the
-\ifpagetuning
-\else
-four
-\fi
-extended fact transformers are not quite
-identical:
-\begin{itemize}
-\item
-Extended fact transformers for nodes and blocks have the same type;
-like forward transfer functions,
-they expect a fact~@f@ rather than the more general @Fact e f@
-required for a graph.
-Because a node or a block has
-exactly one fact flowing into the entry, it~is easiest  simply to pass
-that fact.
-\item
-Extended fact transformers for graphs have the most general type,
-as expressed using @Fact@:
-if the graph is open on entry, its~fact transformer expects a
-single fact;
-if the graph is closed on entry, its~fact transformer expects a
-@FactBase@.
-\item
-Extended fact transformers for bodies have the same type as 
-extended fact transformers for closed/closed graphs.
-\end{itemize}
-
-
-Function @arfGraph@ and its four auxiliary functions comprise a cycle of
-mutual recursion: 
-@arfGraph@ calls @graph@;
-@graph@ calls @body@ and @block@;
-@body@ calls @block@;
-@block@ calls @node@;
-and 
-@node@ calls @arfGraph@.
-These five functions do three different kinds of work:
-compose extended fact transformers, analyze and rewrite nodes, and compute
-fixed points.
-
-
-
-\subsection{Analyzing blocks and graphs by composing extended fact transformers}
-\seclabel{block-impl}
-
-Extended fact transformers compose nicely.
-For example, @block@ is implemented thus:
-\smallverbatiminput{block}
-% defn block
-%%  % we need the foralls
-%%  \begin{smallcode}
-%%    `block :: forall e x .
-%%              Block n e x -> f -> m (DG f n e x, Fact x f)
-%%    block (BFirst  n)  = node n
-%%    block (BMiddle n)  = node n
-%%    block (BLast   n)  = node n
-%%    block (BCat b1 b2) = block b1 `cat` block b2
-%%  \end{smallcode}
-The composition function @cat@ feeds facts from one extended fact
-transformer to another, and it splices decorated graphs.
-\smallverbatiminput{cat}
-% defn cat
-% local ft1
-% local ft2
-(Function @`dgSplice@ is the same splicing function used for an ordinary
-@Graph@, but it uses a one-line block-concatenation function suitable
-for @DBlock@s.)
-The name @cat@ comes from the concatenation of the decorated graphs,
-but it is also appropriate because the style in which it is used is
-reminiscent of @concatMap@, with the @node@ and @block@ functions
-playing the role of @map@.
-
-\seclabel{concat-map-style}
-
-Function @graph@ is much like @block@, but it has more cases.
-
-
-%%%%    
-%%%%    \begin{itemize} 
-%%%%    \item 
-%%%%    The @arfNode@ function processes nodes (\secref{arf-node}).
-%%%%    It handles the subtleties of interleaved analysis and rewriting,
-%%%%    and it deals with fuel consumption.  It calls @arfGraph@ to analyze
-%%%%    and transform rewritten graphs.
-%%%%    \item 
-%%%%    Based on @arfNode@ it is extremely easy to write @arfBlock@, which lifts
-%%%%    the analysis and rewriting from nodes to blocks (\secref{arf-block}).
-%%%%    
-%%%%    
-%%%%    
-%%%%    \item
-%%%%    Using @arfBlock@ we define @arfBody@, which analyzes and rewrites a
-%%%%    @Body@: a~group of closed/closed blocks linked by arbitrary
-%%%%    control flow.
-%%%%    Because a @Body@ is
-%%%%    always closed/closed and does not take shape parameters, function
-%%%%    @arfBody@ is less polymorphic than the others; its type is what
-%%%%    would be obtained by expanding and specializing the definition of
-%%%%    @ARF@ for a @thing@ which is always closed/closed and is equivalent to
-%%%%    a @Body@.
-%%%%    
-%%%%    Function @arfBody@ takes care of fixed points (\secref{arf-body}).
-%%%%    \item 
-%%%%    Based on @arfBody@ it is easy to write @arfGraph@ (\secref{arf-graph}).
-%%%%    \end{itemize}
-%%%%    Given these functions, writing the main analyzer is a simple
-%%%%    matter of matching the external API to the internal functions:
-%%%%    \begin{code}
-%%%%      `analyzeAndRewriteFwdBody
-%%%%         :: forall n f. NonLocal n
-%%%%         => FwdPass n f -> Body n -> FactBase f
-%%%%         -> FuelMonad (Body n, FactBase f)
-%%%%    
-%%%%      analyzeAndRewriteFwdBody pass ^body facts
-%%%%        = do { (^rg, _) <- arfBody pass body facts
-%%%%             ; return (normalizeBody rg) }
-%%%%    \end{code}
-%%%%     
-%%%%    \subsection{From nodes to blocks} \seclabel{arf-block}
-%%%%    \seclabel{arf-graph}
-%%%%    
-%%%%    We begin our explanation with the second task:
-%%%%    writing @arfBlock@, which analyzes and transforms blocks.
-%%%%    \begin{code}
-%%%%    `arfBlock :: NonLocal n => ARF (Block n) n
-%%%%    arfBlock pass (BUnit node) f 
-%%%%      = arfNode pass node f
-%%%%    arfBlock pass (BCat b1 b2) f 
-%%%%      = do { (g1,f1) <- arfBlock pass b1 f  
-%%%%           ; (g2,f2) <- arfBlock pass b2 f1 
-%%%%           ; return (g1 `DGCatO` g2, f2) }
-%%%%    \end{code}
-%%%%    The code is delightfully simple.
-%%%%    The @BUnit@ case is implemented by @arfNode@.
-%%%%    The @BCat@ case is implemented by recursively applying @arfBlock@ to the two
-%%%%    sub-blocks, threading the output fact from the first as the 
-%%%%    input to the second.  
-%%%%    Each recursive call produces a rewritten graph;
-%%%%    we concatenate them with @DGCatO@. 
-%%%%    
-%%%%    Function @arfGraph@ is equally straightforward:
-%%%%    XXXXXXXXXXXXXXX
-%%%%    The pattern is the same as for @arfBlock@: thread
-%%%%    facts through the sequence, and concatenate the results.
-%%%%    Because the constructors of type~@DG@ are more polymorphic than those
-%%%%    of @Graph@, type~@DG@ can represent
-%%%%    graphs more simply than @Graph@; for example, each element of a
-%%%%    @GMany@ becomes a single @DG@ object, and these @DG@ objects are then 
-%%%%    concatenated to form a single result of type~@DG@.
-%%%%    
-
-\subsection{Analyzing and rewriting nodes} \seclabel{arf-node}
-
-The @node@ function is where we interleave analysis with rewriting:
-\smallfuzzverbatiminput{15.1pt}{node}
-% defn ShapeLifter
-% defn singletonDG
-% defn fwdEntryFact
-% defn fwdEntryLabel
-% defn ftransfer
-% defn frewrite
-% local pass'
-% local grw
-%
-Function @node@ uses @frewrite@ to extract the rewrite function from
-@pass@, 
-and it applies that rewrite function to node~@n@ and incoming fact~@f@.
-The result, @grw@, is 
-scrutinized by the @case@ expression.
-
-In the @Nothing@ case, no rewrite takes place.
-We~return node~@n@ and its incoming fact~@f@
-as the decorated graph @singletonDG f n@.
-To produce the outgoing fact, we apply the transfer function
-@ftransfer pass@ to @n@~and~@f@.
-
-In the @Just@ case, we receive a replacement
-graph~@g@ and a new rewrite function~@rw@, as specified by the model
-in \secref{rewrite-model}.
-We~use @rw@ to analyze and rewrite~@g@ recursively with @arfGraph@.  
-The recursive analysis uses
-\ifpagetuning a new pass \fi
-@pass'@, which contains the original lattice and transfer
-function from @pass@, together with~@rw@.
-Function @fwdEntryFact@ converts fact~@f@ from the type~@f@,
-which @node@ has, to~the type @Fact e f@, which @arfGraph@ expects.
-
-As shown above, several functions called in @node@ are overloaded over a
-(private) class @ShapeLifter@.  Their implementations depend
-on the open/closed shape of the node.
-By design, the shape of a node is known statically everywhere @node@
-is called, so
-this use of @ShapeLifter@ is specialized
-away by the compiler.
-
-%%  And that's it!  If~the client wanted deep rewriting, it is
-%%  implemented by the call to @arfGraph@;
-%%  if the client wanted
-%%  shallow rewriting, the rewrite function will have returned
-%%  @noFwdRw@ as~@rw@, which is implanted in @pass'@
-%%  (\secref{shallow-vs-deep}).
-
-
-\subsection{Fixed points} \seclabel{arf-body}
-
-The fourth and final auxiliary function of @arfGraph@ is
-@body@, which iterates to a fixed point.
-This part of the implementation is the only really tricky part, and it is
-cleanly separated from everything else:
-\smallfuzzverbatiminput{2.5pt}{bodyfun}
-% defn body
-% local do_block
-% local blocks
-% local lattice
-% local entryFact
-% local entries
-% local init_fbase
-% local blockmap
-% local fb
-Function @getFact@ looks up a fact by its label.
-If the label is not found,
-@getFact@ returns
-the bottom element of the lattice: 
-\begin{smallcode}
-`getFact :: DataflowLattice f -> Label -> FactBase f -> f
-\end{smallcode}
-Function @forwardBlockList@ takes a list of possible entry points and 
-a finite map from labels to blocks.
-It returns a list of
-blocks, sorted into an order that makes forward dataflow efficient.\footnote
-{The order of the blocks does not affect the fixed point or any other
-result; it affects only the number of iterations needed to
-reach the fixed point.}
-\begin{smallcode}
- `forwardBlockList 
-   :: NonLocal n 
-   => [Label] -> LabelMap (Block n C C) -> [Block n C C]
-\end{smallcode}
-For
-example, if the entry point is at~@L2@, and the block at~@L2@ 
-branches to~@L1@, but not vice versa, then \hoopl\ will reach a fixed point
-more quickly if we process @L2@ before~@L1@.  
-To~find an efficient order, @forwardBlockList@ uses
-the methods of the @NonLocal@ class---@entryLabel@ and @successors@---to
-perform a reverse postorder depth-first traversal of the control-flow graph.
-%%
-%%The @NonLocal@ type-class constraint on~@n@ propagates to all the
-%%@`arfThing@ functions.
-%%  paragraph carrying too much freight
-%%
-
-The rest of the work is done by @`fixpoint@, which is shared by
-both forward and backward analyses:
-\smallfuzzverbatiminput{2.5pt}{fptype}
-% defn Direction
-% defn Fwd
-% defn Bwd
-Except for the @Direction@ passed as the first argument,
-the type signature tells the story.
-The third argument can produce an extended fact transformer for any single block; 
-@fixpoint@ applies it successively to each block in the list
-passed as the fourth argument.
-Function @fixpoint@ returns an extended fact transformer for the~list.
-
-The extended fact transformer returned by @fixpoint@
- maintains a
- ``current @FactBase@''
-which grows monotonically:
-as each block is analyzed,
-the block's input fact is taken from
-the current @FactBase@,
-and the current @FactBase@
-is
-augmented with the facts that flow out of the block.
-%
-The initial value of the current @FactBase@ is the input @FactBase@, 
-and
-the extended fact transformer
-iterates over the blocks until the current @FactBase@ 
-stops changing.
-
-
-
-Implementing @fixpoint@ requires about 90 lines,
-formatted for narrow display.
-%%  
-%%  for completeness, it
-%%  appears in Appendix~\ref{app:fixpoint}.  
-The~code, which is appended to the Web version of this paper (\webversion),
-is mostly straightforward---although we try to be clever
-about deciding when a new fact means that another iteration 
-is required.
-%
-% We'll keep the rest of this section: John judges that it has enough
-% detail to be comprehensible, and it may help someone who wants to
-% play with the code.
-%
-There is one more subtle point worth mentioning, which we highlight by 
-considering a forward analysis of this graph, where execution starts at~@L1@:
-\begin{code}
-  L1: x:=3; goto L4
-  L2: x:=4; goto L4
-  L4: if x>3 goto L2 else goto L5
-\end{code}
-Block @L2@ is unreachable. 
-But if we \naively\ process all the blocks (say in 
-order @L1@, @L4@, @L2@), then we will start with the bottom fact for @L2@, propagate
-\{@x=4@\} to @L4@, where it will join with \{@x=3@\} to yield
-\{@x=@$\top$\}.  
-Given @x=@$\top$, the
-conditional in @L4@ cannot be rewritten, and @L2@~seems reachable.  We have
-lost a good optimization.
-
-Function @fixpoint@ solves this problem 
-by analyzing a block only if the block is
-reachable from an entry point.
-This trick is safe only for a forward analysis, which
- is why
-@fixpoint@ takes a @Direction@ as its first argument.
-
-%%  Although the trick can be implemented in just a couple of lines of
-%%  code, the reasoning behind it is quite subtle---exactly the sort of
-%%  thing that should be implemented once in \hoopl, so clients don't have
-%%  to worry about it.
-
-
-\subsection{Throttling rewriting using ``optimization fuel''}
-\seclabel{vpoiso}
-\seclabel{fuel}
-\seclabel{whalley-from-s2}
-\seclabel{first-debugging-section}
-
-When optimization produces a faulty program,
-we use Whalley's \citeyearpar{whalley:isolation} technique to find the fault:
-given a program that fails when compiled with optimization,
-a binary search on the number of rewrites
-finds an~$n$ such that the program works after $n-1$ rewrites
-but fails after $n$~rewrites.
-The $n$th rewrite is faulty.
-As~alluded to at the end of \secref{debugging-introduced}, this
-technique enables us to debug complex optimizations by
-identifying one single rewrite that is faulty.
-
-To use this debugging technique, we must be able to~control
-the number of~rewrites.
-We limit rewrites using \emph{optimization fuel}.
-Each~rewrite consumes one unit of fuel,
-and when fuel is exhausted, all rewrite functions return @Nothing@.
-To~debug, we do binary search on the amount of fuel.
-
-The supply of fuel is encapsulated in the @FuelMonad@ type class (\figref{api-types}),
-which must be implemented by the client's monad @m@.
-To~ensure that each rewrite consumes one~unit of~fuel,
-@mkFRewrite@ wraps the client's rewrite function, which must be oblivious to fuel,
-in~another function that satisfies the following contract:
-\begin{itemize}
-\item 
-If the fuel supply is empty, the wrapped function always returns @Nothing@. 
-\item
-If the wrapped function returns @Just g@, it has the monadic effect of
-reducing the fuel supply by one unit.
-\end{itemize}
-
-%%%%    \seclabel{fuel-monad}
-%%%%    
-%%%%    \begin{ntext}
-%%%%    \subsection{Rewrite functions}
-%%%%    
-%%%%    
-%%%%    
-%%%%    \begin{code}
-%%%%    `withFuel :: FuelMonad m => Maybe a -> m (Maybe a)
-%%%%    \end{code}
-%%%%    
-%%%%    
-%%%%    as expressed by the
-%%%%    @FwdRew@ type returned by a @FwdRewrite@ (\figref{api-types}).
-%%%%    The first component of the @FwdRew@ is the replacement graph, as discussed earlier.
-%%%%    The second component, $\rw$, is a 
-%%%%    \emph{new rewrite function} to use when recursively processing
-%%%%    the replacement graph. 
-%%%%    For shallow rewriting this new function is
-%%%%    the constant @Nothing@ function; for deep rewriting it is the original
-%%%%    rewrite function.
-%%%%    While @mkFRewrite@ allows for general rewriting, most clients will
-%%%%    take advantage of \hoopl's support for these two common cases:
-%%%%    \begin{smallcode}
-%%%%    `deepFwdRw, `shallowFwdRw
-%%%%       :: Monad m 
-%%%%       => (forall e x . n e x -> f -> m (Maybe (Graph n e x)) 
-%%%%       -> FwdRewrite m n f
-%%%%    \end{smallcode}
-%%%%    \end{ntext}
-
-
-
-\section {Related work} \seclabel{related}
-
-While there is a vast body of literature on
-dataflow analysis and optimization,
-relatively little can be found on
-the \emph{design} of optimizers, which is the topic of this paper.
-We therefore focus on the foundations of dataflow analysis
-and on the implementations of some comparable dataflow frameworks.
-
-\paragraph{Foundations.}
-
-When transfer functions are monotone and lattices are finite in height,
-iterative dataflow analysis converges to a fixed point
-\cite{kam-ullman:global-iterative-analysis}. 
-If~the lattice's join operation distributes over transfer
-functions,
-this fixed point is equivalent to a join-over-all-paths solution to
-the recursive dataflow equations
-\cite{kildall:unified-optimization}.\footnote
-{Kildall uses meets, not joins.  
-Lattice orientation is a matter of convention, and conventions have changed.
-We use Dana Scott's
-orientation, in which higher elements carry more information.}
-\citet{kam-ullman:monotone-flow-analysis} generalize to some
-monotone functions.
-Each~client of \hoopl\ must guarantee monotonicity.
-
-\citet{cousot:abstract-interpretation:1977,cousot:systematic-analysis-frameworks}
-introduce abstract interpretation as a technique for developing
-lattices for program analysis.
-\citet{steffen:data-flow-analysis-model-checking:1991} shows that
-a dataflow analysis can be implemented using model checking;
-\citet{schmidt:data-flow-analysis-model-checking}
-expands on this~result by showing that
-an all-paths dataflow problem can be viewed as model checking an
-abstract interpretation.
-
-\citet{marlowe-ryder:properties-data-flow-frameworks} 
-present a survey of different methods for performing dataflow analyses,
-with emphasis on theoretical results.
-\citet{muchnick:compiler-implementation} 
-presents many examples of both particular analyses and related
-algorithms.
-
-
-\citet{lerner-grove-chambers:2002} show that 
-interleaving analysis and transformation is sound, 
-even when not all speculative transformations are performed on later
-iterations.
-
-
-\paragraph{Frameworks.}
-Most dataflow frameworks support only analysis, not transformation.
-The framework computes a fixed point of transfer functions, and it is
-up to the client of 
-the framework to use that fixed point for transformation.
-Omitting transformation makes it much easier to build frameworks,
-and one can find a spectrum of designs.
-We~describe  two representative
-designs, then move on to frameworks that do interleave
-analysis and transformation.
-
-The Soot framework is designed for analysis of Java programs
-\cite{hendren:soot:2000}.
-%%  {This citation is probably the
-%%  best for Soot in general, but there doesn't appear 
-%%   to be any formal publication that actually details the dataflow
-%%   framework part. ---JD}
-While Soot's dataflow library supports only analysis, not
- transformation, we found much 
-\ifpagetuning\vadjust{\break}\fi
- to admire in its design.
-Soot's library is abstracted over the representation of
-the control-flow graph and the representation of instructions.
-Soot's interface for defining lattice and analysis functions is
-like our own, 
-although because Soot is implemented in an imperative style, 
-additional functions are needed to copy lattice elements.
-
-
-The CIL toolkit \cite{necula:cil:2002}
-%%  \finalremark{No good citation
-%%  for same reason as Soot above ---JD}
-supports both analysis and rewriting of C~programs,
-but rewriting is clearly distinct from analysis:
-one runs an analysis to completion and then rewrites based on the
-results. 
-The framework is limited to one representation of control-flow graphs
-and one representation of instructions, both of which are mandated by
-the framework.
-The~API is complicated;
-much of the complexity is needed to enable the client to
-affect which instructions 
-the analysis iterates over.
-
-
-%%  \finalremark{FYI, LLVM has Pass Managers that try to control the
-%%  order of passes, 
-%%    but I'll be darned if I can find anything that might be termed a
-%%    dataflow framework.} 
-
-The Whirlwind compiler contains the dataflow framework implemented
-by \citet{lerner-grove-chambers:2002}, who were the first to 
-interleave analysis and transformation.
-Their implementation is much like our early efforts:
-it is a complicated mix of code that simultaneously manages interleaving,
-deep rewriting, and fixed-point computation.
-By~separating these tasks, 
-our implementation simplifies the problem dramatically.
-Whirlwind's implementation also suffers from the difficulty of
-maintaining pointer invariants in a mutable representation of
-control-flow graphs, a problem we have discussed elsewhere
-\cite{ramsey-dias:applicative-flow-graph}. 
-
-Because speculative transformation is difficult in an imperative setting,
-Whirlwind's implementation is split into two phases.
-The first phase runs the interleaved analyses and transformations
-to compute the final dataflow facts and a representation of the transformations
-that should be applied to the input graph.
-The second phase executes the transformations.
-In~\hoopl, because control-flow graphs are immutable, speculative transformations
-can be applied immediately, and there is no need
-for a phase distinction.
-
-%%% % repetitious...
-%%%
-%%%   \ourlib\ also improves upon Whirlwind's dataflow framework by providing
-%%%   new support for the optimization writer:
-%%%   \begin{itemize}
-%%%   \item Using static type guarantees, \hoopl\ rules out a whole
-%%%     class of possible bugs: transformations that produced malformed
-%%%     control-flow graphs.
-%%%   \item Using dynamic testing,
-%%%     we can isolate the rewrite that transforms a working program
-%%%     into a faulty program,
-%%%     using Whalley's  \citeyearpar{whalley:isolation} fault-isolation technique.
-%%%   \end{itemize}
-
-%% what follows now looks redundant with discussion below ---NR
-
-%%  In previous work \cite{ramsey-dias:applicative-flow-graph}, we
-%%  described a zipper-based representation of control-flow 
-%%  graphs, stressing the advantages
-%%  of immutability.
-%%  Our new representation, described in \secref{graph-rep}, is a significant improvement:
-%%  \begin{itemize}
-%%  \item
-%%  We can concatenate nodes, blocks, and graphs in constant time.
-%%  %Previously, we had to resort to Hughes's
-%%  %\citeyearpar{hughes:lists-representation:article} technique, representing
-%%  %a graph as a function.
-%%  \item
-%%  We can do a backward analysis without having
-%%  to ``unzip'' (and allocate a copy of) each block.
-%%  \item
-%%  Using GADTs, we can represent a flow-graph
-%%  node using a single type, instead of the triple of first, middle, and
-%%  last types used in our earlier representation.
-%%  This change simplifies the interface significantly:
-%%  instead of providing three transfer functions and three rewrite
-%%  functions per pass---one for 
-%%  each type of node---a client of \hoopl\ provides only one transfer
-%%  function and one rewrite function per pass.
-%%  \item
-%%  Errors in concatenation are ruled out at
-%%  compile-compile time by Haskell's static
-%%  type system.
-%%  In~earlier implementations, such errors were not detected until
-%%  the compiler~ran, at which point we tried to compensate
-%%  for the errors---but
-%%  the compensation code harbored subtle faults,
-%%  which we discovered while developing a new back end
-%%  for the Glasgow Haskell Compiler.
-%%  \end{itemize}
-%%  
-%%  The implementation of \ourlib\ is also much better than
-%%  our earlier implementations.
-%%  Not only is the code simpler conceptually,
-%%  but it is also shorter:
-%%  our new implementation is about a third as long
-%%  as the previous version, which is part of GHC, version 6.12.
-
-
-
-
-\section{Performance considerations}
-
-Our work on \hoopl\ is too new for us to be able to say much
-about performance.
-It~is~important to know how well \hoopl\ performs, but the
-question is comparative, and there isn't another library we can compare
-\hoopl\ with.
-For example, \hoopl\ is not a drop-in  replacement for an existing
-component of GHC; we introduced \hoopl\ to GHC as part of a
-major refactoring of GHC's back end.
-With~\hoopl,  GHC seems about 15\%~slower than
-the previous~GHC, but we
-don't know what part of the slowdown, if any, should be attributed to the
-optimizer.
-%
-We~can say that the costs of using \hoopl\ seem reasonable;
-there is no ``big performance hit.''
-And~a somewhat similar library, written in an \emph{impure} functional
-language, actually improved performance in an apples-to-apples
-comparison with a library using a mutable control-flow graph
-\cite{ramsey-dias:applicative-flow-graph}. 
-
-Although thorough evaluation of \hoopl's performance must await
-future work, we can identify some design decisions that might affect
-performance. 
-\begin{itemize}
-\item
-In \figref{graph}, we show a single concatenation operator for blocks.
-Using this representation, a block of $N$~nodes is represented using
-$2N-1$ heap objects.
-We~have also implemented a representation of blocks that include
-``cons-like'' and ``snoc-like'' constructors;
-this representation requires only $N+1$ heap objects.
-We~don't know how this choice affects performance.
-\item
-In \secref{engine}, the @body@ function analyzes and (speculatively)
-rewrites the body of a control-flow graph, and @fixpoint@ iterates
-this analysis until it reaches a fixed point.
-Decorated graphs computed on earlier iterations are thrown away.
-For~each decorated graph of $N$~nodes, 
-\ifpagetuning\vadjust{\break}\fi
-at least $2N-1$~thunks are allocated; they correspond to applications of
-@singletonDG@ in~@node@ and of @dgSplice@ in~@cat@.
-In~an earlier version of \hoopl, this overhead was
-eliminated by splitting @arfGraph@ into two phases, as in Whirlwind.
-The single @arfGraph@ is simpler and easier
-to maintain; we don't know if the extra thunks matter.
-\item
-The representation of a forward-transfer function is private to
-\hoopl.
-Two representations are possible:
-we may store a triple of functions, one for each shape a node may
-have;
-or we may store a single, polymorphic function.
-\hoopl\ uses triples, because although working with triples
-makes some code slightly more complex,
-the costs are straightforward.
-If~we used a single, polymorphic function, we would have to use a
-\emph{shape classifier} (supplied by the client) when composing
-transfer functions.
-Using a shape classifier would introduce extra @case@ discriminations
-every time we applied a transfer function or rewrite function to a
-node.
-We~don't know how these extra discriminations might affect
-performance.
-\end{itemize}
-In summary, \hoopl\ performs well enough for use in~GHC,
-but there is much we don't know.
-We have no evidence that \emph{any} of the decisions above 
-measurably affects performance---systematic investigation 
-is indicated.
-
-
-
-\section{Discussion}
-
-We built \hoopl\ in order to combine three good ideas (interleaved
-analysis and transformation, an applicative
-control-flow graph, and optimization fuel) in a way that could easily be reused by many
-compiler writers.
-To~evaluate how well we succeeded, we examine how \hoopl\ has been
-used,
-we~examine the API, and we examine the implementation.
-We~also sketch one of the many alternatives we have implemented.
-
-\paragraph{Using \hoopl.}
-
-As~suggested by the constant-propagation example in
-\figref{const-prop}, \hoopl\ makes it easy to implement many standard
-dataflow analyses.
-Students using \hoopl\ in a class at Tufts were able to implement
-such optimizations as lazy code motion \cite{knoop:lazy-code-motion} 
-and induction-variable elimination
-\cite{cocke-kennedy:operator-strength-reduction} in just a few weeks.
-Graduate students at Yale and at Portland State have also implemented
-a variety of optimizations.
-
-\hoopl's graphs can support optimizations beyond classic
-dataflow. 
-For example, in~GHC, \hoopl's  graphs are used 
-to implement optimizations based on control flow,
-such as eliminating branch chains.
-
-\hoopl\ is SSA-neutral:
-although we know of no attempt to use
-\hoopl\ to establish or enforce SSA~invariants,
-\hoopl\ makes it easy to include $\phi$-functions in the
-representation of first nodes,
-and if a transformation preserves SSA~invariants, it will continue to do
-so when implemented in \hoopl.
-
-\paragraph{Examining the API.}
-
-We hope that our presentation of the API in \secref{api} speaks for
-itself,
-but there are a couple of properties worth highlighting.
-First, it's a good sign that the API provides many higher-order
-combinators that make it easier to write client code. % with simple, expressive types.
-We~have had space to mention only a few: 
-@extendJoinDomain@, 
-@joinMaps@,
-@thenFwdRw@, @iterFwdRw@, @deepFwdRw@, and @pairFwd@.
-
-Second,
-the static encoding of open and closed shapes at compile time worked
-out well.
-% especially because it applies equally to nodes, blocks, and graphs.
-Shapes may
-seem like a small refinement, but they helped eliminate a number of
-bugs from GHC, and we expect them to help other clients too.
-GADTs are a convenient way to express shapes, and for clients
-written in Haskell, they are clearly appropriate.
-If~one wished to port \hoopl\ to a language without GADTs,
-many of the benefits could be realized by making the shapes phantom
-types, but without GADTs, pattern matching would be significantly more
-tedious and error-prone.
-
-
-% An~advantage of our ``shapely'' node API is that a client can
-% write a \emph{single} transfer function that is polymorphic in shape.
-% To~make this design work, however, we \emph{must} have
-% the type-level function 
-% @Fact@ (\figref{api-types}), to express how incoming
-% and outgoing facts depend on the shape of a node.
-% Without type-level functions, we would have had to force clients to
-% use \emph{only} the triple-of-functions interface described in
-% \secref{triple-of-functions}.
-
-\ifpagetuning\break\fi
-
-\paragraph{Examining the implementation.}
-
-If you are thinking of adopting \hoopl, you should consider not
-only whether you like the API, but whether if you had~to, you
-could maintain the implementation.
-We~believe that \secref{dfengine} sketches enough to show that \hoopl's
-implementation is a clear improvement over previous implementations
-of similar ideas.
-%%%%    % The implementation is more difficult to evaluate than the~API.
-%%%%    % Previous implementations of similar ideas have rolled the problems
-%%%%    % into a big ball of mud.
-By~decomposing our implementation into @node@, @block@, @body@,
-@graph@, @cat@, @fixpoint@, and @mkFRewrite@, we~have cleanly separated
-multiple concerns:
-interleaving analysis with rewriting,
-throttling rewriting using optimization fuel,
-and~%
-computing a fixed point using speculative rewriting.
-Because of this separation of concerns,
-we believe our implementation will be easier to maintain than
-anything that preceded~it.
-
-%%  Another good sign is that we have been able to make substantial
-%%  changes in the implementation without changing the API.
-%%  For example, in addition to ``@concatMap@ style,'' we have also
-%%  implemented @arfGraph@ in ``fold style'' and in continuation-passing
-%%  style.
-%%  Which style is preferred is a matter of taste, and possibly
-%%  a matter of  performance.
-
-
-
-
-\iffalse
-
-(We have also implemented a ``fold style,'' but because the types are
-a little less intuitive, we are sticking with @concatMap@ style for now.)
-
-
-> Some numbers, I have used it nine times, and would need the general fold
- > once to define blockToNodeList (or CB* equivalent suggested by you).
- > (We are using it in GHC to
- >   - computing hash of the blocks from the nodes
- >   - finding the last node of a block
- >   - converting block to the old representation (2x)
- >   - computing interference graph
- >   - counting Area used by a block (2x)
- >   - counting stack high-water mark for a block
- >   - prettyprinting block)
-
-
-type-parameter hell, newtype hell, typechecking hell, instance hell,
-triple hell
-
-\fi
-
-
-% We have spent six years implementing and reimplementing frameworks for
-% dataflow analysis and transformation.
-%  This formidable design problem taught us
-% two kinds of lessons:
-% we learned some very specific lessons about representations and
-% algorithms for optimizing compilers,
-% and we were forcibly reminded of some very general, old lessons that are well
-% known not just to functional programmers, but to programmers
-% everywhere.
-
-
-
-%%%%    \remark{Orphaned: but for transfer functions that
-%%%%    approximate weakest preconditions or strongest postconditions,
-%%%%    monotonicity falls out naturally.}
-%%%%    
-%%%%    
-%%%%    In conclusion we offer the following lessons from the experience of designing
-%%%%    and implementing \ourlib{}.
-%%%%    \begin{itemize}
-%%%%    \item 
-%%%%    Although we have not stressed this point, there is a close connection
-%%%%    between dataflow analyses and program logic:
-%%%%    \begin{itemize}
-%%%%    \item
-%%%%    A forward dataflow analysis is represented by a predicate transformer
-%%%%    that is related to \emph{strongest postconditions}
-%%%%    \cite{floyd:meaning}.\footnote
-%%%%    {In Floyd's paper the output of the predicate transformer is called
-%%%%    the \emph{strongest verifiable consequent}, not the ``strongest
-%%%%    postcondition.''} 
-%%%%    \item
-%%%%    A backward dataflow analysis is represented by a predicate transformer
-%%%%    that is related to \emph{weakest preconditions} \cite{dijkstra:discipline}.
-%%%%    \end{itemize}
-%%%%    Logicians write down the predicate transformers for the primitive
-%%%%    program fragments, and then use compositional rules to ``lift'' them 
-%%%%    to a logic for whole programs.  In the same way \ourlib{} lets the client
-%%%%    write simple predicate transformers,
-%%%%    and local rewrites based on those assertions, and ``lifts'' them to entire
-%%%%    function bodies with arbitrary control flow.
-
-\iffalse
-
-
-Reuse requires abstraction, and as is well known,
-designing good abstractions is challenging. 
-\hoopl's data types and the functions over those types have been
-through {dozens} of revisions.
-\remark{dozens alert}
-As~we were refining our design, we~found it invaluable to operate in
-two modes:
-In the first mode, we designed, built, and used a framework as an
-important component of a real compiler (first Quick~{\PAL}, then GHC).
-In the second mode, we designed and built a standalone library, then
-redesigned and rebuilt it, sometimes going through several significant
-changes in a week.
-Operating in the first mode---inside a live compiler---forced us to
-make sure that no corners were cut, that we were solving a real
-problem, and that we did not inadvertently
-cripple some other part of the compiler.
-Operating in the second mode---as a standalone library---enabled us to
-iterate furiously, trying out many more ideas than would have
-been possible in the first mode.
- Alternating between these two modes has led to a
-better design than operating in either mode alone.
-
-%% We were forcibly reminded of timeless truths:
-It is a truth universally acknowledged that
-interfaces are more important than implementations and data
-is more important than code.
-This truth is reflected in this paper, in which
-we
-have given \hoopl's API three times as much space as \hoopl's implementation.
-
-We have evaluate \hoopl's API through small, focused classroom
-projects and by using \hoopl\ in the back end of the Glasgow Haskell
-Compiler. 
-
-
-
-We were also reminded that Haskell's type system (polymorphism, GADTs,
-higher-order functions, type classes, and so on) is a remarkably
-effective 
-language for thinking about data and code---and that
-Haskell lacks a language of interfaces (like ML's signatures) that
-would make it equally effective for thinking about APIs at a larger scale.
-Still, as usual, the types were a remarkable aid to writing the code:
-when we finally agreed on the types presented above, the
-code almost wrote itself.  
-
-Types are widely appreciated at ICFP, but  here are three specific
-examples of how types helped us:
-\begin{itemize}
-\item 
-Reuse is enabled by representation-independence, which in a functional
-language is
-expressed through parametric polymorphism.
-Making \ourlib{} polymorphic in the nodes 
-made the code simpler, easier to understand, and easier to maintain.
-In particular, it forced us to make explicit \emph{exactly} what
-\ourlib\ must know about nodes, and to embody that knowledge in the
-@NonLocal@ type class (\secref{nonlocal-class}). 
-\item
-\remark{too much? Simon: better?}
-%
-% this paper is just not about run-time performance ---NR
-%
-%%%%    Moreover, the implementation is faster than it would otherwise be,
-%%%%    because, say, a @(Fact O f)e@ is known to be just an @f@ rather than
-%%%%    being a sum type that must be tested (with a statically known outcome!).
-%
-Giving the \emph{same} shapes
-to nodes, blocks, and graphs helped our
-thinking and helped to structure the implementation.
-\item
-\end{itemize}
-
-\fi
-
-\paragraph{Design alternatives.}
-We~have explored many alternatives to the API presented above.
-While these alternatives are interesting,
-describing and discussing an interesting alternative seems to take us
-a~half-column or
-a~column of text.
-Accordingly, we discuss only the single most interesting alternative:
-keeping the rewrite monad~@m@ private instead of allowing the client
-to define~it.
-
-We~have implemented an alternative~API in which every rewrite function
-must use a monad mandated by~\hoopl.
-This alternative has advantages: 
-\hoopl{} implements
-@checkpoint@, @restart@, 
-@setFuel@, and @getFuel@, 
-so we can ensure that they are right and
-that the client cannot misuse them. 
-The downside is that the only actions a rewrite function can take are
-the actions in the monad(s) mandated by \hoopl.
-These monads must therefore provide extra 
-actions that a client might need, such as supplying fresh labels for
-new blocks.
-Worse, \hoopl\ can't possibly anticipate every action a client might want
-to take.
-What if a client wanted one set of
-unique names for labels and a different set for registers?
-What if, in order to judge the effectiveness of an optimization,
-a client wanted to log how many rewrites take place, or in what
-functions they take place?
-Or~what if a client wanted to implement
-Primitive Redex 
-Speculation \cite{runciman:increasing-prs}, a code-improving
-transformation that can create new 
-function definitions? 
-\hoopl's predefined monads don't accommodate any of these actions.
-By~permitting the client to define the monad~@m@, we~risk the possibility
-that the client may implement key operations incorrectly, but we also
-ensure that
-\hoopl\ can support these examples, as well as other examples not yet
-thought of. 
-
-%%  A~\hoopl\ client implementing this transformation would define a monad
-%%  that could accumulate new definitions.
-%%  The law governing @checkpoint@ and @restart@
-%%  would ensure that a speculative rewrite, if later rolled back, would not
-%%  create  a function definition (or a log entry).
-
-% no~matter how well designed the~API,
-% if it does not play well with existing code,
-% it won't be used.
-
-
-
-
-%%   Another merit of a user-defined monad~@m@ is that, 
-%%   if~a user wants to manage optimization fuel differently,
-%%   he or she can make~@m@ an instance of @FuelMonad@ in which the fuel
-%%   supply is infinite.\john{This is all cool,
-%%   but I don't think the reader would follow without a lot of hand holding.}
-%%   The user is then free to create a new fuel supply in~@m@ and to wrap
-%%   rewrite functions---or not---so as to consume fuel in the new supply.
-%%   This freedom can be~used to implement more exotic uses of fuel;
-%%   for~example, a~user might find it convenient to~rewrite
-%%   a compiler temporary to a hardware register
-%%   without consuming fuel.
-
-%%  \simon{These next two paras are incomprehensible. Cut?}
-%%  Of the many varied implementations we have tried,
-%%  we have space only to raise a few questions, with even fewer answers.
-%%  %
-%%  An~earlier implementation of @fixpoint@ stored the
-%%  ``current'' @FactBase@ in a monad; we~find it easier to understand and
-%%  maintain the code that passes the current @FactBase@ as an argument.
-%%  Among @concatMap@ style, fold style, and continuation-passing style, 
-%%  which is best?
-%%  No~one of these styles makes all the code easiest to read
-%%  and understand: @concatMap@ style is relatively straightforward throughout;
-%%  fold~style is similar overall but different in detail;
-%%  and continuation-passing style is clear and elegant to those who
-%%  like continuations, but baffling to those who don't.
-
-%%  Which value constructors should be\simon{still incomprehensible.  cut?}
-%%  \john{I think only someone who has tried to change the code can understand
-%%  why these questions are interesting.}
-%%  polymorphic in the shapes of their arguments, and which should be
-%%  monomorphic?
-%%  We~experimented with a polymorphic
-%%  \begin{code}
-%%    `BNode :: n e x -> Block n e x
-%%  \end{code}
-%%  but we found that there are significant advantages to knowing the type
-%%  of every node statically, using purely local information---so instead
-%%  we use
-%%  the three monomorphic constructors @BFirst@, @BMiddle@, and @BLast@
-%%  (\figref{graph}). 
-%%  Similar questions arise about the polymorphic @BCat@ and about the
-%%  graph constructors, and even among ourselves, we are divided about how
-%%  best to answer them.
-%%  Yet another question is whether it is worthwhile to save a level of
-%%  indirection by providing a cons-like constructor to concatenate a node
-%%  and a block. 
-%%  Perhaps some of these questions can be answered by appealing to
-%%  performance, but the experiments that will provide the answers have
-%%  yet to be devised.
-
-
-
-
-\paragraph{Final remarks.}
-
-Dataflow optimization is usually described as a way to improve imperative
-programs by mutating control-flow graphs.
-Such transformations appear very different from the tree rewriting
-that functional languages are so well known for and which makes
-\ifhaskellworkshop
-Haskell
-\else
-functional languages 
-\fi
-so attractive for writing other parts of compilers.
-But even though dataflow optimization looks very different from
-what we are used to,
-writing a dataflow optimizer
-in
-\ifhaskellworkshop
-Haskell
-\else
-a pure functional language 
-\fi
-was a win:
-%  We could not possibly have conceived \ourlib{} in C++.
-we had to make every input and output explicit,
-and we had a strong incentive to implement things compositionally.
-Using Haskell helped us make real improvements in the implementation of
-some very sophisticated ideas.
-% %%  
-% %%  
-% %%  In~a pure functional language, not only do we know that
-% %%  no data structure will be unexpectedly mutated,
-% %%  but we are forced to be
-% %%  explicit about every input and output, 
-% %%  and we are encouraged to implement things compositionally.
-% %%  This kind of thinking has helped us make
-% %%  significant improvements to the already tricky work of Lerner, Grove,
-% %%  and Chambers:
-% %%  per-function control of shallow vs deep rewriting 
-% %%  (\secref{shallow-vs-deep}),
-% %%  optimization fuel (\secref{fuel}),
-% %%  and transparent management of unreachable blocks (\secref{arf-body}).
-% We~trust that the improvements are right only because they are
-% implemented in separate 
-% parts of the code that cannot interact except through
-% explicit function calls.
-% %%  %%
-% %%  %%An ancestor of \ourlib{} is in the Glasgow Haskell Compiler today,
-% %%  %%in version~6.12.
-% %%  With this new, improved design in hand, we are now moving back to
-% %%  live-compiler mode,  pushing \hoopl\ into version
-% %%  6.13 of the Glasgow Haskell Compiler.
-
-
-\acks
-
-Brian Huffman and Graham Hutton helped with algebraic laws.
-Sukyoung Ryu told us about Primitive Redex Speculation.
-Several anonymous reviewers helped improve the presentation.
-% , especially reviewer~C, who suggested better language with which to
-% describe our work.  
-
-The first and second authors were funded 
-by a grant from Intel Corporation and
-by NSF awards CCF-0838899 and CCF-0311482.
-These authors also thank Microsoft Research Ltd, UK, for funding
-extended visits to the third author.
-
-
-\vfil\break % balance final columns
-
-\makeatother
-
-\providecommand\includeftpref{\relax} %% total bafflement -- workaround
-\IfFileExists{nrbib.tex}{\bibliography{cs,ramsey}}{\bibliography{dfopt}}
-\bibliographystyle{plainnatx}
-
-
-\clearpage
-
-\appendix
-
-% don't omit LabelSet :: *
-% don't omit delFromFactBase :: FactBase f -> [(Label,f)] -> FactBase f
-% don't omit elemFactBase :: Label -> FactBase f -> Bool
-% don't omit elemLabelSet :: Label -> LabelSet -> Bool
-% don't omit emptyLabelSet :: LabelSet
-% don't omit factBaseLabels :: FactBase f -> [Label]
-% don't omit extendFactBase :: FactBase f -> Label -> f -> FactBase f
-% don't omit extendLabelSet :: LabelSet -> Label -> LabelSet
-% don't omit factBaseList :: FactBase f -> [(Label, f)]
-
-%%  \section{Code for \textmd{\texttt{fixpoint}}}
-%%  \label{app:fixpoint}
-%%  
-%%  {\def\baselinestretch{0.95}\hfuzz=20pt
-%%  \begin{smallcode}
-%%  data `TxFactBase n f
-%%    = `TxFB { `tfb_fbase :: FactBase f
-%%           , `tfb_rg  :: DG n f C C -- Transformed blocks
-%%           , `tfb_cha   :: ChangeFlag
-%%           , `tfb_lbls  :: LabelSet }
-%%   -- Set the tfb_cha flag iff 
-%%   --   (a) the fact in tfb_fbase for or a block L changes
-%%   --   (b) L is in tfb_lbls.
-%%   -- The tfb_lbls are all Labels of the *original* 
-%%   -- (not transformed) blocks
-%%  
-%%  `updateFact :: DataflowLattice f -> LabelSet -> (Label, f)
-%%             -> (ChangeFlag, FactBase f) 
-%%             -> (ChangeFlag, FactBase f)
-%%  updateFact ^lat ^lbls (lbl, ^new_fact) (^cha, fbase)
-%%    | NoChange <- ^cha2        = (cha,        fbase)
-%%    | lbl `elemLabelSet` lbls = (SomeChange, new_fbase)
-%%    | otherwise               = (cha,        new_fbase)
-%%    where
-%%      (cha2, ^res_fact) 
-%%        = case lookupFact fbase lbl of
-%%           Nothing -> (SomeChange, new_fact)
-%%           Just ^old_fact -> fact_extend lat old_fact new_fact
-%%      ^new_fbase = extendFactBase fbase lbl res_fact
-%%  
-%%  fixpoint :: forall n f. NonLocal n
-%%           => Bool        -- Going forward?
-%%           -> DataflowLattice f
-%%           -> (Block n C C -> FactBase f
-%%                -> FuelMonad (DG n f C C, FactBase f))
-%%           -> FactBase f -> [(Label, Block n C C)]
-%%           -> FuelMonad (DG n f C C, FactBase f)
-%%  fixpoint ^is_fwd lat ^do_block ^init_fbase ^blocks
-%%   = do { ^fuel <- getFuel  
-%%        ; ^tx_fb <- loop fuel init_fbase
-%%        ; return (tfb_rg tx_fb, 
-%%                  tfb_fbase tx_fb `delFromFactBase` blocks) }
-%%            -- The outgoing FactBase contains facts only for 
-%%            -- Labels *not* in the blocks of the graph
-%%   where
-%%    `tx_blocks :: [(Label, Block n C C)] 
-%%              -> TxFactBase n f -> FuelMonad (TxFactBase n f)
-%%    tx_blocks []             tx_fb = return tx_fb
-%%    tx_blocks ((lbl,blk):bs) tx_fb = tx_block lbl blk tx_fb
-%%                                     >>= tx_blocks bs
-%%  
-%%    `tx_block :: Label -> Block n C C 
-%%             -> TxFactBase n f -> FuelMonad (TxFactBase n f)
-%%    tx_block ^lbl ^blk tx_fb@(TxFB { tfb_fbase = fbase
-%%                                 , tfb_lbls  = lbls
-%%                                 , tfb_rg    = ^blks
-%%                                 , tfb_cha   = cha })
-%%      | is_fwd && not (lbl `elemFactBase` fbase)
-%%      = return tx_fb    -- Note [Unreachable blocks]
-%%      | otherwise
-%%      = do { (rg, ^out_facts) <- do_block blk fbase
-%%           ; let (^cha', ^fbase') 
-%%                   = foldr (updateFact lat lbls) (cha,fbase) 
-%%                           (factBaseList out_facts)
-%%           ; return (TxFB { tfb_lbls = extendLabelSet lbls lbl
-%%                          , tfb_rg   = rg `DGCatC` blks
-%%                          , tfb_fbase = fbase'
-%%                          , tfb_cha = cha' }) }
-%%  
-%%    loop :: Fuel -> FactBase f -> FuelMonad (TxFactBase n f)
-%%    `loop fuel fbase 
-%%      = do { let ^init_tx_fb = TxFB { tfb_fbase = fbase
-%%                                   , tfb_cha   = NoChange
-%%                                   , tfb_rg    = DGNil
-%%                                   , tfb_lbls  = emptyLabelSet}
-%%           ; tx_fb <- tx_blocks blocks init_tx_fb
-%%           ; case tfb_cha tx_fb of
-%%               NoChange   -> return tx_fb
-%%               SomeChange -> setFuel fuel >>
-%%                             loop fuel (tfb_fbase tx_fb) }
-%%  \end{smallcode}
-%%  \par
-%%  } % end \baselinestretch
-
-
-\section{Index of defined identifiers}
-
-This appendix lists every nontrivial identifier used in the body of
-the paper.  
-For each identifier, we list the page on which that identifier is
-defined or discussed---or when appropriate, the figure (with line
-number where possible).
-For those few identifiers not defined or discussed in text, we give
-the type signature and the page on which the identifier is first
-referred to.
-
-Some identifiers used in the text are defined in the Haskell Prelude;
-for those readers less familiar with Haskell (possible even at the
-Haskell Symposium!), these identifiers are
-listed in Appendix~\ref{sec:prelude}.
-
-\newcommand\dropit[3][]{}
-
-\newcommand\ixcr{\\[0pt plus 0.3pt]}
-
-\newcommand\hsprelude[2]{\noindent
-  \texttt{#1} defined in the Haskell Prelude\ixcr}
-\let\hsprelude\dropit
-
-\newcommand\hspagedef[3][]{\noindent
-  \texttt{#2} defined on page~\pageref{#3}.\ixcr}
-\newcommand\omithspagedef[3][]{\noindent
-  \texttt{#2} not shown (but see page~\pageref{#3}).\ixcr}
-\newcommand\omithsfigdef[3][]{\noindent
-  \texttt{#2} not shown (but see Figure~\ref{#3} on page~\pageref{#3}).\ixcr}
-\newcommand\hsfigdef[3][]{%
-  \noindent
-  \ifx!#1!%
-    \texttt{#2} defined in Figure~\ref{#3} on page~\pageref{#3}.\ixcr
-  \else
-    \texttt{#2} defined on \lineref{#1} of Figure~\ref{#3} on page~\pageref{#3}.\ixcr
-  \fi
-}    
-\newcommand\hstabdef[3][]{%
-  \noindent
-  \ifx!#1!
-    \texttt{#2} defined in Table~\ref{#3} on page~\pageref{#3}.\ixcr
-  \else
-    \texttt{#2} defined on \lineref{#1} of Table~\ref{#3} on page~\pageref{#3}.\ixcr
-  \fi
-}    
-\newcommand\hspagedefll[3][]{\noindent
-  \texttt{#2} {let}- or $\lambda$-bound on page~\pageref{#3}.\ixcr}
-\newcommand\hsfigdefll[3][]{%
-  \noindent
-  \ifx!#1!%
-    \texttt{#2} {let}- or $\lambda$-bound in Figure~\ref{#3} on page~\pageref{#3}.\ixcr
-  \else
-    \texttt{#2} {let}- or $\lambda$-bound on \lineref{#1} of Figure~\ref{#3} on page~\pageref{#3}.\ixcr
-  \fi
-}    
-
-\newcommand\nothspagedef[3][]{\notdefd\ndpage{#1}{#2}{#3}}
-\newcommand\nothsfigdef[3][]{\notdefd\ndfig{#1}{#2}{#3}}
-\newcommand\nothslinedef[3][]{\notdefd\ndline{#1}{#2}{#3}}
-
-\newcommand\ndpage[3]{\texttt{#2}~(p\pageref{#3})}
-\newcommand\ndfig[3]{\texttt{#2}~(Fig~\ref{#3},~p\pageref{#3})}
-\newcommand\ndline[3]{%
-  \ifx!#1!%
-      \ndfig{#1}{#2}{#3}%
-  \else
-      \texttt{#2}~(Fig~\ref{#3}, line~\lineref{#1}, p\pageref{#3})%
-  \fi
-}
-
-\newif\ifundefinedsection\undefinedsectionfalse
-
-\newcommand\notdefd[4]{%
-  \ifundefinedsection
-    , #1{#2}{#3}{#4}%
-  \else
-    \undefinedsectiontrue
-    \par
-    \section{Undefined identifiers}
-    #1{#2}{#3}{#4}%
-  \fi
-}
-
-\begingroup
-\raggedright
-
-\input{defuse}%
-\ifundefinedsection.\fi
-
-\undefinedsectionfalse
-
-
-\renewcommand\hsprelude[2]{\noindent
-  \ifundefinedsection
-    , \texttt{#1}%
-  \else
-    \undefinedsectiontrue
-    \par
-    \section{Identifiers defined in Haskell Prelude or a standard library}\label{sec:prelude}
-    \texttt{#1}%
-  \fi
-}
-\let\hspagedef\dropit
-\let\omithspagedef\dropit
-\let\omithsfigdef\dropit
-\let\hsfigdef\dropit
-\let\hstabdef\dropit
-\let\hspagedefll\dropit
-\let\hsfigdefll\dropit
-\let\nothspagedef\dropit
-\let\nothsfigdef\dropit
-\let\nothslinedef\dropit
-
-\input{defuse}
-\ifundefinedsection.\fi
-
-
-
-\endgroup
-
-
-\section{Computation of fixed points}
-
-Function \verb@updateFact@ updates the current \verb@FactBase@ and
-sets the \verb@ChangeFlag@.
-
-\smallverbatiminput{update}
-% defn updateFact
-% local lat
-% local lbl
-% local lbls
-% local new_fact
-% local cha
-% local cha2
-% local res_fact
-% local fbase
-% local new_fbase
-% local new_fact_debug
-% local old_fact
-% local join
-
-\vfilbreak[1.5in]
-
-
-Datatype \verb@TxFactBase@ 
-accumulates facts (and the transformed code) during the fixpoint
-iteration.
-
-\smallverbatiminput{txfb}
-% defn TxFactBase
-% defn TxFB
-% defn tfb_cha
-% defn tfb_fbase
-% defn tfb_lbls
-% defn tfb_rg
-
-
-\smallverbatiminput{fpimp}
-% local direction
-% local blocks
-% local tagged_blocks
-% local is_fwd
-% local tag
-% local tx_blocks
-% local blk
-% local blks
-% local cha'
-% local fbase'
-% local init_tx
-% local tx_fb
-% omit dgnilC :: DG f n C C
-% omit LabelSet :: *
-% local lbls'
-% local loop
-% local rg
-% local tx_block
-% local out_facts
-% local in_lbls
-
-% omit lookupFact :: FactBase f -> Label -> Maybe f
-% omit mapDeleteList :: [Label] -> LabelMap a -> LabelMap a
-% omit mapFoldWithKey :: (Label -> a -> b -> b) -> b -> LabelMap a -> b
-% omit mapInsert :: Label -> a -> LabelMap a -> LabelMap a
-% omit mapMember :: Label -> LabelMap a -> Bool
-
-% omit setEmpty :: LabelSet
-% omit setFromList :: [Label] -> LabelSet
-% omit setMember :: Label -> LabelSet -> Bool
-% omit setUnion :: LabelSet -> LabelSet -> LabelSet
-
-\vfilbreak[0.5in]
-
-Here are some of the invariants of the \verb@TxFactBase@ used by algorithm:
-\begin{itemize} 
-\item The current \verb@FactBase@,  \verb@tfb_fbase@, increases monotonically.
-\item 
-During an iteration,
-\verb@tfb_lbls@ is the set of in-labels of all blocks that have
-  been processed so far this sweep, including the block that is
-  currently being processed.  
-It is a
-  subset of the Labels of the \emph{original} (not transformed) blocks.
-\item 
-During an iteration,
-\verb@tfb_cha@ is set to \verb@SomeChange@ if and only if we decide another
-iteration will be needed.
-It is set if the fact in \verb@tfb_fbase@ for a block~@L@ changes
-\emph{and}  \verb@L@~is in \verb@tfb_lbls@.
-(Until a label enters \verb@tfb_lbls@, its fact in \verb@tfb_fbase@
-  has not been read, hence it cannot affect the outcome.)
-\end{itemize}
-
-
-\iffalse
-
-\section{Dataflow-engine functions}
-
-
-\begin{figure*}
-\setcounter{codeline}{0}
-\begin{numberedcode}
-\end{numberedcode}
-\caption{The forward iterator}
-\end{figure*}
-
-\begin{figure*}
-\setcounter{codeline}{0}
-\begin{numberedcode}
-\end{numberedcode}
-\caption{The forward actualizer}
-\end{figure*}
-
-
-\fi
-
-
-
-\end{document}
-
-
-
-
-THE FUEL PROBLEM:
-
-
-Here is the problem:
-
-  A graph has an entry sequence, a body, and an exit sequence.
-  Correctly computing facts on and flowing out of the body requires
-  iteration; computation on the entry and exit sequences do not, since
-  each is connected to the body by exactly one flow edge.
-
-  The problem is to provide the correct fuel supply to the combined
-  analysis/rewrite (iterator) functions, so that speculative rewriting
-  is limited by the fuel supply.
-
-  I will number iterations from 1 and name the fuel supplies as
-  follows:
-
-     f_pre      fuel remaining before analysis/rewriting starts
-     f_0        fuel remaining after analysis/rewriting of the entry sequence
-     f_i, i>0   fuel remaining after iteration i of the body
-     f_post     fuel remaining after analysis/rewriting of the exit sequence
-
-  The issue here is that only the last iteration of the body 'counts'.
-  To formalize, I will name fuel consumed:
-
-     C_pre      fuel consumed by speculative rewrites in entry sequence
-     C_i        fuel consumed by speculative rewrites in iteration i of body
-     C_post     fuel consumed by speculative rewrites in exit sequence
-
-  These quantities should be related as follows:
-
-     f_0    = f_pre - C_pref
-     f_i    = f_0 - C_i            where i > 0
-     f_post = f_n - C_post         where iteration converges after n steps
-
-When the fuel supply is passed explicitly as parameter and result, it
-is fairly easy to see how to keep reusing f_0 at every iteration, then
-extract f_n for use before the exit sequence.  It is not obvious to me
-how to do it cleanly using the fuel monad.
-
-
-Norman
diff --git a/paper/haskell-reviews.txt b/paper/haskell-reviews.txt
deleted file mode 100644 (file)
index 298fc9f..0000000
+++ /dev/null
@@ -1,222 +0,0 @@
-Date: Mon, 12 Jul 2010 10:26:20 +0100
-From: Haskell 2010 <haskell2010@easychair.org>
-To: Norman Ramsey <nr@cs.tufts.edu>
-Subject: Haskell 2010 notification for paper 6
-
-Dear Norman, 
-
-Thanks again for your submission "Hoopl: A Modular, Reusable Library for
-Dataflow Analysis and Transformation" to the Haskell Symposium 2010. I'm happy
-to report that it has been accepted for publication. We had a record number of
-submissions this year, and I'm looking forward to hearing your talk during a
-very exciting day on 30th September in Baltimore.
-
-Final papers are due with the publishers on Monday 2nd August; I believe that
-this deadline is firm. I will be in touch soon with more instructions.
-
-Cheers,
-Jeremy
-
-
-===========================  REVIEWS  ==========================
-
----------------------------- REVIEW 1 -------------------------- PAPER: 6
-TITLE: Hoopl: A Modular, Reusable Library for Dataflow Analysis and
-Transformation
-OVERALL RATING: 3 (strong accept) 
-REVIEWER'S CONFIDENCE: 3 (high) 
-
-I enjoyed this paper very much.  Compiler optimisation is a fun topic,
-and this library (to implement the analysis that is at the very core of
-most imperative optimisations) is both nicely designed and nicely
-described.
-
-Only a few minor suggestions for improvement.
-
-In the definition bullets at the start of Section 3, it is left unstated
-whether _edges_ connect _blocks_, in addition to connecting _nodes_
-within _blocks_ (bullet 3).  Bullet 4 defines a _graph_ as a composition
-of _blocks_, but also does not mention _edges_.  As someone who knows
-what dataflow means, the missing information is obvious to me, but it
-should be made precise for the reader with less prior knowledge.
-
-It is revealed later on, in section 3.4, that there are two different
-kinds of edge: edges connecting nodes are implicit, edges connecting
-blocks are explicit.  It might be worth bringing this distinction
-forward into the initial definition bullets.
-
-In 3.4, the first mention of _program_point_ should be italicised, as
-this is the definition of the term.
-
-In 3.5 and 3.6, the fact that the definitions of gSplice and NonLocal
-are statically exhaustive is (a) surprising, (b) subtle, and (c) very
-cool.
-
-Section 8 "Examining the API", First sentence: typo "the" -> "that" 
-
-
-
----------------------------- REVIEW 2 -------------------------- PAPER: 6
-TITLE: Hoopl: A Modular, Reusable Library for Dataflow Analysis and
-Transformation
-OVERALL RATING: 1 (weak accept) 
-REVIEWER'S CONFIDENCE: 3 (high) 
-
-Hoopl is a Haskell library that implements the interleaved dataflow
-analysis and transformation framework of Lerner, Grove, and Chambers
-(POPL02).  The library is polymorphic in the types of graph nodes and
-dataflow facts; this flexibility is achieved using some advanced GHC
-type features.  It is used in the development version of GHC's back
-end. The paper describes Hoopl's capabilities, interface, and
-implementation.
-
-This is a beautifully polished paper, which manages to describe Hoopl
-very clearly and yet concisely; indeed, I cannot suggest any
-substantive improvements in this regard.  Moreover, the paper should
-be of interest and utility to compiler writers of all persuasions.
-
-And yet...I cannot give the paper the highest possible score because
-I'm not certain that it is suitable for publication in the Haskell
-Symposium. The CFP notes that "it is not enough simply to describe a
-program!" But that is really what this paper does -- albeit very well.
-Readers who are interested in Hoopl because of what it does will be
-happy, but others may not get much out of the paper.
-
-There are a couple of ways in which the material could be made more
-relevant to the general Symposium audience:
-
-- Disucss the benefits (and limitations?) of the advanced type
-features used by Hoopl, and contrast with what the interface might
-look like without them.
-
-- Discuss the impact of Hoopl on GHC itself; e.g., how has it improved
-the quality of generated code?
-
-But a better audience for the paper might be a compiler implementation
-conference (like CC) -- for which you'd scarcely need to change a
-word.
-
-Small points and typos:
-
-p. 1 abstract, line 5: "for _any_ compiler" written in Haskell, that is.
-p. 1 col 2 section 1 line -4 : "requires" -> "uses" (?)  
-p. 4 col 1 defn. of gSplice: 'mapUnion' and 'addBlock' are not defined
-              (though perhaps one can guess the definitions)
-p. 7 col 1 after second display : "number functions" -> "number of functions"
-p. 10 footnote 3 : "is conventional" -> "is a matter of convention" 
-
-
-
----------------------------- REVIEW 3 -------------------------- PAPER: 6
-TITLE: Hoopl: A Modular, Reusable Library for Dataflow Analysis and
-Transformation
-OVERALL RATING: 2 (accept) 
-REVIEWER'S CONFIDENCE: 3 (high) 
-
-Summary:
-
-This paper describes a library, called Hoopl, for writing dataflow analyses
-and transformation. The library is not tied to a particular compiler, but can
-be reused by any client program by providing a few definitions; specifically
-client programs must provide definitions (interface and implementation) of
-nodes and dataflow facts as well as implementations (because the interface is
-provided by Hoopl) of dataflow transfer-, and rewrite-functions.
-
-Hoopl implements the idea of interleaving analyses with transformation as
-presented by Lerner, Grove, and Chambers (Composing Dataflow Analyses and
-Transformations) in their 2002 POPL paper. Each analysis and transformation is
-specified separately, but applied interleaved so that each analysis and
-transformation can benefit from the results of each other.
-
-A major contribution of Lerner, Grove, and Chambers is a proof that the
-interleaving algorithm is sound and terminating. However, their presentation
-is significantly more complex than the one given in the present paper. The
-authors of the present paper state the conditions under which their algorithm
-is sound and terminating but otherwise focus on presenting Hoopl.
-
-The paper is divided in two major parts; the first part describes how a client
-program can make use of Hoopl in terms of a simple constant propagation
-example. The second part describes the implementation of Hoopl.
-
-Many details are covered in the paper. Perhaps a little too many; from page 2
-to 10 at least two new concepts are introduced (in terms of source code). For
-some concepts, the actual definition is only given later in the paper. E.g.
-the concept "FuelMonad" is introduced on page 5, but the purpose of the Monad
-is only explained on page 10. It is helpful to have an almost complete example
-of how a client program would use Hoopl, on the other hand, a smaller example
-could give more room for describing the actual implementation of Hoopl.
-
->From all the details in the paper it is clear that much work has been put
->into Hoopl and that many important design
-decisions have been made in order to reach the current status. The simple API
-provided by Hoopl is therefore a major contribution, but also the fact that
-Hoopl is implemented in Haskell instead of the less used Whirlwind is an
-important contribution. Perhaps more discussion of the APIs scrapped could be
-interesting to motivate the current API.
-
-It sounds convincing that Hoopl has been used with success in the development
-of GHC. However, the fact that Hoopl has been used in the development of GHC
-does not fully support the claim made in paper that Hoopl is unusually easy to
-make use of in other compilers. Indeed, the authors state in the discussion
-section that porting Hoopl to other languages without GADTs would be
-troublesome. As for expressibility, it is disturbing to see that computation
-and exploitation of SSA is not supported, for example for optimal [Hack, Goos
-2006] or other register allocation.
-Altogether it seems more reasonable to make the claims of the abstract less
-general and simply say: "Hoopl has been very useful in the development of GHC
-and we believe it to have potential for other compilers as well".
-
-The references to data flow analysis are a bit sketchy. As for textbooks,
-Muchnick is a good choice, though Hecht (1977) could be considered as a
-classic.  A more recent and up-to-date comprehensive survey of data flow
-frameworks is Marlowe and Ryder, Acta Informatica 1990. Data flow analysis as
-model checking has been popularized by Schmidt (1998), but its original
-discoverer Steffen, TACS 1991 (!) -- see also other articles between 1991 and
-1998 by Steffen -- should be given due credit. Key SSA and register allocation
-references, which have been drivers for much of program dependence, control
-flow and data flow analysis and applications also deserve to be mentioned in a
-general tour through the data flow analysis landscape.
-
-
-
-Minor issues:
-
-8. Discussion; 3 line says: "many, many"
-Should simply be "many".
-
-Figure 5. The caption says that the source code shown in this Figure is
-extracted automatically from the code distributed with Hoopl, but not how. It
-would be less confusing for readers if the caption simply said: "extracted
-from the code distributed with Hoopl".
-
-
-
----------------------------- REVIEW 4 -------------------------- PAPER: 6
-TITLE: Hoopl: A Modular, Reusable Library for Dataflow Analysis and
-Transformation
-OVERALL RATING: 2 (accept) 
-REVIEWER'S CONFIDENCE: 1 (low) 
-
-[As Programme Chair of the Haskell Symposium 2010, I intend to write a
-short non-anonymous review myself of every single submission. Please
-consider this as a bonus, in addition to the full anonymous reviews
-that you receive from members of the Programme Committee. -jg]
-
-This is quite a weighty paper on (as the title says) a Haskell library
-for dataflow analyses. I was impressed by the results, and it is
-beautifully written; but I cannot claim to have understood it all (the
-bit that makes most sense to me is the use of GADTs for capturing
-shape invariants, but then I've already heard a talk about that
-aspect).
-
-One trivial comment: I think it's a pity that you don't use the names
-"n" and "x" for ENtry and EXit labels; but I appreciate that you also
-want "n" for "node". The "thanks to Reviewer C" comment is a bit odd;
-presumably this paper has come to HS via ICFP? 
-
-
diff --git a/paper/hsprelude b/paper/hsprelude
deleted file mode 100644 (file)
index d8faa00..0000000
+++ /dev/null
@@ -1,60 +0,0 @@
-Int
-Bool
-String
-!
-$
-&
-*
-+
--
-.
-/
-==
->
->=
-return
-Maybe
-liftM
->>=
->>
-Just
-Nothing
-True
-False
-mapM_
-++
-&&
-uncurry
-curry
-Data.Map
-flip
-const
-last
-head
-tail
-not
-undefined
-id
-foldl
-foldr
-fst
-snd
-map
-take
-drop
-otherwise
-Integer
-Map.insert
-Map.lookup
-Map.empty
-Map.Map
-fmap
-concatMap
-Monad
-=<<
-cycle
-Ord
-&&
->>=
-not
-otherwise
diff --git a/paper/icfp2010response.txt b/paper/icfp2010response.txt
deleted file mode 100644 (file)
index 8ca96b2..0000000
+++ /dev/null
@@ -1,70 +0,0 @@
-Thank you for the measured, thoughtful reviews.  Thank you also for
-the helpful pointers to related work.
-
-We agree with your assessments and have identified no obvious
-misunderstandings: our paper tries to show how to implement a
-sophisticated optimization engine in a principled way.  We address your
-concerns below; please don't feel that you must read all the details.
-
------------------------------------------------------------------
-
-We're red-faced about the overenthusiastic tone of the paper.  
-A revised version will adopt a more suitable tone.
-
-Regarding performance, we have only very rough data.  Using our ideas
-in an eager language (Objective Caml) resulted in a slight performance
-*improvement*, as documented in our 2005 paper.  The version of GHC
-with our code runs roughly 15% slower than the version without, but
-this version of GHC includes wholesale changes to the back end, and we
-don't know what portion of the slowdown can be attributed to the
-optimizer.  In short, we think it unlikely that we are taking a "big hit."
-
-Regarding edges, we must have misstated something: the term 'edges' is
-intended to refer to a relation between nodes, not just between
-blocks.  We fear we've misled you by our use of the word 'Edges' to
-describe a type class; a better name might be 'NonLocal', as the
-operations of this class gather the information needed to understand
-how control flows between basic blocks.
-
-A function call is indeed represented as an open/closed call node with
-a closed/open return continuation.  Multiple calls may share a return
-continuation, and one of the optimizations we've implemented in GHC
-arranges for call sites to share return continuations when possible.
-
-Regarding use cases, we do support other control-flow algorithms; for
-example, we use Hoopl to compute dominators by a purely functional
-variant of the algorithm of Cooper, Harvey, and Kennedy (2001).
-We have also implemented a small suite of pure control-flow
-optimizations that that do not use any dataflow analysis, such as the
-elimination of branches to branches.  We have not contemplated trying
-to extend Hoopl to establish or maintain SSA invariants.
-
-As noted by Referee D, soundness is not at all obvious, and it is
-definitely relative to the soundness of the transfer functions.  
-We don't prove soundness; instead, we appeal to the proof provided by
-Lerner, Grove, and Chambers (2002).  We'll try to make this appeal
-clearer.
-
-In Section 4.8, column 1, after each iteration we throw away the
-rewritten graph but we keep the improved FactBase.  When the FactBase
-stops improving, we have reached a fixed point, at which stage we keep
-*both* the improved FactBase *and* the rewritten graph.  Our use of
-the term "virgin" to describe the original graph is gratuitous and
-without meaning; we'll remove it.
-
-Your point about GADTs and their utility is well taken: from the
-client's point of view, we could do almost as well with phantom types.
-The major exception is that without GADTs, a client would have to
-provide smart constructors for nodes: the client must ensure that each
-time a node is created with a particular value constructor, it always
-gets the same phantom type.
-
-The definition of 'rewriteE' appears in a 'where' clause in Figure 5
-on page 7.
-
-Expansion-Passing Style does indeed look related to our rewrite
-functions that return rewrite functions, but they are not identical.
-To elucidate that relationship, we will have to dig deeper.
-
-We'll improve the tone of section 5---but we would welcome your joint
-opinion about whether condensing that section would make the paper better.
diff --git a/paper/icfp2010reviews.html b/paper/icfp2010reviews.html
deleted file mode 100644 (file)
index 28ccbbc..0000000
+++ /dev/null
@@ -1,424 +0,0 @@
-<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
-<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
-<head>
-<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
-<meta http-equiv="Content-Style-Type" content="text/css" />
-<meta http-equiv="Content-Script-Type" content="text/javascript" />
-<link rel='stylesheet' type='text/css' href="cacheable.php?file=style.css&amp;mtime=1268319418" />
-<title>Paper #69 - ICFP 2010</title>
-</head><body id='paper_view' onload='hotcrpLoad(1274717974, 240, 0)'>
-<div id='header'>
-  <div id='header_left_conf'><h1><a class='x' href='index.php' title='Home'>ICFP 2010</a></h1></div><div id='header_left_page'><h1>Paper #69</h1></div><div id='header_right'><strong>nr@cs.tufts.edu</strong> <span class='barsep'>&nbsp;|&nbsp;</span> <a href='help.php'>Help</a> <span class='barsep'>&nbsp;|&nbsp;</span> <a href='index.php?signout=1'>Sign&nbsp;out</a> <span class='barsep'>&nbsp;|&nbsp;</span> Monday 24 May 2010 12:19:34pm EDT<br /><span id='usertime'></span></div>
-  <div class='clear'></div>
-<div class='nvbar'><table class='vbar'><tr><td class='spanner'></td>
-  <td class='listlinks nowrap'><a href="review.php?p=7&amp;ls=3"><img src='images/_.gif' alt="&lt;-" class="prev" />#7</a></td>
-  <td class='gopaper nowrap'><form class='gopaper' action='paper.php' method='get' accept-charset='UTF-8'><div class='inform'><input class='textlite' type='text' size='10' name='p' title='Enter paper numbers or search terms' /><input type='hidden' name='ls' value='3' />&nbsp; <input class='b' type='submit' value='Search' /></div></form></td>
-</tr></table></div></div><div class='body'>
-<table class='pbox'><tr>
-    <td colspan='3' class='pboxt'><div class='psmodec'><div class='psmode'><div class='papmodex'><a href='paper.php?p=69&amp;ls=3'><img src='images/view18.png' alt="[Main]" class="b" /></a>&nbsp;<a href='paper.php?p=69&amp;ls=3'>Main</a></div>
-<div class='papmode'><a href='paper.php?p=69&amp;m=pe&amp;ls=3'><img src='images/edit18.png' alt="[Edit]" class="b" /></a>&nbsp;<a href='paper.php?p=69&amp;m=pe&amp;ls=3'>Edit</a></div>
-<div class='clear'></div></div></div></td>
-</tr>
-<tr>
-    <td class='pboxi'><div class='papnum'><h2><a href='paper.php?p=69&amp;ls=3' class='q'>#69</a></h2></div>    <div class='papstripc'><div class='papstrip'>
-<form id='watchform' class='fold7o' action="comment.php?p=69&amp;post=1&amp;ls=3" method='post' enctype='multipart/form-data' accept-charset='UTF-8' onsubmit='return Miniajax.submit("watchform")'><div class='inform'><input type='hidden' name='setwatch' value='1' /><div class='pst'><span class='psfn'><input type="checkbox" class="cb" id="taggctl1" name="watch" value="2" checked="checked" onchange="Miniajax.submit('watchform')" />&nbsp;<label for="taggctl1">Comment notification</label></span><div class='clear'></div></div><div class='pshint'>If selected, you will receive email when updated comments are available for this paper. <span id='watchformresult'></span></div><div class='papv'><input class='b fx7' type='submit' value='Save' /></div></div></form>
-
-<div class='pst'><span class='psfn'>PC conflicts</span><div class='clear'></div></div><div class='psv'><span class='autblentry'>Simon Peyton Jones</span> <span class='autblentry'>Stephanie Weirich</span> </div>
-</div></div></td>
-    <td class='pboxt'><table class='papc'>
-       <tr><td class='papculs'></td><td></td><td class='papcur'></td></tr>
-       <tr><td></td><td><h2><a href='paper.php?p=69&amp;ls=3' class='q'>Hoopl: A Modular, Reusable Library for Dataflow Analysis and Transformation</a></h2></td><td></td></tr>
-    </table></td>
-    <td class='pboxj'></td>
-</tr><tr>
-    <td class='pboxl'></td>
-    <td class='pboxr'><table class='papc'>
-       <tr><td class='papcl'><img src='images/_.gif' alt="" class="_" /></td><td class='papct'><div class='inpapct'><div id='foldpaper' class='fold8c fold9c fold6c fold5c'><table class='paptab'><tr><td class='papbe' colspan='3'><table><tr><td class='nowrap'><span class='pstat pstat_sub'>Submitted</span></td><td class='nowrap'><a href="doc.php/icfp2010-paper69.pdf" class='q nowrap'><img src='images/pdf24.png' alt="[PDF]" class="dlimg" />&nbsp;<span class='dlsize'>238kB</span></a></td><td><span class='sep'></span></td><td><span class='hint'><span class='nowrap' title='Time of most recent update'><img src='images/_.gif' alt="Updated" title="Time of most recent update" class="timestamp12" /> Friday 2 Apr 2010 10:24:41am EDT</span> &nbsp;<span class='barsep'>|</span>&nbsp; <span class='nowrap' title='SHA-1 checksum'><img src='images/_.gif' alt="SHA-1" title="SHA-1 checksum" class="checksum12" /> 4e8df6a07b4c698ac20a073bf2a3decf1de2467c</span></span></td></tr></table><div class='g'></div>
-You are an <span class='author'>author</span> of this paper.</td></tr>
-       <tr><td class='paple'><div class='papt'><span class='papfn'><a class='q fn6' href="/paper.php?p=69&amp;pfold=6o&amp;ls=3" onclick='return fold("paper", 0, 6)' title="Show full abstract">+&nbsp;Abstract</a><a class='q fx6' href="/paper.php?p=69&amp;pfold=6c&amp;ls=3" onclick='return fold("paper", 1, 6)' title="Abbreviate abstract">&minus;&nbsp;Abstract</a><img id='foldsession.paper6' alt='' src='sessionvar.php?var=foldpaperb&amp;val=1&amp;cache=1' width='1' height='1' /></span><div class='clear'></div></div><div class='papv abstract'><span class='fn6'>Dataflow analysis and transformation of control-flow graphs is\r
-pervasive in optimizing compilers, but it is typically tightly\r
-interwoven with the details of a particular  <a class='fn6' href='javascript:void fold("paper", 0, 6)'>[more]</a></span><span class='fx6'>Dataflow analysis and transformation of control-flow graphs is\r
-pervasive in optimizing compilers, but it is typically tightly\r
-interwoven with the details of a particular compiler.  We describe\r
-Hoopl, a reusable Haskell library that makes it unusually easy \r
-to define new analyses and transformations for *any* compiler.  Hoopl's\r
-interface is modular and polymorphic, and it offers unusually strong\r
-static guarantees.  The implementation is also far from routine: it\r
-encapsulates state-of-the-art algorithms (interleaved analysis and\r
-rewriting, dynamic error isolation), and it cleanly separates their\r
-tricky elements so that they can be understood independently.</span></div>
-
-</td><td class='papce'></td><td class='papre'><div class='papt'><span class='papfn'><a class='q fn9' href="/paper.php?p=69&amp;pfold=9o&amp;ls=3" onclick='return fold("paper", 0, 9)' title="Show full authors">+&nbsp;Authors</a><a class='q fx9' href="/paper.php?p=69&amp;pfold=9c&amp;ls=3" onclick='return fold("paper", 1, 9)' title="Show abbreviated authors">&minus;&nbsp;Authors</a><img id='foldsession.paper9' alt='' src='sessionvar.php?var=foldpaperp&amp;val=1&amp;cache=1' width='1' height='1' /></span><div class='clear'></div></div><div class='papv'><span class='fn9'>N. Ramsey, J. Dias, S. Jones <a class='fn9' href='javascript:void fold("paper", 0, 9)'>[details]</a></span><span class='fx9'>Norman Ramsey (Tufts University) &lt;<a href="mailto:nr@cs.tufts.edu">nr@cs.tufts.edu</a>&gt;<br />
-João Dias (Tufts University) &lt;<a href="mailto:dias@cs.tufts.edu">dias@cs.tufts.edu</a>&gt;<br />
-Simon Peyton Jones (Microsoft Research) &lt;<a href="mailto:simonpj@microsoft.com">simonpj@microsoft.com</a>&gt;</span></div>
-
-<div class='papt'><span class='papfn'><a class='q fn5' href="/paper.php?p=69&amp;pfold=5o&amp;ls=3" onclick='return fold("paper", 0, 5)' title="Show topics, documents, and options">+&nbsp;Topics, Documents, and Options</a><a class='q fx5' href="/paper.php?p=69&amp;pfold=5c&amp;ls=3" onclick='return fold("paper", 1, 5)' title="Hide topics, documents, and options">&minus;&nbsp;Topics</a><img id='foldsession.paper5' alt='' src='sessionvar.php?var=foldpapert&amp;val=1&amp;cache=1' width='1' height='1' /></span><div class='clear'></div></div><div class='papv fn5'></div><div class='papv fx5'><span class='topic1'>compilation</span> <span class='sep'></span> <span class='topic1'>components and composition</span></div>
-
-<div class='papt fx5'><span class='papfn'>Documents and Options</span><div class='clear'></div></div><div class='papv fx5'>Submission category: Functional pearl<br />
-<a href="doc.php/icfp2010-supplementary-material69.pdf"><img src='images/pdf.png' alt="[PDF]" class="sdlimg" />&nbsp;Supplementary material</a><br />
-</div>
-
-</td></tr></table></div></div></td><td class='papcr'><img src='images/_.gif' alt="" class="_" /></td></tr>
-       <tr><td colspan='3' class='papsep'></td></tr>
-       <tr><td></td><td class='papcc'><table class='reviewers'>
-    <tr><td class='empty' colspan='2'></td><th><span class='hastitle' title="Overall merit">OveMer</span></th><th><span class='hastitle' title="Expertise">Exp</span></th></tr>
-    <tr><td><a href='#review69A'>Review&nbsp;#69A</a></td><td class='empty'></td><td class='revscore rs_overAllMerit'>B</td><td class='revscore rs_reviewerQualification'>Y</td><td></td></tr>
-    <tr><td><a href='#review69B'>Review&nbsp;#69B</a></td><td class='empty'></td><td class='revscore rs_overAllMerit'>A</td><td class='revscore rs_reviewerQualification'>Y</td><td></td></tr>
-    <tr><td><a href='#review69C'>Review&nbsp;#69C</a></td><td class='empty'></td><td class='revscore rs_overAllMerit'>A</td><td class='revscore rs_reviewerQualification'>X</td><td></td></tr>
-    <tr><td><a href='#review69D'>Review&nbsp;#69D</a></td><td class='empty'></td><td class='revscore rs_overAllMerit'>C</td><td class='revscore rs_reviewerQualification'>Y</td><td></td></tr>
-  </table>
-<a href='paper.php?p=69&amp;m=pe&amp;ls=3'><img src='images/edit24.png' alt="[Edit paper]" class="dlimg" /></a>&nbsp;<a href='paper.php?p=69&amp;m=pe&amp;ls=3'><strong>Edit paper</strong></a> <span class='barsep'>&nbsp;|&nbsp;</span> <a href="#response"><img src='images/comment24.png' alt="[Add response]" class="dlimg" /></a>&nbsp;<a href="#response"><strong>Add response</strong></a></td><td></td></tr>
-       <tr><td class='papcll'></td><td></td><td class='papclr'></td></tr>
-</table></td></tr></table>
-<div class='relative'><table class='pbox'><tr><td class='pboxl'></td><td class='pboxr'><a href='review.php?p=69&amp;m=r&amp;text=1&amp;ls=3'><img src='images/txt24.png' alt="[Text]" class="dlimg" /></a>&nbsp;<a href='review.php?p=69&amp;m=r&amp;text=1&amp;ls=3'>Reviews and comments in plain text</a></td></tr></table></div>
-<div class='relative'><table class='pbox'><tr>
-  <td class='pboxl'></td>
-  <td class='pboxr'><table class='revc'>
-       <tr><td class='revcul'></td><td></td><td class='revcur'></td></tr>
-       <tr><td></td><td class='revhead'><div class='floatright'><a href='review.php?r=69A&amp;text=1&amp;ls=3'><img src='images/txt.png' alt="[Text]" class="b" /></a>&nbsp;<a href='review.php?r=69A&amp;text=1&amp;ls=3'>Plain text</a></div><h3><a href='review.php?r=69A&amp;ls=3' name='review69A' class='u'>Review&nbsp;#69A</a></h3>
- <span class='revinfo'>Modified Tuesday 18 May 2010 8:33:53am EDT</span>
-<div class='clear'></div></td><td></td></tr>
-  <tr><td></td><td class='revct'><div class='inrevct'><table class='revtab'>
-<tr>
-  <td class='reve rev_overAllMerit revle'><div class='revt'><span class='revfn'>Overall&nbsp;merit <a class='scorehelp' href='scorehelp.php?f=overAllMerit'>(?)</a></span><div class='clear'></div></div>
-<div class='revv'><span class='rev_overAllMerit_B'><span class='rev_num rev_num_B'>B.</span> OK paper, but I will not champion it.</span></div></td>
-  <td class='revce'></td>
-  <td class='reve rev_reviewerQualification revre'><div class='revt'><span class='revfn'>Expertise <a class='scorehelp' href='scorehelp.php?f=reviewerQualification'>(?)</a></span><div class='clear'></div></div>
-<div class='revv'><span class='rev_reviewerQualification_Y'><span class='rev_num rev_num_Y'>Y.</span> I am knowledgeable in the area, though not an expert.</span></div></td>
-</tr>
-
-<tr>
-  <td class='reve rev_paperSummary revbe' colspan='3'><div class='revt'><span class='revfn'>Paper&nbsp;summary</span><div class='clear'></div></div>
-<div class='revv'>Describes the design, interface and implementation of a generic library for dataflow analyses and transformations.  The approach followed is Lerner, Grove and Chambers's &quot;analyze and (simultaneously) transform&quot; rather than the more traditional &quot;analyze then transform&quot;.  GADTs and type families are used in a couple of places to statically enforce some well-formedness properties on control-flow graphs (e.g. maintain a distinction between nodes that start a block, end a block, or are in the middle of a block).<br />
-<br />
-</div></td>
-</tr>
-
-<tr>
-  <td class='reve rev_strengthOfPaper revbe' colspan='3'><div class='revt'><span class='revfn'>Paper strengths and weaknesses</span><div class='clear'></div></div>
-<div class='revv'>+ Very solid engineering.\r<br />
-+ Good writing for such a technical topic\r<br />
-- The examples don't demonstrate the full power of the Lerner-Grove-Chambers approach (composition of analyses)\r<br />
-- As a research paper: no breakthrough, conceptual advances are small.\r<br />
-- As a functional pearl: not really entertaining, reads too much like documentation for a library.<br />
-<br />
-</div></td>
-</tr>
-
-<tr>
-  <td class='reve rev_commentsToAuthor revbe' colspan='3'><div class='revt'><span class='revfn'>Comments for author</span><div class='clear'></div></div>
-<div class='revv'>This is a nice, well-engineered implementation of the &quot;analyze and transform&quot; approach of Lerner et al.\r<br />
-\r<br />
-As a research paper, it is very short on conceptual advances, though.  The use of GADTs and type families to enforce shape properties on CFGs is cute but not very deep.  Everything else is known already, although the paper does a good job of connecting the pieces of knowledge together.\r<br />
-\r<br />
-As a programming pearl, I'm afraid it fails the Bird-Gibbons test (http://www.comlab.ox.ac.uk/people/Jeremy.Gibbons/pearls/):\r<br />
-\r<br />
-&quot;Bird characterizes them as &quot;polished, elegant, instructive, entertaining&quot;. [...] Think more along the lines of short stories --- 6 to 10 pages, brisk, engaging, accessible, surprising.&quot;\r<br />
-\r<br />
-Polished and instructive it is; elegant and accessible, to some extent; but entertaining, brisk, engaging and surprising, no.\r<br />
-\r<br />
-I was disappointed by the very short treatment of compositionality (section 4.5).  The ability to compose analyses is the major innovation of Lerner et al's paper.  For a single analysis followed by a single transformation, their approach simplifies a bit the transfer function (as explained well in the paper), but doesn't improve the precision of the analysis.  Where Lerner et al really shine is the ability to combine multiple analyses and transformations.  I really missed an example of such a combination in the paper, and was disappointed to see the &quot;thenFwd&quot; combinator on page 7 left as an exercise for the reader.  There is also the question of combining forward and backward analyses that is left open in Lerner et al's paper (as far as I can remember) and would definitely deserve a second look.\r<br />
-\r<br />
-Page 11: CIL is not &quot;analysis-only&quot;.  It provides about as many (or as few?) facilities for code rewriting than for code analysis.  The comment about the API being complicated (in both cases) is correct, though.\r<br />
-\r<br />
-The paper is generally well written but is somewhat repetitive in emphasizing how hard the authors worked and how nice the resulting API is.  I'm not sure all of the following sentences have their place in a scientific paper (some of them perhaps, but all of them is a bit too much):\r<br />
-\r<br />
-&quot;... an idea that is elegantly captured by the FwdRes type...&quot;\r<br />
-&quot;What a beautiful type thenFwrdRw has!&quot;\r<br />
-&quot;We have spent six years implementing...&quot;\r<br />
-&quot;This formidable design problem...&quot;\r<br />
-&quot;...have been through dozens of revisions&quot;\r<br />
-&quot;We are proud of using GADTs to track...&quot;<br />
-<br />
-</div></td>
-</tr>
-</table>
-</div></td><td></td></tr>
-       <tr><td class='revcll'></td><td></td><td class='revclr'></td></tr>
-</table></td></tr>
-</table></div>
-
-<div class='relative'><table class='pbox'><tr>
-  <td class='pboxl'></td>
-  <td class='pboxr'><table class='revc'>
-       <tr><td class='revcul'></td><td></td><td class='revcur'></td></tr>
-       <tr><td></td><td class='revhead'><div class='floatright'><a href='review.php?r=69B&amp;text=1&amp;ls=3'><img src='images/txt.png' alt="[Text]" class="b" /></a>&nbsp;<a href='review.php?r=69B&amp;text=1&amp;ls=3'>Plain text</a></div><h3><a href='review.php?r=69B&amp;ls=3' name='review69B' class='u'>Review&nbsp;#69B</a></h3>
- <span class='revinfo'>Modified Wednesday 19 May 2010 8:22:31am EDT</span>
-<div class='clear'></div></td><td></td></tr>
-  <tr><td></td><td class='revct'><div class='inrevct'><table class='revtab'>
-<tr>
-  <td class='reve rev_overAllMerit revle'><div class='revt'><span class='revfn'>Overall&nbsp;merit <a class='scorehelp' href='scorehelp.php?f=overAllMerit'>(?)</a></span><div class='clear'></div></div>
-<div class='revv'><span class='rev_overAllMerit_A'><span class='rev_num rev_num_A'>A.</span> Good paper. I will champion it at the PC meeting.</span></div></td>
-  <td class='revce'></td>
-  <td class='reve rev_reviewerQualification revre'><div class='revt'><span class='revfn'>Expertise <a class='scorehelp' href='scorehelp.php?f=reviewerQualification'>(?)</a></span><div class='clear'></div></div>
-<div class='revv'><span class='rev_reviewerQualification_Y'><span class='rev_num rev_num_Y'>Y.</span> I am knowledgeable in the area, though not an expert.</span></div></td>
-</tr>
-
-<tr>
-  <td class='reve rev_paperSummary revbe' colspan='3'><div class='revt'><span class='revfn'>Paper&nbsp;summary</span><div class='clear'></div></div>
-<div class='revv'>The paper presents Hoopl, a Haskell framework for implementing\r<br />
-dataflow analyses and compiler optimizations. Hoopl implements the\r<br />
-ideas first presented by Lerner, Grove, and Chambers in their POPL\r<br />
-2002 paper. The paper presents Hoopl, shows how to use it practically on\r<br />
-one example (constant folding), and sketches its implementation.<br />
-<br />
-</div></td>
-</tr>
-
-<tr>
-  <td class='reve rev_strengthOfPaper revbe' colspan='3'><div class='revt'><span class='revfn'>Paper strengths and weaknesses</span><div class='clear'></div></div>
-<div class='revv'>+ nicely written\r<br />
-\r<br />
-+ good and convincing illustration of the Haskell type machinery\r<br />
-\r<br />
-+ inspiring paper on compilers architecture\r<br />
-\r<br />
-- merely a packaging of already published ideas<br />
-<br />
-</div></td>
-</tr>
-
-<tr>
-  <td class='reve rev_commentsToAuthor revbe' colspan='3'><div class='revt'><span class='revfn'>Comments for author</span><div class='clear'></div></div>
-<div class='revv'>Section 4.5 vaguely remembers me Expansion Passing Style by Dybvig,\r<br />
-Friedman and Haynes. Don't you think EPS is related to your rewrite\r<br />
-functions that return rewrite functions?\r<br />
-\r<br />
-Page 7, why no giving definition of rewriteE?\r<br />
-\r<br />
-Page 8, section 4.7. This section is not very convincing. It is not \r<br />
-technically very deep and I have mostly read it as a disrupting digression.\r<br />
-Toward the conclusion, you state that using the fuel monad was one of\r<br />
-your three goals. If, indeed, you consider using the fuel monad that\r<br />
-important, then I think you should emphasize it all along the paper.\r<br />
-\r<br />
-Section 5. This section is really for Haskell aficionados. I understand why\r<br />
-it is there and I thank you for not making it too long but I still don't\r<br />
-like it very much. It reads too much as a self contentment Section.<br />
-<br />
-</div></td>
-</tr>
-</table>
-</div></td><td></td></tr>
-       <tr><td class='revcll'></td><td></td><td class='revclr'></td></tr>
-</table></td></tr>
-</table></div>
-
-<div class='relative'><table class='pbox'><tr>
-  <td class='pboxl'></td>
-  <td class='pboxr'><table class='revc'>
-       <tr><td class='revcul'></td><td></td><td class='revcur'></td></tr>
-       <tr><td></td><td class='revhead'><div class='floatright'><a href='review.php?r=69C&amp;text=1&amp;ls=3'><img src='images/txt.png' alt="[Text]" class="b" /></a>&nbsp;<a href='review.php?r=69C&amp;text=1&amp;ls=3'>Plain text</a></div><h3><a href='review.php?r=69C&amp;ls=3' name='review69C' class='u'>Review&nbsp;#69C</a></h3>
- <span class='revinfo'>Modified Friday 21 May 2010 10:52:35am EDT</span>
-<div class='clear'></div></td><td></td></tr>
-  <tr><td></td><td class='revct'><div class='inrevct'><table class='revtab'>
-<tr>
-  <td class='reve rev_overAllMerit revle'><div class='revt'><span class='revfn'>Overall&nbsp;merit <a class='scorehelp' href='scorehelp.php?f=overAllMerit'>(?)</a></span><div class='clear'></div></div>
-<div class='revv'><span class='rev_overAllMerit_A'><span class='rev_num rev_num_A'>A.</span> Good paper. I will champion it at the PC meeting.</span></div></td>
-  <td class='revce'></td>
-  <td class='reve rev_reviewerQualification revre'><div class='revt'><span class='revfn'>Expertise <a class='scorehelp' href='scorehelp.php?f=reviewerQualification'>(?)</a></span><div class='clear'></div></div>
-<div class='revv'><span class='rev_reviewerQualification_X'><span class='rev_num rev_num_X'>X.</span> I am an expert in the subject area of this paper.</span></div></td>
-</tr>
-
-<tr>
-  <td class='reve rev_paperSummary revbe' colspan='3'><div class='revt'><span class='revfn'>Paper&nbsp;summary</span><div class='clear'></div></div>
-<div class='revv'>This paper describes a dataflow analysis and transformation framework\r<br />
-written in Haskell.  A client of this library provides the representation\r<br />
-of nodes (i.e., instructions), data-flow facts, and transformations,\r<br />
-and the library provides the analysis and transformations.  Hoopl makes\r<br />
-heavy use of advanced Haskell type-system features (GADTs, etc.) to\r<br />
-enforce static correctness.<br />
-<br />
-</div></td>
-</tr>
-
-<tr>
-  <td class='reve rev_strengthOfPaper revbe' colspan='3'><div class='revt'><span class='revfn'>Paper strengths and weaknesses</span><div class='clear'></div></div>
-<div class='revv'>Pros:\r<br />
-\r<br />
-While it does not introduce a new analysis algorithm or transformation, this\r<br />
-work bridges the gap between the theoretical presentations and actual compilers.\r<br />
-\r<br />
-Demonstrates the utility of functional programming for algorithms on\r<br />
-control-flow graphs, which are an aspect of compilers that was _not_ obviously\r<br />
-suited to functional programming languages.\r<br />
-\r<br />
-One might argue that the paper does not introduce any new analyses or optimizations,\r<br />
-but I think that problem of how to actually build such applications is important\r<br />
-and this paper does a very good job of addressing that topic in a principled way.\r<br />
-\r<br />
-Cons:\r<br />
-\r<br />
-Some minor quibbles described below.<br />
-<br />
-</div></td>
-</tr>
-
-<tr>
-  <td class='reve rev_commentsToAuthor revbe' colspan='3'><div class='revt'><span class='revfn'>Comments for author</span><div class='clear'></div></div>
-<div class='revv'>On page 4, the claim that middle nodes cannot refer to labels is not\r<br />
-really true (e.g., LoadAddress); what you mean is that middle nodes\r<br />
-do not use labels for their control flow.\r<br />
-\r<br />
-In footnote 4, you say that program points correspond to edges, but edges\r<br />
-only occur between blocks and not between nodes.  Surely nodes are program\r<br />
-points too?\r<br />
-\r<br />
-The mkIfThenElse function in Figure 4 looks like it has a type error:\r<br />
-t and e are AGraphs, but gCat is defined to work on Graphs.\r<br />
-\r<br />
-How do you expect function calls to be treated?  Would then be open/closed\r<br />
-nodes with a closed/open return node?\r<br />
-\r<br />
-I would like to see a bit more discussion about use cases.  For example,\r<br />
-would you use it on an SSA representation?  Do you support other control-flow\r<br />
-algorithms, such as determining dominators?\r<br />
-\r<br />
-You do not mention the MLRisc library, but it also supports some higher-order\r<br />
-programming of optimizations (mostly through the heavy use of functors).\r<br />
-I don't think that there was ever a write up of this, other than the\r<br />
-documentation\r<br />
-\r<br />
-&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;http://www.cs.nyu.edu/leunga/www/MLRISC/Doc/html/index.html\r<br />
-\r<br />
-One issue that is not addressed is how fast/slow are the resulting optimization\r<br />
-passes?  Do you take a big hit because of the abstractions?\r<br />
-\r<br />
-Another piece of related work that is missing is Lee and Colby's implementation\r<br />
-of Parameterized Partial Evaluation using SML functors (the idea is based\r<br />
-on Consel's Parameterized Partial).  It is similar in that the client\r<br />
-supplies an abstract domain and operators and the library takes care of the\r<br />
-rest.  It also supports combining analyses and transformations automatically.<br />
-<br />
-</div></td>
-</tr>
-</table>
-</div></td><td></td></tr>
-       <tr><td class='revcll'></td><td></td><td class='revclr'></td></tr>
-</table></td></tr>
-</table></div>
-
-<div class='relative'><table class='pbox'><tr>
-  <td class='pboxl'></td>
-  <td class='pboxr'><table class='revc'>
-       <tr><td class='revcul'></td><td></td><td class='revcur'></td></tr>
-       <tr><td></td><td class='revhead'><div class='floatright'><a href='review.php?r=69D&amp;text=1&amp;ls=3'><img src='images/txt.png' alt="[Text]" class="b" /></a>&nbsp;<a href='review.php?r=69D&amp;text=1&amp;ls=3'>Plain text</a></div><h3><a href='review.php?r=69D&amp;ls=3' name='review69D' class='u'>Review&nbsp;#69D</a></h3>
- <span class='revinfo'>Modified Friday 21 May 2010 12:18:00pm EDT</span>
-<div class='clear'></div></td><td></td></tr>
-  <tr><td></td><td class='revct'><div class='inrevct'><table class='revtab'>
-<tr>
-  <td class='reve rev_overAllMerit revle'><div class='revt'><span class='revfn'>Overall&nbsp;merit <a class='scorehelp' href='scorehelp.php?f=overAllMerit'>(?)</a></span><div class='clear'></div></div>
-<div class='revv'><span class='rev_overAllMerit_C'><span class='rev_num rev_num_C'>C.</span> Weak paper, though I will not fight strongly against it.</span></div></td>
-  <td class='revce'></td>
-  <td class='reve rev_reviewerQualification revre'><div class='revt'><span class='revfn'>Expertise <a class='scorehelp' href='scorehelp.php?f=reviewerQualification'>(?)</a></span><div class='clear'></div></div>
-<div class='revv'><span class='rev_reviewerQualification_Y'><span class='rev_num rev_num_Y'>Y.</span> I am knowledgeable in the area, though not an expert.</span></div></td>
-</tr>
-
-<tr>
-  <td class='reve rev_paperSummary revbe' colspan='3'><div class='revt'><span class='revfn'>Paper&nbsp;summary</span><div class='clear'></div></div>
-<div class='revv'>The paper descripes Hoopl, a library for dataflow analysis mixed with\r<br />
-transformations.  Hoopl is implemented in Haskell in a purely functional\r<br />
-way, using GADT to enforce invariants on internal data structures.<br />
-<br />
-</div></td>
-</tr>
-
-<tr>
-  <td class='reve rev_strengthOfPaper revbe' colspan='3'><div class='revt'><span class='revfn'>Paper strengths and weaknesses</span><div class='clear'></div></div>
-<div class='revv'>Strengths:\r<br />
-\r<br />
-&nbsp;- Having this code exported as a library rather than keeping it internal to\r<br />
-&nbsp;&nbsp;&nbsp;the GHC compiler is useful for others.  \r<br />
-\r<br />
-&nbsp;- This paper may serve as a reference for people using the library or for\r<br />
-&nbsp;&nbsp;&nbsp;other people implementing a similar library in other languages. \r<br />
-\r<br />
-Weaknesses: \r<br />
-\r<br />
-&nbsp;- This remains the description of code, without much algorithmic novelty,\r<br />
-&nbsp;&nbsp;&nbsp;and however useful the work and smart the implementation are, this remains\r<br />
-&nbsp;&nbsp;&nbsp;a kind of boring paper to read.  (Despite the constant efforts of the\r<br />
-&nbsp;&nbsp;&nbsp;authors to transmit their enthusiasm to the reader.)\r<br />
-\r<br />
-&nbsp;- One originality of the library compared to other existing implementations\r<br />
-&nbsp;&nbsp;&nbsp;of similar libraries is that it is purely functional.  This is presented\r<br />
-&nbsp;&nbsp;&nbsp;as a great advantage for the design and I can believe it.  Still, it\r<br />
-&nbsp;&nbsp;&nbsp;would have been interesting to have a discussion and some figures about\r<br />
-&nbsp;&nbsp;&nbsp;the efficiency of the implementation, to convince us that this is not\r<br />
-&nbsp;&nbsp;&nbsp;simultaneously a dropback.<br />
-<br />
-</div></td>
-</tr>
-
-<tr>
-  <td class='reve rev_commentsToAuthor revbe' colspan='3'><div class='revt'><span class='revfn'>Comments for author</span><div class='clear'></div></div>
-<div class='revv'>- Section 3.3, col 1, last sentence: &quot;Using GADTs to enforce...&quot;  Since you\r<br />
-&nbsp;&nbsp;given an interface in a library, you could use smart constructors and\r<br />
-&nbsp;&nbsp;phantom types to enfore the invariants from the client's point of view,\r<br />
-&nbsp;&nbsp;i.e. to force the client to write only meaningful graphs. The GADTs helps\r<br />
-&nbsp;&nbsp;you &quot;take advantage&quot; of these invariants knowing that other cases cannot\r<br />
-&nbsp;&nbsp;occur.\r<br />
-\r<br />
-&nbsp;&nbsp;My impression is that (here and below) you are slightly exagerating the\r<br />
-&nbsp;&nbsp;importance of GADTs---form the clients point of view.  \r<br />
-&nbsp;\r<br />
-- Section 4.8: col 1, last two items: I do not understand what you mean\r<br />
-&nbsp;&nbsp;here.  It seems that you throw away the transformation at each\r<br />
-&nbsp;&nbsp;iteration, so what would be the point of iterating?  Please detail.\r<br />
-&nbsp;&nbsp;You call the original graph &quot;virgin&quot;. In what sense? Since you transform\r<br />
-&nbsp;&nbsp;graphs rather than annotate them, each graph should have the same status as\r<br />
-&nbsp;&nbsp;another. \r<br />
-\r<br />
-- Section 4, last item: &quot;The algorithm is sound&quot;.  Is it so obvious? Can the\r<br />
-&nbsp;&nbsp;transfer function be wrong, e.g. say that nothing never flows out of\r<br />
-&nbsp;&nbsp;anything and the rewrite eliminated significant stuff because it is not\r<br />
-&nbsp;&nbsp;assume to flow in (this rewrite is sound) so that the resulting\r<br />
-&nbsp;&nbsp;transformation is wrong?  You should assume some form of soundness for the\r<br />
-&nbsp;&nbsp;transfer function as well. \r<br />
-\r<br />
-- Section 5, one before last paragraph: &quot;clever trick&quot;.  This seems a rather\r<br />
-&nbsp;&nbsp;obvious thing to do, not even a trick...<br />
-<br />
-</div></td>
-</tr>
-</table>
-</div></td><td></td></tr>
-       <tr><td class='revcll'></td><td></td><td class='revclr'></td></tr>
-</table></td></tr>
-</table></div>
-
-<form action='comment.php?p=69&amp;ls=3&amp;response=1&amp;post=1' method='post' enctype='multipart/form-data' accept-charset='UTF-8'><div class='aahc'>
-<table class='pbox'>
-<tr>
-  <td class='pboxl'></td>
-  <td class='pboxr'><table class='cmtc response'>
-       <tr><td class='cmtcul'></td><td></td><td class='cmtcur'></td></tr>
-       <tr><td></td><td class='cmthead'><h3 id='response'>Response</h3><span class='cmtfn'></span><div class='clear'></div><div class='hint'>The authors' response is intended to address
-reviewer concerns and correct misunderstandings.
-The response should be addressed to the program committee, who
-will consider it when making their decision.  Don't try to
-augment the paper's content or form&mdash;the conference deadline
-has passed.  Please keep the response short and to the point.</div>
-</td><td></td></tr>
-  <tr><td></td><td class='cmtcc'><textarea name='comment' class='reviewtext' rows='10' cols='60' onchange='hiliter(this)'></textarea>
-  <div class='g'></div>
-  <input type="checkbox" class="cb" id="taggctl2" name="forReviewers" value="1" checked="checked" onchange="hiliter(this)" />&nbsp;<label for="taggctl2">This response should be sent to the reviewers.</label>
-<div class='aa'><table class='pt_buttons'>
-    <tr>
-      <td class='ptb_button'><input class='bb' type='submit' value='Save' name='submit' /></td>
-    </tr>
-  </table></div>
-</td><td></td></tr>
-       <tr><td class='cmtcll'></td><td></td><td class='cmtclr'></td></tr>
-</table></td></tr>
-</table>
-</div></form>
-
-</div>
-<div id='footer'>
-  <div id='footer_crp'><a href='http://www.cs.ucla.edu/~kohler/hotcrp/'>HotCRP</a> Conference Management Software<!-- Version 2.38 --></div>
-  <div class='clear'></div></div>
-<script type='text/javascript' src='cacheable.php?file=script.js&amp;mtime=1268319418'></script>
-<!--[if lte IE 6]> <script type='text/javascript' src='cacheable.php?file=supersleight.js'></script> <![endif]-->
-<script type='text/javascript'>Miniajax.onload("watchform");addScoreHelp()</script><div class='scorehelpc' id='scorehelp_overAllMerit'><strong>Overall&nbsp;merit</strong> choices are:<br /><span class='rev_overAllMerit'><span class='rev_num rev_num_A'>A.</span>&nbsp;Good paper. I will champion it at the PC meeting.<br /><span class='rev_num rev_num_B'>B.</span>&nbsp;OK paper, but I will not champion it.<br /><span class='rev_num rev_num_C'>C.</span>&nbsp;Weak paper, though I will not fight strongly against it.<br /><span class='rev_num rev_num_D'>D.</span>&nbsp;Serious problems. I will argue to reject this paper.<br /></span></div><div class='scorehelpc' id='scorehelp_reviewerQualification'><strong>Expertise</strong> choices are:<br /><span class='rev_reviewerQualification'><span class='rev_num rev_num_X'>X.</span>&nbsp;I am an expert in the subject area of this paper.<br /><span class='rev_num rev_num_Y'>Y.</span>&nbsp;I am knowledgeable in the area, though not an expert.<br /><span class='rev_num rev_num_Z'>Z.</span>&nbsp;I am not an expert. My evaluation is that of an informed outsider.<br /></span></div></body>
-</html>
diff --git a/paper/latex.mk b/paper/latex.mk
deleted file mode 100644 (file)
index 1ac6684..0000000
+++ /dev/null
@@ -1,18 +0,0 @@
-LATEX=latex
-DVIPS=dvips
-
-%.dvi:  %.tex
-       $LATEX '\scrollmode \input '"$stem"
-       ltxcount=3
-       while egrep -s 'Rerun (LaTeX|to get cross-references right|to get citations correct)' $stem.log &&
-             [ $ltxcount -gt 0 ]
-       do
-         $LATEX '\scrollmode \input '"$stem"
-         ltxcount=`expr $ltxcount - 1`
-       done
-
-%.ps:  %.dvi
-       $DVIPS -Ppdf -o $target $stem.dvi
-%.pdf: %.dvi
-       $DVIPS -Ppdf -o"| ps2pdf13 - $target" $prereq
-
diff --git a/paper/mkfile b/paper/mkfile
deleted file mode 100644 (file)
index 9ee5672..0000000
+++ /dev/null
@@ -1,82 +0,0 @@
-<./latex.mk
-<./spell.mk
-<./bbl.$USER.mk
-<./bitly.$USER.mk
-
-
-LASTPAGE=13  # final draft has extra page
-
-TGT=dfopt
-
-all:V: $TGT.pdf $TGT.ps hoopl10-supplement.bitly hoopl10.bitly
-old:V: popl-index.bitly
-bib:V: $TGT.bbl
-bibfile:V: $TGT.bib
-dvi:V: $TGT.dvi
-pdf:V: $TGT.pdf
-ps:V: $TGT.ps
-bbl:V: bib
-xdvi:V: $TGT.dvi
-       sht=`xwininfo -root | awk '$1 == "Height:" { print $2 }'`
-       swd=`xwininfo -root | awk '$1 == "Width:"  { print $2 }'`
-    swd=`expr $swd - 120` # more room
-       xdvi -s 5 -geometry =$(expr $swd / 2)x$(expr $sht - 20)+78+2 $prereq
-
-
-tag:VQ: $TGT.tex
-       tag=`$HOME/bin/md5words -trim $prereq | tr -d "'" | tr -cs a-zA-Z0-9 - | sed s/-*$//`
-       echo git tag $tag
-       git tag $tag
-
-dfopt.dvi: dfopt.bbl code.sty timestamp.tex dfoptdu.tex cprop.tex comb1.tex iterf.tex pairf.tex dg.tex cat.tex
-
-dfoptdu.tex: cprop.tex comb1.tex iterf.tex pairf.tex dg.tex node.tex
-
-$TGT.pdf: $TGT.dvi
-       dvips -Ppdf -o"|ps2pdf - $target" -pp 1-$LASTPAGE $prereq
-
-$TGT.ps: $TGT.dvi
-       dvips -Ppdf -o "$target" -pp 1-$LASTPAGE $prereq
-
-$HOME/www/pubs/hoopl10-supplement.pdf: $TGT.dvi
-       dvips -Ppdf -o"|ps2pdf - $target" -pp `expr $LASTPAGE + 1`- $prereq
-
-$HOME/www/pubs/hoopl10.pdf: $TGT.dvi
-       dvips -Ppdf -o"|ps2pdf - $target" $prereq
-
-timestamp.tex: $TGT.tex
-       date=`stat -c "%y" $prereq`
-       signature=""
-       if [ -x $HOME/bin/md5words ]; then
-         words="`md5words -trim $prereq`"
-      signature=" [MD5: \\mbox{$words}]"
-    else
-      words="(could not compute signature words)"
-       fi
-       date -d "$date" "+\def\mdfivestamp{\\rlap{\\textbf{%a %e %b %Y, %l:%M %p$signature}}}\def\mdfivewords{$words}" > $target
-
-
-
-%du.tex:D: defuse %.tex hsprelude
-       [ -r "$target" ] && chmod +w $target
-       ./defuse '\^' < $stem.tex > $target
-       chmod -w $target
-
-
-CLIENT=../testing
-CPROPS=ConstProp Simplify Test
-
-cprop.tex:D: ./xsource ${CPROPS:%=$CLIENT/%.hs}
-       lua $prereq > $target
-
-HOOPL=../src/Compiler/Hoopl
-
-comb1.tex iterf.tex pairf.tex:D: ./xsource $HOOPL/Combinators.hs
-       lua $prereq
-
-dfoptdu.tex: fptype.tex bodyfun.tex block.tex
-
-dfoptdu.tex: bodyfun.tex fptype.tex update.tex fpimp.tex txfb.tex
-
-txfb.tex block.tex cat.tex bodyfun.tex update.tex fptype.tex fpimp.tex dg.tex node.tex:D: ./xsource $HOOPL/Dataflow.hs
-       lua ./xsource -4 $HOOPL/Dataflow.hs
diff --git a/paper/notes-relatedwork b/paper/notes-relatedwork
deleted file mode 100644 (file)
index 6ff44ac..0000000
+++ /dev/null
@@ -1,57 +0,0 @@
-Soot:
-
-3 kinds of analyses:
- - fwd, bwd, fwd with different results on different branches
-
-Abstracted over flowgraph (abstract DirectedGraph class)
-
-Requires a new, annoying constructor for each analysis that calls ... doAnalysis()
-
-Lattice join and _copy_ -- b/c it's _required_ to be mutable
-
-No interleaving
-
-Most useful reading: http://www.brics.dk/SootGuide/
-
-
-
-CIL:
-
-Not abstracted over flowgraph
-
-Complicated interface that can affect how the analysis iterates
-over the graph.
-
-No interleaving
-
-Most useful reading:
-http://docs.camlcity.org/docs/godipkg/3.10/godi-cil/doc/godi-cil/html/api/Dataflow.ForwardsTransfer.html
-
-
-Whirlwind:
-Interleaving, of course.
-Implementation much like our earlier efforts:
-a complicated mix of interleaving and recursive rewriting,
-with dynamic checks that the client returns correct graphs.
-Representation of the transformations is generated by interleaved analysis and
-transformation,
-then the generated transformations are applied;
-all of this is simpler in our story b/c we have immutable graphs.
-No optimization fuel.
-
-analyze-implementation.diesel - 284 non-comment, non-blank loc
-analysis.diesel - 30 non-comment, non-blank loc
-analysis-action.diesel - 45 non-comment, non-blank loc
-analysis-graph.diesel - 79 non-comment, non-blank loc
-analysis-info.diesel - 4 non-comment, non-blank loc
-analyze.diesel - 20 non-comment, non-blank loc
-
-core of implementation is about 500 non-comment, non-blank loc
-
-
-
-LLVM:
-
-Pass manager -- there's a lot of support for gathering passes
-  and ordering them effectively, but I don't see anything
-  that might be termed a dataflow framework
diff --git a/paper/old-implementation-sections.tex b/paper/old-implementation-sections.tex
deleted file mode 100644 (file)
index e30f6aa..0000000
+++ /dev/null
@@ -1,344 +0,0 @@
-\section{The Dataflow Engine}
-\seclabel{engine}
-\seclabel{dfengine}
-\simon{Need a linking sentence like ``So far we have discussed clients of 
-our library.  Now we turn our attention to the implementation of the
-library itself.''  Yes, you'll want to use different vocabulary!}
-
-The dataflow engine is implemented in two layers.
-The lower layer is the \emph{dataflow monad}.
-It~keeps track of the values of dataflow facts as the engine iterates.
-The upper layer is divided into four parts:
-a forward solver, a forward rewriter,
-a backward solver, and a backward rewriter.
-
-Despite the implicit claim in the title of this paper,
-the dataflow engine is not simple.
-The benefit of our design is that the \emph{interface} to the dataflow
-engine (lattice, transfer functions, rewriting functions) is simple,
-and as shown above, compiler passes written \emph{using} the engine
-are very simple indeed.
-But~the engine itself is complex.
-
-Most of the complexity in the dataflow engine arises because we
-implement the ambitious algorithm of
-\citet{lerner-grove-chambers:2002}, who write
-\begin{quote}
-\emph{Previous efforts to exploit [the mutually beneficial
-interactions of dataflow analyses] either (1)~iteratively performed
-each individual analysis until no further improvements are discovered
-or (2)~developed [handwritten] ``super-analyses'' that manually
-combine conceptually separate analyses. We have devised a new approach
-that allows analyses to be defined independently while still enabling
-them to be combined automatically and profitably. Our approach avoids
-the loss of precision associated with iterating individual analyses
-and the implementation difficulties of manually writing a
-super-analysis.}
-\end{quote}
-Adapting this work to a purely functional setting results in an
-implementation that is significantly simpler than the original.
-We~sketch that implementation below.
-
-
-%%  Note that the dataflow engine is the only part of the system that is
-%%  hard to get right---this is where all the hair is.
-%%  Prime benefit of our system is that once this is right, everything is
-%%  easy (and indeed is just logic, strongest postcondition, or weakest
-%%  precondition). 
-%%  
-
-
-
-\subsection{The dataflow monad}
-
-The primary purpose of the dataflow monad is to keep track of 
-dataflow facts as the engine iterates.
-Dataflow facts are found in three places:
-\begin{itemize}
-\item
-There is a dataflow fact associated with every labelled basic block in
-the current graph;
-the dataflow monad maintains this association in a finite map.
-The functions @getFact@ and @setFact@ query and update this map.
-\item
-The current graph may be a subgraph of a larger graph, in which case a
-forward dataflow pass may produce dataflow facts that flow to labelled
-blocks that are outside the current graph.
-These facts must be retained and propagated even if the current graph
-is abandoned; such facts are added with @addLastOutFact@ and recovered
-with @bareLastOuts@.
-\item
-Finally, a foraward dataflow pass over a subgraph may propagate a fact forward by
-``falling off the end;'' such a fact is set with @setExitFact@ and
-recovered with @getExitFact@.
-\end{itemize}
-In addition to keeping track of facts, 
-the dataflow monad provides a number of other facilities to manage
-changes in state as graphs are rewritten and facts climb the dataflow
-lattice:
-\begin{itemize}
-\item
-The monad keeps track of whether any fact has changed.
-\item
-It provides a @subanalysis@ function which makes it possible to
- analyze a subgraph using the current set of facts, then discard any
- changes in state that may have resulted from the analysis of the
- subgraph.
-\item
-It provides a supply of fresh @BlockId@s, which are available for use
-by rewrite functions.
-\item
-It tracks the supply of \emph{optimization fuel}.
-As~shown below, when fuel runs out, the dataflow engine stops
-calling rewriting functions, effectively halting optimization.
-Binary search on the size of the fuel supply enables the compiler to
-identify unsound rewrites quickly \cite{whalley:isolation}.
-\end{itemize}
-
-
-\subsection{The dataflow engine}
-
-In implementing the dataflow engine, our primary tactic has been to
-minimize the amount of duplicate or near-duplicate code.
-To~that end, \emph{the dataflow engine implements only composed
-analysis and transformation}.
-Pure analysis is implemented as a special case in which no node is
-ever rewritten.
-As explained by \citet{lerner-grove-chambers:2002}, a~composed
-analysis is implemented in two phases:
-\begin{itemize}
-\item
-In the first phase, when a rewrite function proposes to replace a
-node, the replacement graph is analyzed recursively, and the results
-of that analysis are used as the new dataflow
-fact(s) flowing out of the original node.
-But \emph{the original node is not replaced}; indeed, the replacement
-graph is abandoned, and only the facts remain.
-If,~during iteration, the original node is analyzed again, perhaps
-with a more conservative input fact, the rewrite function may propose
-a different replacement or even no replacement at all.
-This phase is called the \emph{solver}.
-The solve computes a fixed point of the dataflow analysis
-\emph{as if} nodes were replaced, while avoiding ever replacing a node
-unsafely. 
-\item
-Once the solver is complete, the resulting fixed point is sound,
-and the facts in the fixed point are used by the second phase in which
-each replacement proposed by a rewriting function is actually
-performed.
-This phase is called the \emph{rewriter}.
-\end{itemize}
-
-In \citeyear{ramsey-dias:applicative-flow-graph}, two of us
-\citeauthor{ramsey-dias:applicative-flow-graph} presented
-implementations in Objective Caml of a backward solver and rewriter.
-Here, then, as a complement, we sketch implementations of the forward
-solver and rewriter used in~GHC. \simon{Oh!  thinks the reader... so this
-paper is just a rehash in Haskell of your earlier work?  Can we 
-say somethign like ``See Related work for the substantial differences
-between this paper and our ealier work''?}
-
-
-\begin{itemize}
-\item
-@fwd_pure_anal@ is @forward_sol@ passed the @squash@ function
-@\ _ _ -> Nothing@.
-It ignores its rewrite, depth, and fuel parameters.
-\item
-The internal @solve@ function is higher-order in the parameter
-@finish@, which extracts from the dataflow monad either the unique
-exit fact or the set of @LastOuts@, depending on context.
-\item
-The function @set_or_save@ calls @setFact@ for @BlockId@s located
-within graph~@g@ and calls @addLastOutFact@ for @BlockId@s located
-outside graph~@g@.
-\end{itemize}
-
-
-
-
-\section{Implementing graphs}
-\seclabel{graphs}
-
-Our optimizer represents each procedure using a control-flow graph.
-Our representation of control-flow graphs is
-\begin{itemize}
-\item
-Purely applicative, which makes it exceptionally easy to compose
-analyses and transformations as described in \secref{engine}
-\item
-Polymorphic, which enables us not only to reuse the graph for
-different low-level intermediate languages, but which forces us to
-distinguish generally useful dataflow algorithms from particular
-realizations in~GHC
-\item
-Based on Huet's \citeyearpar{huet:zipper} \emph{zipper},
-which makes it easy to adapt existing code improvements written in
-imperative style
-\end{itemize}
-\citet{dias-ramsey:applicative-flow-graph} present our design in
-detail, as well as discussing alternatives, advantages, and
-disadvantages.
-In~this paper we give a high-level view of the data structure, and we
-emphasize a significant refinement: the introduction of polymorphism.
-
-\subsection{Basic data structure}
-
-A~basic block is a sequence beginning with a first node, continuing
-with zero or more middle nodes, and ending in a last node.
-A~first node contains only a unique identifier of type @BlockId@; the
-types of middle and last nodes are parameters.
-At~any given moment, the dataflow engine may \emph{focus} on a
-particular edge, in which case 
-it holds the source of that edge plus a
-list of its predecessors all the way back to the first node,
-and 
-it holds the sink of that edge plus a
-list of its successors all the way forward to the last node.
-These values have types @ZHead m@ and @ZTail m l@, where @m@~and~@l@
-are the types of middle and last nodes:
-\begin{code}
-data ZHead m   = ZFirst BlockId 
-               | ZHead (ZHead m) m
-data ZTail m l = ZLast (ZLast l) | ZTail m (ZTail m l)
-\end{code}
-The type @ZLast l@ extends~@l@ with an additional case, @LastExit@,
-which represents a subgraph that ends not in a control transfer but by
-``falling off the end.''
-
-We~``modify'' a block by creating a new head and tail; to ``insert'',
-``remove'', or ``mutate'' a node typically requires a couple of
-allocations 
-\cite{dias-ramsey:applicative-flow-graph}. 
-With these operations it is easy to recast imperative graph-rewriting
-code into a pure functional form.
-
-
-When we are not focusing on a particular edge, we represent a basic
-block by pairing its first node (a~@BlockId@ with a @ZTail@):
-\begin{code}
-data Block m l = Block BlockId (ZTail m l)
-\end{code}
-An entire graph is represented as a finite map from @BlockId@ to
-block, together with the ID of the entry node:\footnote
-{The representation of @BlockId@ is chosen so that not only is
-  it efficient to create an infinite supply of @BlockId@s, but finite
-  maps with @BlockId@ keys can be implemented using a Patricia tree,
-  which is even more efficient than a balanced binary tree
-  \cite{okasaki-gill:integer-map}.} 
-\begin{code}
-data Graph m l =
-   Graph { g_entry  :: BlockId
-         , g_blocks :: BlockEnv (Block m l) }
-\end{code}
-%%  
-%%  A~graph has a single \emph{entry} and at most one \emph{default exit}.
-%%  A~graph has a default exit, which we abbreviate just ``exit'', only if
-%%  control can ``fall off the end.'' 
-%%  A~graph has no exit if control leaves the graph only by an explicit
-%%  procedure return or tail call;
-%%  for example, the graph for a whole procedure  has no exit.
-%%  The most common use of a single-entry, single-exit flow graph is as a
-%%  replacement for a middle node during code improvement.
-
-%%  Each control-flow graph is represented as a finite map from @BlockId@ to
-%%  basic block, together with a distinguished @BlockId@ that marks the entry
-%%  node.
-%%  When a graph is ``being modified'',
-%%  we \emph{focus} on one internal edge of one basic block.
-%%  The focus is represented by a pair.
-%%  One element of the pair points to the
-%%  source of the edge, which is linked to its predecessor, and so on up
-%%  to the block's first node.
-%%  The other element of the pair points to the
-%%  sink of the edge, which is linked to its successor, and so on down
-%%  to the block's last node.
-
-\subsection{Realization in GHC}
-
-The two significant differences between the applicative flow graph
-used in Quick~{\PAL} \cite{dias-ramsey:applicative-flow-graph} and the
-refined version described in this paper are that the new version is
-polymorphic, and the new version stores properties in separate finite
-maps, not in mutable property lists.
-%We use finite maps in order to avoid mutable reference cells, which
-%require that computations be done in the @IO@~monad.
-The change from propertly lists to finite maps is inconsequential,
-affecting the algorithms in only minor ways and the structure of the
-code not at all.
-The change from a monomorphic to a polymorphic control-flow graph, by
-contrast, has far-reaching implications.
-
-Types related to control flow graph are polymorphic in two parameters:
-the type of middle nodes and the type of last nodes.\footnote
-{We considered abstracting over types associated with first nodes as
-  well, but we preferred to restrict first nodes so that a first node
-  carries a @BlockId@ and only a @BlockId@.
-  This design gives us fewer type parameters and
-  therefore fewer higher-order functions associated with those
-  parameters.
-  Because we can always use a finite map to associate data with
-  each first node, we don't lose any expressive power.}
-This design militates toward a modular implementation,
-in which the implementation of the dataflow engine is 
-decoupled from the representation of computations at individual nodes.
-\begin{itemize}
-\item
-Module @ZipCfg@ exports data structures and algorithms that are
-independent of the type of middle and last nodes.
-However, in order to enable other algorithms to change the flow graph
-without knowing the representation of a last node, @ZipCfg@ exports a
-@LastNode@ type class which all last nodes must support.
-Ths @LastNode@ type class expresses the minimum required of a type
-that claims to repesent a control transfer:
-it must be possible to
-create a last node that branches unconditionally to a given @BlockId@ (goto);
-to test to see if a last node is an unconditional branch, and if so, to
-what target;
-and to observe what @BlockIds@ designate possible successors of a last
-node.
-Operations that observe successors are extended to basic
-blocks of type @Block m l@ and to values of type @ZTail m l@.
-
-@ZipCfg@ exports a number of basic algorithms on graphs, including the
-splicing algorithms described by
-\citet{ramsey-dias:applicative-flow-graph}. 
-The most important algorithm is postorder depth-first-search
-traversal, which orders the basic blocks in a way such that iterative
-dataflow analyses converge quickly.
-As~a benevolent side effect, this traversal also prunes unreachable
-code from the graph.
-\item
-Module @ZipCfgCmmRep@ depends on @ZipCfg@, but not the converse.
-It~exports definitions of the middle- and last-node types needed to
-represent GHC's low-level intermediate code, @Cmm@.
-For convenience, it also exports instantiations of graph types,
-and it exports instance declarations that make it easy to walk @Cmm@
-nodes and find out what registers and stack slots are defined and
-used.
-\item
-The \emph{representation} exported by
-@ZipCfg@ and @ZipCfgCmmRep@ is useful primarily
-for \emph{analyzing} flow graphs.
-To~\emph{construct} a flow graph we use ``smart constructors'' which
-produce monadic functions from graphs to graphs.
-Using these constructors, GHC's front end creates large graphs by
-composing smaller ones.
-
-The smart constructors are inspired by Hughes's \citeyearpar{hughes:novel-lists}
-representation of lists.
-They are similar to the functions of type 
-@zgraph -> zgraph@ described by
-\citet{ramsey-dias:applicative-flow-graph}, 
-but in our Haskell implementation, the function type is monadic and is
-hidden from clients.
-A~monadic type is necessary in order to plumb through an infinite supply
-of @BlockId@ values.
-When a client \emph{wants} to use a @BlockId@, for example, to translate
-structured control flow into conditional and unconditional branches,
-the graph-construction interface provides a constructor of type
-analogous to $(\mathtt{BlockId} \arrow \mathit{graph}) \arrow \mathit{graph}$.
-%% , as described in the companion paper.
-%% \cite{dias-peyton:refactoring}. 
-\end{itemize}
-
diff --git a/paper/onepage.tex b/paper/onepage.tex
deleted file mode 100644 (file)
index 5175653..0000000
+++ /dev/null
@@ -1,610 +0,0 @@
-\documentclass[twocolumn]{article}
-\usepackage{vmargin,mathpartir,times,mathptm,graphicx}
-% l2h substitution PAL <tt>C--</tt>
-\renewcommand{\ttdefault}{aett}
-
-
-\setcounter{secnumdepth}{0}
-
-\usepackage{verbatim} % allows to define \begin{smallcode}
-\newenvironment{code}{\par\unskip\kern-6pt \small\verbatim}{\endverbatim}
-\newenvironment{smallcode}{\par\unskip\footnotesize\verbatim}{\endverbatim}
-%\newenvironment{fuzzcode}[1]{\par\unskip\hfuzz=#1 \verbatim}{\endverbatim}
-%\newenvironment{smallfuzzcode}[1]{\par\unskip\small\hfuzz=#1 \verbatim}{\endverbatim}
-
-\newcommand{\PAL}{\mbox{C\ttfamily-{}-}}
-\newcommand\lrtl{\mbox{$\lambda$-RTL}}
-% l2h substitution lrtl <b>lambda</b>-RTL
-\setpapersize{USletter}
-%            left  top   right  bottom
-\setmarginsrb{0.93in}{0.5in}{0.93in}{0.4in}
-             {\headheight}{\headsep}{\footheight}{\footskip}
-\columnsep=23pt
-
-\pagestyle{headings}
-\makeatletter
-\let\nrlist\@listi
-\def\@listi{\nrlist\parsep=0.5\parsep
-  \itemsep=0.5\itemsep\topsep=0.5\topsep
-  \parskip=0.5\parskip}
-\let\@listI\@listi
-\def\@oddhead{\hfil\smash{\raisebox{-10pt}{
-\large
-\begin{tabular}{c}
-\Large {Hoopl} in four pages\\Norman Ramsey, Tufts University
-\\(joint work with Jo\~ao Dias and Simon Peyton Jones)\vrule width 0pt
-height 0pt depth 8pt
-\end{tabular}}}\hfil}
-\def\@oddfoot{\hfil\thepage\hfil}
-\makeatother
-
-\makeatletter
-\newcommand\mysection[1]{%
-  \par
-  \vskip 0.5\baselineskip plus 2pt minus 1pt
-  \noindent{\raggedright\textbf{#1}}
-  \par
-  \vskip 0.3\baselineskip plus 2pt minus 1pt
-  \@afterindentfalse
-}
-
-\newcommand\triple[3]{\ensuremath{#1\;\{#2\}\;#3}}
-\newcommand\implies{\Rightarrow}
-\renewcommand\wp{\ensuremath{\mathit{wlp}}}
-\let\wlp=\wp
-\renewcommand\sp{\ensuremath{\mathit{sp}}}
-
-\renewcommand\mysection[1]{%
-  \@startsection{section}{1}{\z@}{-0.5\baselineskip plus -2pt minus -1pt}%
-                                   {0.3\baselineskip plus 2pt minus 1pt}%
-           {\normalfont\raggedright\bfseries}}
-
-\makeatother
-
-
-\parindent=0pt
-\parskip=2pt plus3pt
-
-\newenvironment{twolist}{\itemize}{\enditemize}
-
-\input{diagrams}
-
-\begin{document}
-
-\mysection*{Background}
-
-In my student days I didn't care for dataflow analysis or
-optimization.
-Dataflow analysis was full of bit vectors and $\cap$~and~$\cup$
-symbols and funny words like ``gen'' and ``kill.''
-Optimization was even more chaotic: more bit vectors, plus
-special-purpose, pointwise, stateful program transformations that
-didn't seem to have anything to do with anything else (or each other).
-
-Two things changed my mind: in 2002, Sorin Lerner, David Grove, and Craig
-Chambers published a landmark paper which, among other things, showed
-me a uniform way to think about program analysis and transformation;
-and in 2004, after several years wrestling with traditional, mutable
-representations of programs, John Dias and I had the idea of using an
-\emph{applicative} control-flow graph based on Huet's zipper.
-The applicative control-flow graph turned out to make it almost
-trivial to implement the big innovation of Lerner, Grove, and
-Chambers: speculative rewriting.
-The key idea is an analogy between dataflow analysis and program
-logic.
-
-\mysection*{Program logic}
-
-Compilers might be ugly, but semantics can be beautiful.
-The rock on which we build is Tony Hoare's axiomatic semantics, 
-also known as ``Hoare logic,''
-where
-\begin{mathpar}
-\triple P S Q
-\end{mathpar}
-says that if we execute command~$S$ in any state satisfying precondition~$P$, and
-if it terminates, the final state satisfies postcondition~$Q$.
-Tony laid out axioms and inference rules for this judgment, of which
-the most suggestive are the strengthening and weakening rules:
-\begin{mathpar}
-\inferrule{P \implies P' \\ \triple {P'} S Q}
-{\triple P S Q}
-
-\inferrule{\triple P S {Q'} \\ Q' \implies Q \\ }
-{\triple P S Q}
-\end{mathpar}
-These rules suggest there could be a \emph{best}
-postcondition~$Q$---the one that implies all the others---and likewise
-a \emph{best} precondition~$P$.
-In fact they are Bob Floyd's 
- \emph{strongest verifiable consequent} (now called ``strongest postcondition'')
-and Dijkstra's weakest (liberal) precondition.
-And the most natural thing in the world is to try to turn Hoare's
-relation into a function: to \emph{compute} \wp~or~\sp.
-Unfortunately, in the presence of loops, these computations don't
-terminate.
-Dijkstra and Hoare got around the problem by forcing the programmer to
-write down a \emph{loop invariant}:
-\begin{mathpar}
-\inferrule{\triple {I \land B} S I}
-{\triple I {\mbox{\texttt{while} $B$ \texttt{do} $S$}} {I \land \lnot B}}
-\end{mathpar}
-Without a loop invariant, this approach seemed like a dead end---but
-it isn't.
-
-\mysection*{Dataflow analysis as program logic}
-
-Dataflow analysis typically talks about ``states'' (sometimes
-represented as bit vectors) and ``transfer functions.''
-I~follow Lerner, Grove, and Chambers, who talk about ``dataflow facts.''
-The connection with program logic is simple but breathtaking:\footnote
-{As stated here, the connection is \emph{over} simple.  More anon.}
-\begin{itemize}
-\item
-A dataflow fact \emph{stands for} a logical formula.
-Even better, every logical formula can be \emph{approximated} by a
-dataflow fact.
-\item
-The transfer function for a forward dataflow analysis is a homomorphic
-image of \sp\ on the dataflow fact.
-And the transfer function for a backward dataflow analysis is a homomorphic
-image of \wlp\ on the dataflow fact.
-\end{itemize}
-In other words, \emph{dataflow analysis is simply predicate
-  transformers applied to an impoverished program logic}.\footnote
-{I'm sure David Schmidt means something similar when he says that
-  dataflow analysis is model checking of abstract interpretation, but
-  since I've never been able to understand any of those papers,
-  I~can't prove~it.}
-A~``transfer function'' is a Curried function that takes program code
-  as an argument and returns a \emph{fact transformer}.
-
-\newcommand\embed{\mathcal E}
-\renewcommand\approx{\mathcal A}
-
-% \newarrow{impliedBy} {<=}====
-
-\kern-2\baselineskip
-
-\begin{center}
-\begin{diagram}
-P' & \lImplies     & P              & \rTo^{\sp} & Q' & \rImplies & Q \\
-   & \luTo^{\embed} & \dTo ^ \approx &           &    &  \ruTo^\embed & \\
-   &                & f              & \rTo^{\mbox{transfer}} & f' &     & \\
-\end{diagram}
-\end{center}
-
-Because of loops, there's a little more to it than that:
-\begin{itemize}
-\item
-We associate a logical variable with each basic block,
-and on each basic block 
- we run the fact transformers and get out an equation relating logical
- variables.
-In the presence of loops, the equations are mutually recursive.
-\item
-We solve the recursive equations \emph{constructively}, through the
-method of successive approximations.
-If we use a work-list method,
-the analogy with iterative dataflow analysis is exact.
-\end{itemize}
-
-
-
-This observation has two important consequences:
-\begin{enumerate} 
-\item
-\label{cbottom}
-The representation of dataflow facts, unlike that of
-logical formulas, \emph{must} include a bottom element.
-\item
-\label{cterm}
-Unlike the language of formulas, 
-the language of dataflow facts must be sufficiently impoverished that
-there are no infinite ascending chains.
-\end{enumerate}
-Consequence~\ref{cbottom} gives us a starting point for the method of
-successive approximations; consequence~\ref{cterm} ensures it terminates.
-
-
-\mysection*{The genesis of Hoopl}
-
-Here's why I've spent five years on this problem:
-\begin{quote}
-\emph{If
-the analogy between program logic and dataflow analysis holds up,
-we should be able to create optimizers that are powerful, fun to
-build, easy to get right, and that are part of an intellectually
-coherent family of program transformations.
-}
-\end{quote}
-I've refined this notion into three hypotheses.
-
-\emph{Hypothesis~\#1\quad} 
-Having a good story changes the way we should think
-about dataflow analysis:
-\begin{itemize}
-\item
-Instead of thinking about bit vectors, sets, mutation, gen, kill, and
-all that, we should think about \emph{transforming dataflow facts},
-which represent logical formulas.
-Using a pure functional language and ``wholemeal programming'' as
-advocated by Richard Bird, we can write the code the way we think
-about problems.
-\item
-There are only two analyses: weakest preconditions and strongest
-postconditions.
-And there are an infinite number of ways to approximate formulas.
-These approximations will be the source of the next 700 dataflow
-analyses.
-\end{itemize}
-
-\emph{Hypothesis~\#2\quad} 
-The classical optimizations, which appear to be such a mess, can
-be better understood as being composed from just three
-transformations:
-\begin{itemize}
-\item
-Substitution of equals for equals
-\item
-Elimination of redundant assignments
-\item
-\emph{Introduction} of redundant assignment
-\end{itemize}
-Substitution needs no introduction.
-A~redundant assignment is the imperative analog of a let-bound
-variable that does not appear free in the body: the binding can be
-eliminated. 
-Redundant assignments are \emph{introduced} to enable the first two
-transformations. 
-The simplest example is ``code motion.''
-
-
-\emph{Hypothesis~\#3\quad} 
-We should change the way we
-code:
-\begin{itemize}
-\item
-If we understand predicate transformers, transfer functions should be
-easy to write.
-\item
-If that diagram really commutes, it should be possible to \emph{test}
-that it commutes.
-\item
-If we can pull our head out of the bit vectors and the other details,
-it should be possible to tell beautiful new stories about all the old
-optimizations.
-\end{itemize}
-
-To investigate these hypotheses, John Dias, Simon Peyton Jones, and~I
-have created a reusable library called \emph{Hoopl:} a Higher Order
-OPtimization Library.
-Hoopl is intended for classical optimization of \emph{imperative} code
-such as low-level intermediate code or machine instructions.
-An~analysis or optimization written using Hoopl is a \emph{client}.
-
-\mysection*{Representing control-flow graphs}
-
-Authors of clients should be free to think great thoughts about
-predicate transformers and fact transformers.
-Hoopl keeps track of which predicates flow where.
-To~simplify this process we \emph{statically type} the units of the IR
-being optimized:
-\begin{itemize}
-\item
-The target of \emph{any} control transfer must be labelled with a
-unique \texttt{Label}.
-A~labelled node may have any number of predecessors (including zero),
-but it has exactly one successor.
-In~a typical IR, a labelled node will contain \emph{only} the label.
-\item
-An ordinary computational node does no control flow; it has
-exactly one predecessor and exactly one successor.
-This case is the most common and is the simplest for the client,
-because it reduces most directly to predicate transformers.
-\item
-A control-flow node has a unique predecessor, but it may have many
-successors.
-Such nodes includes calls, returns, and all forms of goto
-(conditional, unconditional, and computed).
-\emph{Every} successor must be a labelled node; Hoopl does not permit
-``fallthrough.''
-\end{itemize}
-
-\subsection{Nodes, blocks and graphs; open and closed}
-
-Every node is \emph{open or closed at entry}
-and \emph{open or closed at exit}.  
-An \emph{open} point is one at which control may implicitly ``fall through;''
-to transfer control at a \emph{closed} point requires an explicit
-control-transfer instruction.
-
-A~sequence of nodes is well typed only if whenever two nodes follow
-one another in the sequence, both nodes are open at the point where
-they touch.
-Such a sequence is called a \emph{block} and can be written using
-these constructors:
-\begin{code}
-data O   -- Open
-data C   -- Closed
-
-data Block n e x where
- BFirst  :: n C O                      -> Block n C O
- BMiddle :: n O O                      -> Block n O O
- BLast   :: n O C                      -> Block n O C
- BCat    :: Block n e O -> Block n O x -> Block n e x
-\end{code}
-Blocks come in four shapes: open/open, open/closed, closed/open, and
-closed/closed.
-A~closed/closed block is a \emph{basic block} and cannot be further
-extended with \texttt{BCat}.
-Basic blocks are \emph{not} living dinosaurs; they are a fundamental
-consequence of controlling predecessors and successors.
-
-In honor of their position within a basic block, 
-a closed/open node is called a \emph{first node}; 
-an open/open node is called a \emph{middle node}; 
-and
-an open/closed node is called a \emph{last node}.
-
-
-A \emph{control-flow graph} is a collection of blocks.
-Graphs also come in four shapes:
-\begin{code}
-data Graph n e x where
-  GNil  :: Graph n O O
-  GUnit :: Block n O O -> Graph n O O
-  GMany :: MaybeO e  (Block n O C) 
-        -> Map Label (Block n C C)
-        -> MaybeO x  (Block n C O)
-        -> Graph n e x
-
-data MaybeO ex t where
-  JustO    :: t -> MaybeO O t
-  NothingO ::      MaybeO C t
-\end{code}
-Most blocks are closed/closed; a graph may contain at most one
-open/closed \emph{entry sequence} and at most one closed/open
-\emph{exit sequence}.
-Also, an open/open sequence of middle nodes forms a graph
-(by~\texttt{GUnit} or \texttt{GNil}).
-
-
-
-Our implementation exploits the fact that the shape of every node and
-block is known \emph{statically} from the context in which it occurs.
-But our analysis and rewriting functions are all polymorphic in the
-shape.
-
-\mysection*{Dataflow passes}
-
-Each dataflow analysis begins with a lattice of dataflow facts.
-Hoopl proper does not need to know how to embed a fact into the
-language of logical formulas or how to approximate a logical formula
-by a fact.
-It~needs only to be able to start at the bottom and to take the least
-upper bound of a pair of facts.
-(When it does take the least upper bound, however, it needs to know if
-something changed.)
-\begin{smallcode}
-data DataflowLattice f = DataflowLattice  
- { fact_bot        :: f
- , fact_extend     :: JoinFun f
- }
-type JoinFun f
-  = Label -> OldFact f -> NewFact f -> (ChangeFlag, f)
-  -- the label argument is for debugging purposes only
-newtype OldFact f = OldFact f
-newtype NewFact f = NewFact f
-
-data ChangeFlag = NoChange | SomeChange
-\end{smallcode}
-
-A forward transfer function takes a node of any shape and returns a
-fact transformer:
-\begin{code}
-type FwdTransfer n f 
-  = forall e x. n e x -> f -> Fact x f 
-
-type family   Fact x f :: *
-type instance Fact C f = FactBase f
-type instance Fact O f = f
-
-type FactBase f = Map Label f
-\end{code}
-The type definition uses a new feature of Haskell called \emph{type
-  families}.
-A~type family is a type-level function; this one says that the
-  transfer function for a node that is open at the exit (and so has a
-  single successor) returns a single fact~\texttt{f}.
-But the transfer function for a node that is \emph{closed} at the exit
-  could have multiple successors, so it returns a finite map from
-  successors' labels to facts.
-This map is called a \emph{fact base}.
-
-Clients can also \emph{rewrite} nodes:
-\begin{smallcode}
-type FwdRewrite n f 
-  = forall e x. n e x -> f -> Maybe (FwdRes n f e x)
-data FwdRes n f e x = FwdRes (AGraph n e x) (FwdRewrite n f)
-  -- result of a rewrite is a new graph and 
-  -- a (possibly) new rewrite function
-\end{smallcode}
-If justified by the incoming fact, a rewrite function can
-\emph{replace} a node with a graph, subject only to the requirement
-that in any execution in which the incoming fact holds, the graph is
-observationally equivalent to the node it replaces.
-Rewrite functions implement all three kinds of transformations.
-
-Combine all three and you get a \emph{forward dataflow pass}:
-\begin{code}
-data FwdPass n f
-  = FwdPass { fp_lattice  :: DataflowLattice f
-            , fp_transfer :: FwdTransfer n f
-            , fp_rewrite  :: FwdRewrite n f }
-\end{code}
-What Hoopl does for you is captured in one function:
-\begin{smallcode}
-analyzeAndRewriteFwd
-   :: (Edges n, LabelsPtr entries)
-   => FwdPass n f
-   -> entries
-   -> Graph n e x 
-   -> Fact e f
-   -> FuelMonad (Graph n e x, FactBase f, MaybeO x f)
-\end{smallcode}
-This function takes a forward pass, a graph with entry points,
-and an incoming fact or fact~base.
-It returns a rewritten graph, the fact associated with each label in
-the rewritten graph, and if the graph is open at the exit, the fact
-flowing out that exit.
-
-Backward dataflow passes use the same lattice type and appropriate
-types for transfer and rewrite functions.
-
-\mysection*{Creating a client}
-
-To create an analysis or optimization, you
-\begin{enumerate} 
-\item
-Decide on a set of dataflow facts and identify what logical formulas
-they approximate.
-\item
-Write the transfer function as the homomorphic image of the predicate
- transformer  \wp~or~\sp.
-\item
-Possibly create a rewrite function that exploits the dataflow fact to
-make code-improving transformations.
-\end{enumerate}
-One beautiful aspect of this approach is that once you have chosen
-a representation of nodes, \emph{there is only one correct way to
-  write \wp~and~\sp}.  
-You can therefore build a deep understanding of these predicate
-transformers and how to approximate them.
-Perhaps one day we'll have automated tests or even proofs, such as
-Sorin Lerner has developed at UCSD.
-
-\mysection*{The critical bit I left out}
-
-Dataflow analysis does \emph{more} than classical program logic:
-it can reason about \emph{paths}.
-Classical Hoare logic gives a predicate about states, and the
-predicate applies to any state that the machine can be in at a
-particular program point, \emph{no matter what path it took to get
-  there}.
-In~the jargon of dataflow analysis, anything analogous to Hoare logic
-is an ``all-paths problem.''
-There are also ``any-paths problems,'' such as \emph{reachability}:
-can a particular node be reached from the entry point?  Or~from some
-other node.
-
-To decide the redundancy of an assignment to variable~$x$, we solve a ``backwards
-any-path problem:'' is there any path from the assignment to a
-\emph{use} of~$x$ such that the path is not cut by any other
-assignment to~$x$.
-
-As far as I know, it is not known if there is an analogy between path
-problems and program logic.
-I'm~keenly interested in this question.
-I~find it telling that while we have a name for the set of paths
-leaving a program 
-point---the point's \emph{continuation}---I don't know if we have a name
-for the set of paths \emph{reaching} a program point.
-Dataflow analyses can reason about history and about the future.
-How~can we connect this reasoning to program semantics?
-
-
-\mysection*{An example: dominators}
-
-If \emph{every} path from the entry to
-label \texttt{L} must pass through another label \texttt{D},
-\texttt{D} \emph{dominates} \texttt{L}.
-\texttt{D} is called a \emph{dominator} of \texttt{L}.
-There are efficient special-purpose
-algorithms for computing dominators, but we can also compute
-dominators through a forward dataflow analysis.
-The analysis is beautifully simple; it is based on an unpublished
-paper by Cooper, Harvey, and Kennedy, who showed that their $O(N^2)$ version
-outperforms the classical $O(E\;\log N)$ algorithm of Lengauer and
-Tarjan.
-\begin{enumerate}
-\item
-The dataflow fact at a point is a list of all the labels that dominate
-the point:
-\begin{code}
-type DPath = [Label] -- path in dominator tree
-\end{code}
-The list is ordered such that every label is dominated by all its
-successors.
-The predicate associated with the dataflow fact is not a logical
-formula; it is an assertion about the set of all paths from the entry to
-the point at which the fact applies.
-
-The analysis requires a bottom element that is not a list;
-bottom corresponds to an assertion that a node that is not reachable
-from the entry, i.e., no path exists from the entry to that node.
-The bottom element is added by type \texttt{WithBot}:
-\begin{code}
-type Doms = WithBot DPath
-\end{code}
-\item
-The transfer function is simple: given a first node, it adds the label
-to the head of the list.
-Transfer for a middle node is the identity, and
-transfer for a last node distributes the fact to its successors:
-\begin{code}
-domFirst n  = (entryLabel n :)
-domMiddle _ = id
-domLast     = distributeFact
-
-distributeFact :: Edges n => n O C -> f -> FactBase f
-distributeFact n f
-  = mkFactBase [ (l, f) | l <- successors n ]
-\end{code}
-\item
-The interesting part is the join function:
-given two paths, it returns the longest common suffix:
-\begin{code}
-extend :: JoinFun DPath
-extend _ (OldFact l) (NewFact l')
-  = (changeIf (l `lengthDiffers` j), j)
- where j = lcs l l'
-       lcs :: [Label] -> [Label] -> [Label]
-       ...
-\end{code}
-The \texttt{WithBot} type comes with a lifting function that returns
-\texttt{JoinFun~Doms}.
-\end{enumerate}
-
-\subsection{Example results from dominator analysis}
-
-The program is insertation sort, with two nested loops:
-\begin{smallcode}
-  a := 0
-  goto L1
-L1:
-  if (a != d) then goto L2 else goto L3
-L6:
-  c[b] := e
-  goto L1
-L2:
-  a := (a + 1)
-  b := (a - 1)
-  e := c[b]
-  goto L4
-L4:
-  if ((b != 0) && (c[(b - 1)] > e)) then goto L5 else goto L6
-L5:
-  c[b] := c[(b - 1)]
-  b := (b - 1)
-  goto L4
-L3:
-\end{smallcode}
-
-\centerline{%
-\includegraphics[scale=0.4]{dom.eps}%
-}
-
-
-\end{document}
-
diff --git a/paper/proto-response.txt b/paper/proto-response.txt
deleted file mode 100644 (file)
index b443958..0000000
+++ /dev/null
@@ -1,87 +0,0 @@
-  * We apologize for missing definitions of types, functions, and data
-    structures.  Since the submission deadline we have corrected some
-    of these faults, but regardless of whether the paper is accepted
-    we would be very grateful for a referee to point out other places
-    where information is missing.
-
-  * We need to say something about Schmidt's paper.
-
-  * We agree with reviewer #1 that our paper is about solid
-    engineering; we do not claim to have made a breakthrough.  To an
-    engineer, 'appears straightforward' is a high compliment.  In the
-    design of software and systems, one wishes always to build the
-    simplest system possible.  A simple design usually seems obvious
-    only in retrospect.  Certainly we believe that the interfaces
-    described in the paper are substantially simpler than the
-    interfaces we described in 2005, and we believe that this
-    simplification required substantial intellectual effort.  But
-    perhaps others could have adapted the 2005 paper to something
-    equally simple with less effort.
-
-  * We are sorry to have given the impression that the library is
-    conceived just to serve GHC and its intermediate language.  We
-    have worked hard to make our library polymorphic so that it can be
-    used with *any* intermediate language, provided only that the
-    language distinguishes control transfers and provides a means to
-    follow control-flow edges.  We hope soon to use the library with
-    representations of machine instructions for the various platforms
-    GHC supports.
-
-    It is true that the *implementation* of the library depends on
-    GHC's internals in a few inessential ways, of which the most
-    important is probably that it uses an efficient implementation of
-    integer maps developed by Chris Okasaki and Andy Gill.
-
-  * We're not sure what Reviewer #3 would accept as evidence for a
-    library's fitness for general purposes.  This evaluation is
-    especially important as we make no claim to theoretical novelty
-    and no claim to enable analyses that cannot be implemented using
-    other methods.  Our claim is that using our library, it is much
-    *easier* to implement analyses and transformations than it is
-    using other compiler infrastructures (e.g., SUIF or vpo, to name
-    two with which we are familiar).  In order to substantiate this
-    claim, we included examples of analyses and optimizations which
-    are already known, so that readers can compare our code with code
-    written for their favorite compiler.  
-
-    To be extra confident in the correctness of the examples, we also
-    included *only* examples which have been implemented and tested as
-    part of GHC's back end.  This decision may have influenced the
-    reviewer's impression that the library is not fit for general
-    purposes.
-
-  * Along with Reviewer #2, we felt that section 7 was not properly
-    explained.  In the process of developing a better explanation, we
-    have rewritten the dataflow engine twice.  We have also rewritten
-    every part of section 7 except the part on 'optimization fuel'.
-    It would be unfair to ask referees to evaluate this new material,
-    but we feel constrained to let the referees know that whether the
-    paper is accepted at ICFP or is submitted to another venue, the
-    section 7 in the submission they have evaluated will not appear.
-
-  * To reviewer #1: if register pressure could be approximated by,
-    e.g., the number of live variables, then it would be a
-    straightforward matter to write a dataflow pass that removes
-    redundant reloads when the number of live variables is small.  In
-    fact our back end takes the opposite approach: we optimistically
-    insert a reload of $x$ only in front of the *first* use of $x$
-    (explaining why we use dataflow and not a syntactic
-    transfomration).  If register pressure leads to a spill, $x$ might
-    be spilled preferentially because we know that that value of $x$
-    is already on the stack, and thus only a reloead is needed.  (We
-    say 'might' because our register-allocation guru, who would know
-    for sure, is on his honeymoon.)
-
-If the paper is accepted, our priorities will be:
-
-  1. To make sure all missing definitions and explanations are
-     accounted for, so that readers can understand the code easily.
-
-  2. To provide a suitable scholarly account of the relationship with
-     Schmidt's work and with abstract interpretation more generally.
-
-  3. To work extra hard on the description of the new implementation
-     (Section 7) since that will not have been reviewed by the program
-     committee. 
-
-  4. Anything else?
diff --git a/paper/refs.txt b/paper/refs.txt
deleted file mode 100644 (file)
index c457718..0000000
+++ /dev/null
@@ -1,78 +0,0 @@
-Andrew W. Appel. 1998. Modern Compiler Implementation. Cambridge
-University Press, Cambridge, UK. Available in three editions: C, Java, and ML.
-
-John Cocke and Ken Kennedy. 1977. An algorithm for
-reduction of operator strength. Communications of the ACM, 20(11): 850--856.
-
-Keith D. Cooper, Timothy J. Harvey, and Ken
-Kennedy. 2001. A simple, fast dominance algorithm. Technical report, Rice
-University. Unpublished report available from http://www.hipersoft.rice.edu/
-grads/publications/dom14.pdf.
-
-Patrick Cousot and Radhia Cousot. 1977 (January).
-Abstract interpretation: A unified lattice model for static analysis of
-programs by construction or approximation of fixpoints. In Conference Record of
-the 4th ACM Symposium on Principles of Programming Languages, pages 238--252.
-
-Patrick Cousot and Radhia Cousot. 1979 (January).
-Systematic design of program analysis frameworks. In Conference Record of the
-6th Annual ACM Symposium on Principles of Programming Languages, pages 269--282.
-
-John B. Kam and Jeffrey D. Ullman. 1976. Global data flow
-analysis and iterative algorithms. Journal of the ACM, 23(1):158--171.
-
-John B. Kam and Jeffrey D. Ullman. 1977. Monotone data
-flow analysis frameworks. Acta Informatica, 7:305--317.
-
-Gary A. Kildall. 1973 (October). A unified approach to global
-program optimization. In Conference Record of the ACM Symposium on Principles
-of Programming Languages, pages 194--206.
-
-Jens Knoop, Oliver Ruething, and Bernhard
-Steffen. 1992. Lazy code motion. Proceedings of the ACM SIGPLAN '92 Conference
-on Programming Language Design and Implementation, in SIGPLAN Notices, 27
-(7):224--234.
-
-Sorin Lerner, David Grove, and Craig
-Chambers. 2002 (January). Composing dataflow analyses and transformations.
-Conference Record of the 29th Annual ACM Symposium on Principles of Programming
-Languages, in SIGPLAN Notices, 31 (1):270--282.
-
-Thomas J. Marlowe and Barbara G. Ryder. 1990.
-Properties of data flow frameworks: a unified model. Acta Informatica, 28
-(2):121--163.
-
-Steven S. Muchnick. 1997. Advanced compiler design and
-implementation. Morgan Kaufmann, San Mateo, CA.
-
-Necula, McPeak, Rahul, and Weimer George C. Necula, Scott
-McPeak, Shree Prakash Rahul, and Westley Weimer. 2002. CIL: Intermediate
-language and tools for analysis and transformation of C programs. In CC '02:
-Proceedings of the 11th International Conference on Compiler Construction,
-pages 213--228.
-
-Norman Ramsey and João Dias. 2005 (September). An
-applicative control-flow graph based on Huet's zipper. In ACM SIGPLAN Workshop
-on ML, pages 101--122.
-
-Colin Runciman. 2010 (June). Finding and increasing PRS
-candidates. Reduceron Memo 50, www.cs.york.ac.uk/fp/reduceron.
-
-David A. Schmidt. 1998. Data flow analysis is model checking of
-abstract interpretations. In ACM, editor, Conference Record of the 25th Annual
-ACM Symposium on Principles of Programming Languages, pages 38--48.
-
-Bernhard Steffen. 1991. Data flow analysis as model checking. In
-TACS '91: Proceedings of the International Conference on Theoretical Aspects of
-Computer Software, pages 346--365.
-
-Vallée-Rai, Gagnon, Hendren, Lam, Pominville, and
-Sundaresan Raja Vallée-Rai, Etienne Gagnon, Laurie J. Hendren, Patrick Lam,
-Patrice Pominville, and Vijay Sundaresan. 2000. Optimizing Java bytecode using
-the Soot framework: Is it feasible? In CC '00: Proceedings of the 9th
-International Conference on Compiler Construction, pages 18--34.
-
-David B. Whalley. 1994 (September). Automatic isolation of
-compiler errors. ACM Transactions on Programming Languages and Systems, 16
-(5):1648--1659.
-
diff --git a/paper/spell.mk b/paper/spell.mk
deleted file mode 100644 (file)
index 91f5579..0000000
+++ /dev/null
@@ -1,21 +0,0 @@
-%-spell:V: %.nw 
-       PATH=/usr/lib/noweb:/usr/local/noweb/lib:$PATH
-       markup $prereq | 
-       sed -e '/^@begin code/,/^@end code/d' -e '/^@quote/,/@endquote/d' |
-       unmarkup |
-       strip-tex-markup |
-       sed '/^\\begin{verbatim}/,/^\\end{verbatim}/d' |
-       # detex -l | spell +okwords.sort | grep -v '[:,&.]' | grep -v '^[0-9A-Z]*$'
-       (sed 's/^/*/' $HOME/okwords.txt; sed 's/^/^/') | ispell -t -a | 
-       sed '/^[*+]/d;/^$/d;s/[0-9][0-9 ]*[0-9]/9/;s/ *[0-9][0-9]*//' | sort -uf
-
-%-texspell:V: %.tex
-       strip-tex-markup $prereq |
-       sed -e '/^\\begin{verbatim}/,/^\\end{verbatim}/d'               \
-            -e '/^\\begin{code}/,/^\\end{code}/d'                       \
-            -e '/^\\begin{smallverbatim}/,/^\\end{smallverbatim}/d'     \
-            -e '/^\\begin{smallcode}/,/^\\end{smallcode}/d'             \
-            -e '/^\\begin{numberedcode}/,/^\\end{numberedcode}/d'       |
-       (sed 's/^/*/' $HOME/okwords.txt; sed 's/^/^/') | ispell -t -a | 
-       sed '/^[*+]/d;/^$/d;s/[0-9][0-9 ]*[0-9]/9/;s/ *[0-9][0-9]*//' | sort -uf
-
diff --git a/paper/xsource b/paper/xsource
deleted file mode 100755 (executable)
index aa2345e..0000000
+++ /dev/null
@@ -1,75 +0,0 @@
-#!/usr/bin/env lua
-
-local shift = '^'   -- prefix of blanks to remove
-
-if arg[1] and arg[1]:find '^%-%d+$' then
-  shift = '^' .. string.rep(' ', -tonumber(arg[1]))
-  table.remove(arg, 1)
-end
-
-local outputs = { } -- map filename to list of lines
-setmetatable(outputs, { __index = function(t, k) local u = {}; t[k] = u; return u end })
-
-local function add_modified_line(lines, l)
-  if l:find '%{ fact_name%s+='
-    or l:find '^%s*%-%- See Note '
-  then
-    return
-  end
-  l = l:gsub('%s*%-%- Note %[.*$', '')
-  l = l:gsub('%s*%-%- I do not understand.*$', '')
-  l = l:gsub('^(%s*),( fact_bot)', '%1{%2')
---  l = l:gsub('^(%s*, fact_join = .*)$', '%1 }')
-  l = l:gsub('%s*%-%-%s%^.*$', '')
-  l = l:gsub('CheckpointMonad', 'CkpointMonad')
-  return table.insert(lines, l)
-end
-
-
-local function shift_left(l, n)
-  l = l:gsub('^' .. string.rep(' ', n), '')
-  return l
-end
-
-for _, file in ipairs(arg) do
-  local outfile, distance
-  for l in io.lines(file) do
-    local action, filename, n = l:match '^%s*%-%-%s%@%s+(%w+)%s+(%S+)%s+%-(%d+)%s*$'
-    if not n then
-      action, filename = l:match '^%s*%-%-%s%@%s+(%w+)%s+(%S+)%s*$'
-      n = action and 0
-    end
-    if action == 'start' then
-      assert(outfile == nil and distance == nil)
-      outfile, distance = filename, n
-    elseif action == 'stop' or action == 'end' then
-      assert(outfile, '@stop without @start: ' .. l)
-      assert(outfile == filename, l .. 'does not match @start ' .. outfile)
-      outfile, distance = nil, nil
-    elseif action ~= nil then
-      error("Unknown action '" .. action .. "' in line " .. l)
-    else
-      if outfile then
-        add_modified_line(outputs[outfile], shift_left(l, distance))
-      end
-    end
-  end
-end
-
-for file, lines in pairs(outputs) do
-  local f = assert(io.open(file, 'w'))
-  local do_shift = true
-  for _, l in ipairs(lines) do
-    if not l:find(shift) then
-      do_shift = false
-      break
-    end
-  end
-  for _, l in ipairs(lines) do
-    f:write(do_shift and l:gsub(shift, '') or l, '\n')
-  end
-  f:close()
-end
-
-      
-      
\ No newline at end of file
index 8388788..7d5a590 100644 (file)
@@ -37,12 +37,10 @@ deepFwdRw f = deepFwdRw3 f f f
 
 -- N.B. rw3, rw3', and rw3a are triples of functions.
 -- But rw and rw' are single functions.
--- @ start comb1.tex
 thenFwdRw :: forall m n f. Monad m 
           => FwdRewrite m n f 
           -> FwdRewrite m n f 
           -> FwdRewrite m n f
--- @ end comb1.tex
 thenFwdRw rw3 rw3' = wrapFR2 thenrw rw3 rw3'
  where
   thenrw :: forall m1 e x t t1.
@@ -56,11 +54,9 @@ thenFwdRw rw3 rw3' = wrapFR2 thenrw rw3 rw3'
      where fwdRes Nothing   = rw' n f
            fwdRes (Just gr) = return $ Just $ fadd_rw rw3' gr
 
--- @ start iterf.tex
 iterFwdRw :: forall m n f. Monad m 
           => FwdRewrite m n f 
           -> FwdRewrite m n f
--- @ end iterf.tex
 iterFwdRw rw3 = wrapFR iter rw3
  where iter :: forall a m1 m2 e x t.
                (Monad m2, Monad m1) =>
@@ -141,12 +137,10 @@ badd_rw :: Monad m
 badd_rw rw2 (g, rw1) = (g, rw1 `thenBwdRw` rw2)
 
 
--- @ start pairf.tex
 pairFwd :: forall m n f f'. Monad m
         => FwdPass m n f
         -> FwdPass m n f' 
         -> FwdPass m n (f, f')
--- @ end pairf.tex
 pairFwd pass1 pass2 = FwdPass lattice transfer rewrite
   where
     lattice = pairLattice (fp_lattice pass1) (fp_lattice pass2)
index ca5eb8c..1447fa3 100644 (file)
@@ -212,27 +212,16 @@ arfGraph pass@FwdPass { fp_lattice = lattice,
     type ARFX thing = forall e x . thing e x -> Fact e f -> m (DG f n e x, Fact x f)
     -}
     graph ::              Graph n e x -> Fact e f -> m (DG f n e x, Fact x f)
--- @ start block.tex -2
-    block :: forall e x . 
-             Block n e x -> f -> m (DG f n e x, Fact x f)
--- @ end block.tex
--- @ start node.tex -4
-    node :: forall e x . (ShapeLifter e x) 
-         => n e x -> f -> m (DG f n e x, Fact x f)
--- @ end node.tex
--- @ start bodyfun.tex
-    body  :: [Label] -> LabelMap (Block n C C)
-          -> Fact C f -> m (DG f n C C, Fact C f)
--- @ end bodyfun.tex
-                    -- Outgoing factbase is restricted to Labels *not* in
-                    -- in the Body; the facts for Labels *in*
-                    -- the Body are in the 'DG f n C C'
--- @ start cat.tex -2
+    block :: forall e x . Block n e x -> f -> m (DG f n e x, Fact x f)
+    node :: forall e x . (ShapeLifter e x) => n e x -> f -> m (DG f n e x, Fact x f)
+    body  :: [Label] -> LabelMap (Block n C C) -> Fact C f -> m (DG f n C C, Fact C f)
+     -- Outgoing factbase is restricted to Labels *not* in
+     -- in the Body; the facts for Labels *in*
+     -- the Body are in the 'DG f n C C'
     cat :: forall e a x f1 f2 f3. 
            (f1 -> m (DG f n e a, f2))
         -> (f2 -> m (DG f n a x, f3))
         -> (f1 -> m (DG f n e x, f3))
--- @ end cat.tex
 
     graph GNil            = \f -> return (dgnil, f)
     graph (GUnit blk)     = block blk
@@ -252,7 +241,6 @@ arfGraph pass@FwdPass { fp_lattice = lattice,
 #endif
 
     -- Lift from nodes to blocks
--- @ start block.tex -2
     block BNil          = \f -> return (dgnil, f)
     block (BlockCO l b)   = node l `cat` block b
     block (BlockCC l b n) = node l `cat` block b `cat` node n
@@ -260,11 +248,9 @@ arfGraph pass@FwdPass { fp_lattice = lattice,
 
     block (BMiddle n)  = node n
     block (BCat b1 b2) = block b1 `cat` block b2
--- @ end block.tex
     block (BSnoc h n)  = block h  `cat` node n
     block (BCons n t)  = node  n  `cat` block t
 
--- @ start node.tex -4
     node n f
      = do { grw <- frewrite rewrite n f
           ; case grw of
@@ -275,16 +261,12 @@ arfGraph pass@FwdPass { fp_lattice = lattice,
                       f'    = fwdEntryFact n f
                   in  arfGraph pass' (fwdEntryLabel n) g f' }
 
--- @ end node.tex
-
     -- | Compose fact transformers and concatenate the resulting
     -- rewritten graphs.
     {-# INLINE cat #-} 
--- @ start cat.tex -2
     cat ft1 ft2 f = do { (g1,f1) <- ft1 f
                        ; (g2,f2) <- ft2 f1
                        ; return (g1 `dgSplice` g2, f2) }
--- @ end cat.tex
     arfx :: forall thing x .
             NonLocal thing
          => (thing C x ->        f -> m (DG f n C x, Fact x f))
@@ -294,10 +276,9 @@ arfGraph pass@FwdPass { fp_lattice = lattice,
      -- joinInFacts adds debugging information
 
 
-                    -- Outgoing factbase is restricted to Labels *not* in
-                    -- in the Body; the facts for Labels *in*
-                    -- the Body are in the 'DG f n C C'
--- @ start bodyfun.tex
+     -- Outgoing factbase is restricted to Labels *not* in
+     -- in the Body; the facts for Labels *in*
+     -- the Body are in the 'DG f n C C'
     body entries blockmap init_fbase
       = fixpoint Fwd lattice do_block entries blockmap init_fbase
       where
@@ -305,8 +286,6 @@ arfGraph pass@FwdPass { fp_lattice = lattice,
                  -> m (DG f n C x, Fact x f)
         do_block b fb = block b entryFact
           where entryFact = getFact lattice (entryLabel b) fb
--- @ end bodyfun.tex
-
 
 -- Join all the incoming facts with bottom.
 -- We know the results _shouldn't change_, but the transfer
@@ -484,9 +463,9 @@ arbGraph pass@BwdPass { bp_lattice  = lattice,
                           ; return (rg, fb) }
      -- joinInFacts adds debugging information
 
-                    -- Outgoing factbase is restricted to Labels *not* in
-                    -- in the Body; the facts for Labels *in*
-                    -- the Body are in the 'DG f n C C'
+     -- Outgoing factbase is restricted to Labels *not* in
+     -- in the Body; the facts for Labels *in*
+     -- the Body are in the 'DG f n C C'
     body entries blockmap init_fbase
       = fixpoint Bwd lattice do_block (map entryLabel (backwardBlockList entries blockmap)) blockmap init_fbase
       where
@@ -568,7 +547,6 @@ class Monad m => FixpointMonad m where
   observeChangedFactBase :: m (Maybe (FactBase f)) -> Maybe (FactBase f)
 -}
 
--- @ start fptype.tex
 data Direction = Fwd | Bwd
 fixpoint :: forall m n f. (CheckpointMonad m, NonLocal n)
  => Direction
@@ -577,8 +555,7 @@ fixpoint :: forall m n f. (CheckpointMonad m, NonLocal n)
  -> [Label]
  -> LabelMap (Block n C C)
  -> (Fact C f -> m (DG f n C C, Fact C f))
--- @ end fptype.tex
--- @ start fpimp.tex
+
 fixpoint direction lat do_block entries blockmap init_fbase
   = do
         -- trace ("fixpoint: " ++ show (case direction of Fwd -> True; Bwd -> False) ++ " " ++ show (mapKeys blockmap) ++ show entries ++ " " ++ show (mapKeys init_fbase)) $ return()
@@ -705,11 +682,10 @@ we'll propagate (x=4) to L4, and nuke the otherwise-good rewriting of L4.
 --          TOTALLY internal to Hoopl; each block is decorated with a fact
 -----------------------------------------------------------------------------
 
--- @ start dg.tex
 type Graph = Graph' Block
 type DG f  = Graph' (DBlock f)
 data DBlock f n e x = DBlock f (Block n e x) -- ^ block decorated with fact
--- @ end dg.tex
+
 instance NonLocal n => NonLocal (DBlock f n) where
   entryLabel (DBlock _ b) = entryLabel b
   successors (DBlock _ b) = successors b
@@ -762,15 +738,12 @@ dgSplice = splice fzCat
 -- Lowering back:
 --  - from fact-like things to facts
 -- Note that the latter two functions depend only on the entry shape.
--- @ start node.tex
 class ShapeLifter e x where
  singletonDG   :: f -> n e x -> DG f n e x
  fwdEntryFact  :: NonLocal n => n e x -> f -> Fact e f
  fwdEntryLabel :: NonLocal n => n e x -> MaybeC e [Label]
  ftransfer :: FwdTransfer n f -> n e x -> f -> Fact x f
- frewrite  :: FwdRewrite m n f -> n e x
-           -> f -> m (Maybe (Graph n e x, FwdRewrite m n f))
--- @ end node.tex
+ frewrite  :: FwdRewrite m n f -> n e x -> f -> m (Maybe (Graph n e x, FwdRewrite m n f))
  bwdEntryFact :: NonLocal n => DataflowLattice f -> n e x -> Fact e f -> f
  btransfer    :: BwdTransfer n f -> n e x -> Fact x f -> f
  brewrite     :: BwdRewrite m n f -> n e x
diff --git a/src/Compiler/Hoopl/DataflowFold.hs b/src/Compiler/Hoopl/DataflowFold.hs
deleted file mode 100644 (file)
index c49bb28..0000000
+++ /dev/null
@@ -1,712 +0,0 @@
-{-# LANGUAGE CPP, RankNTypes, ScopedTypeVariables, GADTs, TypeFamilies, MultiParamTypeClasses #-}
-#if __GLASGOW_HASKELL__ >= 701
-{-# LANGUAGE Safe #-}
-#endif
-
-{- Notes about the genesis of Hoopl7
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-Hoopl7 has the following major chages
-
-a) GMany has symmetric entry and exit
-b) GMany closed-entry does not record a BlockId
-c) GMany open-exit does not record a BlockId
-d) The body of a GMany is called Body
-e) A Body is just a list of blocks, not a map. I've argued
-   elsewhere that this is consistent with (c)
-
-A consequence is that Graph is no longer an instance of NonLocal,
-but nevertheless I managed to keep the ARF and ARB signatures
-nice and uniform.
-
-This was made possible by
-
-* FwdTransfer looks like this:
-    type FwdTransfer n f
-      = forall e x. n e x -> Fact e f -> Fact x f 
-    type family   Fact x f :: *
-    type instance Fact C f = FactBase f
-    type instance Fact O f = f
-
-  Note that the incoming fact is a Fact (not just 'f' as in Hoopl5,6).
-  It's up to the *transfer function* to look up the appropriate fact
-  in the FactBase for a closed-entry node.  Example:
-       constProp (Label l) fb = lookupFact fb l
-  That is how Hoopl can avoid having to know the block-id for the
-  first node: it defers to the client.
-
-  [Side note: that means the client must know about 
-  bottom, in case the looupFact returns Nothing]
-
-* Note also that FwdTransfer *returns* a Fact too;
-  that is, the types in both directions are symmetrical.
-  Previously we returned a [(BlockId,f)] but I could not see
-  how to make everything line up if we do this.
-
-  Indeed, the main shortcoming of Hoopl7 is that we are more
-  or less forced into this uniform representation of the facts
-  flowing into or out of a closed node/block/graph, whereas
-  previously we had more flexibility.
-
-  In exchange the code is neater, with fewer distinct types.
-  And morally a FactBase is equivalent to [(BlockId,f)] and
-  nearly equivalent to (BlockId -> f).
-
-* I've realised that forwardBlockList and backwardBlockList
-  both need (NonLocal n), and that goes everywhere.
-
-* I renamed BlockId to Label
--}
-
-module Compiler.Hoopl.DataflowFold
-  ( DataflowLattice(..), JoinFun, OldFact(..), NewFact(..), Fact
-  , ChangeFlag(..), changeIf
-  , FwdPass(..), FwdTransfer, mkFTransfer, mkFTransfer', getFTransfers
-  , FwdRes(..),  FwdRewrite,  mkFRewrite,  mkFRewrite',  getFRewrites
-  , BwdPass(..), BwdTransfer, mkBTransfer, mkBTransfer', getBTransfers
-  , BwdRes(..),  BwdRewrite,  mkBRewrite,  mkBRewrite',  getBRewrites
-  , analyzeAndRewriteFwd,  analyzeAndRewriteBwd
-  )
-where
-
-import Data.Maybe
-
-import Compiler.Hoopl.Fuel
-import Compiler.Hoopl.Graph
-import Compiler.Hoopl.MkGraph
-import Compiler.Hoopl.Label
-import Compiler.Hoopl.Util
-
------------------------------------------------------------------------------
---             DataflowLattice
------------------------------------------------------------------------------
-
-data DataflowLattice a = DataflowLattice  
- { fact_name       :: String          -- Documentation
- , fact_bot        :: a               -- Lattice bottom element
- , fact_join       :: JoinFun a       -- Lattice join plus change flag
-                                      -- (changes iff result > old fact)
- }
--- ^ A transfer function might want to use the logging flag
--- to control debugging, as in for example, it updates just one element
--- in a big finite map.  We don't want Hoopl to show the whole fact,
--- and only the transfer function knows exactly what changed.
-
-type JoinFun a = Label -> OldFact a -> NewFact a -> (ChangeFlag, a)
-  -- the label argument is for debugging purposes only
-newtype OldFact a = OldFact a
-newtype NewFact a = NewFact a
-
-data ChangeFlag = NoChange | SomeChange deriving (Eq, Ord)
-changeIf :: Bool -> ChangeFlag
-changeIf changed = if changed then SomeChange else NoChange
-
-
------------------------------------------------------------------------------
---             Analyze and rewrite forward: the interface
------------------------------------------------------------------------------
-
-data FwdPass n f
-  = FwdPass { fp_lattice  :: DataflowLattice f
-            , fp_transfer :: FwdTransfer n f
-            , fp_rewrite  :: FwdRewrite n f }
-
-newtype FwdTransfer n f 
-  = FwdTransfers { getFTransfers ::
-                     ( n C O -> f -> f
-                     , n O O -> f -> f
-                     , n O C -> f -> FactBase f
-                     ) }
-
-newtype FwdRewrite n f 
-  = FwdRewrites { getFRewrites ::
-                    ( n C O -> f -> Maybe (FwdRes n f C O)
-                    , n O O -> f -> Maybe (FwdRes n f O O)
-                    , n O C -> f -> Maybe (FwdRes n f O C)
-                    ) }
-data FwdRes n f e x = FwdRes (AGraph n e x) (FwdRewrite n f)
-  -- result of a rewrite is a new graph and a (possibly) new rewrite function
-
-mkFTransfer :: (n C O -> f -> f)
-            -> (n O O -> f -> f)
-            -> (n O C -> f -> FactBase f)
-            -> FwdTransfer n f
-mkFTransfer f m l = FwdTransfers (f, m, l)
-
-mkFTransfer' :: (forall e x . n e x -> f -> Fact x f) -> FwdTransfer n f
-mkFTransfer' f = FwdTransfers (f, f, f)
-
-mkFRewrite :: (n C O -> f -> Maybe (FwdRes n f C O))
-           -> (n O O -> f -> Maybe (FwdRes n f O O))
-           -> (n O C -> f -> Maybe (FwdRes n f O C))
-           -> FwdRewrite n f
-mkFRewrite f m l = FwdRewrites (f, m, l)
-
-mkFRewrite' :: (forall e x . n e x -> f -> Maybe (FwdRes n f e x)) -> FwdRewrite n f
-mkFRewrite' f = FwdRewrites (f, f, f)
-
-
-type family   Fact x f :: *
-type instance Fact C f = FactBase f
-type instance Fact O f = f
-
--- | if the graph being analyzed is open at the entry, there must
---   be no other entry point, or all goes horribly wrong...
-analyzeAndRewriteFwd
-   :: forall n f e x entries. (NonLocal n, LabelsPtr entries)
-   => FwdPass n f
-   -> MaybeC e entries
-   -> Graph n e x -> Fact e f
-   -> FuelMonad (Graph n e x, FactBase f, MaybeO x f)
-analyzeAndRewriteFwd pass entries g f =
-  do (rg, fout) <- arfGraph pass (nilBefore g) (fmap targetLabels entries) g f
-     let (g', fb) = normalizeGraph rg
-     return (g', fb, distinguishedExitFact g' fout)
- where nilBefore (GMany NothingO _ _) = rgnilC
-       nilBefore (GMany (JustO _) _ _) = rgnil
-       nilBefore GNil = rgnil
-       nilBefore (GUnit _) = rgnil
-       nilBefore :: Graph n e x -> RG f n e e
-
-distinguishedExitFact :: forall n e x f . Graph n e x -> Fact x f -> MaybeO x f
-distinguishedExitFact g f = maybe g
-    where maybe :: Graph n e x -> MaybeO x f
-          maybe GNil       = JustO f
-          maybe (GUnit {}) = JustO f
-          maybe (GMany _ _ x) = case x of NothingO -> NothingO
-                                          JustO _  -> JustO f
-
-----------------------------------------------------------------
---       Forward Implementation
-----------------------------------------------------------------
-
-
-type FM = FuelMonad
-
-type Entries e = MaybeC e [Label]
-
-type RGPair f n e x = (RG f n e x, Fact x f)
-
-
-arfGraph :: forall n f e a x .
-            (NonLocal n)
-         => FwdPass n f
-         -> RG f n e a
-         -> Entries a -> Graph n a x -> Fact a f -> FM (RG f n e x, Fact x f)
-arfGraph pass head entries g f = graph g (head, f)
- where
-   graph :: Graph n a x -> RGPair f n e a -> FM (RGPair f n e x)
-   block :: forall e a x . Block n a x -> (RG f n e a, f) -> FM (RGPair f n e x)
-   node  :: forall e a x . (ShapeLifter a x) 
-                        => n a x -> (RG f n e a, f) -> FM (RGPair f n e x)
-   body  :: forall e . [Label] -> Body n -> (RGPair f n e C) -> FM (RGPair f n e C) 
-                   -- Outgoing factbase is restricted to Labels *not* in
-                   -- in the Body; the facts for Labels *in*
-                   -- the Body are in the 'RG f n C C'
-
-   cat :: forall e a b x info info' info''.
-          ((RG f n e a, info)  -> FuelMonad (RG f n e b, info'))
-       -> ((RG f n e b, info') -> FuelMonad (RG f n e x, info''))
-       -> ((RG f n e a, info)  -> FuelMonad (RG f n e x, info''))
-
-   cat ft1 ft2 (g, f) = ft1 (g, f) >>= ft2
-
-   graph GNil            = return
-   graph (GUnit blk)     = block blk
-   graph (GMany e bdy x) = eb e bdy `cat` exit x
-    where
-     eb   :: MaybeO a (Block n O C) -> Body n -> (RGPair f n e a) -> FM (RGPair f n e C)
-     exit :: MaybeO x (Block n C O)           -> (RGPair f n e C) -> FM (RGPair f n e x)
-     exit (JustO blk) = arfx block blk
-     exit NothingO    = return
-     eb entry bdy = c entries entry
-      where c :: MaybeC a [Label] -> MaybeO a (Block n O C)
-              -> (RGPair f n e a) -> FM (RGPair f n e C)
-            c NothingC (JustO entry)   = block entry `cat` body (successors entry) bdy
-            c (JustC entries) NothingO = body entries bdy
-
-   -- Lift from nodes to blocks
-   block (BFirst  n)  = node n
-   block (BMiddle n)  = node n
-   block (BLast   n)  = node n
-   block (BCat b1 b2) = block b1 `cat` block b2
-   block (BSnoc h n)  = block h  `cat` node n
-   block (BCons n t)  = node  n  `cat` block t
-   block (BClosed h t)= block h  `cat` block t
-
-   node thenode (head, f)
-     = do { mb_g <- withFuel (frewrite pass thenode f)
-          ; case mb_g of
-              Nothing -> return (spliceRgNode head f thenode,
-                                 ftransfer pass thenode f)
-              Just (FwdRes ag rw) ->
-                  do { g <- graphOfAGraph ag
-                     ; let pass' = pass { fp_rewrite = rw }
-                     ; arfGraph pass' head (entry thenode) g (elift thenode f) } }
-
-   -- | Compose fact transformers and concatenate the resulting
-   -- rewritten graphs.
-   {-# INLINE cat #-} 
-
-   arfx :: forall thing e x .
-           NonLocal thing
-        => (thing C x -> (RG f n e C,        f) -> FM (RGPair f n e x))
-        -> (thing C x -> (RG f n e C, Fact C f) -> FM (RGPair f n e x))
-   arfx arf thing (h, fb) = 
-     arf thing (h, fromJust $ lookupFact (joinInFacts lattice fb) $ entryLabel thing)
-    where lattice = fp_lattice pass
-    -- joinInFacts adds debugging information
-
-
-                   -- Outgoing factbase is restricted to Labels *not* in
-                   -- in the Body; the facts for Labels *in*
-                   -- the Body are in the 'RG f n C C'
-   body entries blocks (h, init_fbase)
-       = do { (body', fb) <- fix; return (h `rgCat` body', fb) }
-     where
-       fix = fixpoint True (fp_lattice pass) do_block init_fbase $
-             forwardBlockList entries blocks
-       do_block b f = do (g, fb) <- block b (rgnilC, lookupF pass (entryLabel b) f)
-                         return (g, factBaseList fb)
-
-
--- Join all the incoming facts with bottom.
--- We know the results _shouldn't change_, but the transfer
--- functions might, for example, generate some debugging traces.
-joinInFacts :: DataflowLattice f -> FactBase f -> FactBase f
-joinInFacts (DataflowLattice {fact_bot = bot, fact_join = fj}) fb =
-  mkFactBase $ map botJoin $ factBaseList fb
-    where botJoin (l, f) = (l, snd $ fj l (OldFact bot) (NewFact f))
-
-
-forwardBlockList :: (NonLocal n, LabelsPtr entry)
-                 => entry -> Body n -> [Block n C C]
--- This produces a list of blocks in order suitable for forward analysis,
--- along with the list of Labels it may depend on for facts.
-forwardBlockList entries (Body blks) = postorder_dfs_from blks entries
-
------------------------------------------------------------------------------
---             Backward analysis and rewriting: the interface
------------------------------------------------------------------------------
-
-data BwdPass n f
-  = BwdPass { bp_lattice  :: DataflowLattice f
-            , bp_transfer :: BwdTransfer n f
-            , bp_rewrite  :: BwdRewrite n f }
-
-newtype BwdTransfer n f 
-  = BwdTransfers { getBTransfers ::
-                     ( n C O -> f          -> f
-                     , n O O -> f          -> f
-                     , n O C -> FactBase f -> f
-                     ) }
-newtype BwdRewrite n f 
-  = BwdRewrites { getBRewrites ::
-                    ( n C O -> f          -> Maybe (BwdRes n f C O)
-                    , n O O -> f          -> Maybe (BwdRes n f O O)
-                    , n O C -> FactBase f -> Maybe (BwdRes n f O C)
-                    ) }
-data BwdRes n f e x = BwdRes (AGraph n e x) (BwdRewrite n f)
-
-mkBTransfer :: (n C O -> f -> f) -> (n O O -> f -> f) ->
-               (n O C -> FactBase f -> f) -> BwdTransfer n f
-mkBTransfer f m l = BwdTransfers (f, m, l)
-
-mkBTransfer' :: (forall e x . n e x -> Fact x f -> f) -> BwdTransfer n f
-mkBTransfer' f = BwdTransfers (f, f, f)
-
-mkBRewrite :: (n C O -> f          -> Maybe (BwdRes n f C O))
-           -> (n O O -> f          -> Maybe (BwdRes n f O O))
-           -> (n O C -> FactBase f -> Maybe (BwdRes n f O C))
-           -> BwdRewrite n f
-mkBRewrite f m l = BwdRewrites (f, m, l)
-
-mkBRewrite' :: (forall e x . n e x -> Fact x f -> Maybe (BwdRes n f e x)) -> BwdRewrite n f
-mkBRewrite' f = BwdRewrites (f, f, f)
-
-
------------------------------------------------------------------------------
---             Backward implementation
------------------------------------------------------------------------------
-
-type ARB' n f thing e x
-  = BwdPass n f -> thing e x -> Fact x f -> FuelMonad (RG f n e x, f)
-
-type ARB thing n = forall f e x. ARB' n f thing e x 
-
-arbNode :: (NonLocal n, ShapeLifter e x) => ARB' n f n e x
--- Lifts (BwdTransfer,BwdRewrite) to ARB_Node; 
--- this time we do rewriting as well. 
--- The ARB_Graph parameters specifies what to do with the rewritten graph
-arbNode pass node f
-  = do { mb_g <- withFuel (brewrite pass node f)
-       ; case mb_g of
-           Nothing -> return (rgunit entry_f (unit node), entry_f)
-                    where entry_f  = btransfer pass node f
-          Just (BwdRes ag rw) -> do { g <- graphOfAGraph ag
-                                     ; let pass' = pass { bp_rewrite = rw }
-                                     ; (g, f) <- arbGraph pass' g f
-                                     ; return (g, elower (bp_lattice pass) node f)} }
-
-arbBlock :: NonLocal n => ARB (Block n) n
--- Lift from nodes to blocks
-arbBlock pass (BFirst  node)  = arbNode pass node
-arbBlock pass (BMiddle node)  = arbNode pass node
-arbBlock pass (BLast   node)  = arbNode pass node
-arbBlock pass (BCat b1 b2)    = arbCat arbBlock arbBlock pass b1 b2
-arbBlock pass (BSnoc h n)     = arbCat arbBlock arbNode  pass h n
-arbBlock pass (BCons n t)     = arbCat arbNode  arbBlock pass n t
-arbBlock pass (BClosed h t)   = arbCat arbBlock arbBlock pass h t
-
-arbCat :: NonLocal n => ARB' n f thing1 e O -> ARB' n f thing2 O x
-       -> BwdPass n f -> thing1 e O -> thing2 O x
-       -> Fact x f -> FuelMonad (RG f n e x, f)
-arbCat arb1 arb2 pass thing1 thing2 f = do { (g2,f2) <- arb2 pass thing2 f
-                                           ; (g1,f1) <- arb1 pass thing1 f2
-                                           ; return (g1 `rgCat` g2, f1) }
-
-arbBody :: NonLocal n
-        => BwdPass n f -> Body n -> FactBase f
-        -> FuelMonad (RG f n C C, FactBase f)
-arbBody pass blocks init_fbase
-  = fixpoint False (bp_lattice pass) do_block init_fbase $
-    backwardBlockList blocks 
-  where
-    do_block b f = do (g, f) <- arbBlock pass b f
-                      return (g, [(entryLabel b, f)])
-
-arbGraph :: NonLocal n
-         => BwdPass n f -> Graph n e x -> Fact x f
-         -> FuelMonad (RG f n e x, Fact e f)
-arbGraph _    GNil        f = return (rgnil, f)
-arbGraph pass (GUnit blk) f = arbBlock pass blk f
-arbGraph pass (GMany NothingO body NothingO) f
-  = do { (body', fb) <- arbBody pass body f
-       ; return (body', fb) }
-arbGraph pass (GMany NothingO body (JustO exit)) f
-  = do { (exit', fx) <- arbBlock pass exit f
-       ; (body', fb) <- arbBody  pass body $
-                          joinInFacts (bp_lattice pass) $ mkFactBase [(entryLabel exit, fx)]
-       ; return (body' `rgCat` exit', fb) }
-arbGraph pass (GMany (JustO entry) body NothingO) f
-  = do { (body', fb)  <- arbBody  pass body f
-       ; (entry', fe) <- arbBlock pass entry fb
-       ; return (entry' `rgCat` body', fe) }
-arbGraph pass (GMany (JustO entry) body (JustO exit)) f
-  = do { (exit', fx)  <- arbBlock pass exit f
-       ; (body', fb)  <- arbBody  pass body $
-                           joinInFacts (bp_lattice pass) $ mkFactBase [(entryLabel exit, fx)]
-       ; (entry', fe) <- arbBlock pass entry fb
-       ; return (entry' `rgCat` body' `rgCat` exit', fe) }
-
-backwardBlockList :: NonLocal n => Body n -> [Block n C C]
--- This produces a list of blocks in order suitable for backward analysis,
--- along with the list of Labels it may depend on for facts.
-backwardBlockList body = reachable ++ missing
-  where reachable = reverse $ forwardBlockList entries body
-        entries = externalEntryLabels body
-        all = bodyList body
-        missingLabels =
-            mkLabelSet (map fst all) `minusLabelSet`
-            mkLabelSet (map entryLabel reachable)
-        missing = map snd $ filter (flip elemLabelSet missingLabels . fst) all
-
-{-
-
-The forward and backward dataflow analyses now use postorder depth-first
-order for faster convergence.
-
-The forward and backward cases are not dual.  In the forward case, the
-entry points are known, and one simply traverses the body blocks from
-those points.  In the backward case, something is known about the exit
-points, but this information is essentially useless, because we don't
-actually have a dual graph (that is, one with edges reversed) to
-compute with.  (Even if we did have a dual graph, it would not avail
-us---a backward analysis must include reachable blocks that don't
-reach the exit, as in a procedure that loops forever and has side
-effects.)
-
-Since in the general case, no information is available about entry
-points, I have put in a horrible hack.  First, I assume that every
-label defined but not used is an entry point.  Then, because an entry
-point might also be a loop header, I add, in arbitrary order, all the
-remaining "missing" blocks.  Needless to say, I am not pleased.  
-I am not satisfied.  I am not Senator Morgan.
-
-Wait! I believe that the Right Thing here is to require that anyone
-wishing to analyze a graph closed at the entry provide a way of
-determining the entry points, if any, of that graph.  This requirement
-can apply equally to forward and backward analyses; I believe that
-using the input FactBase to determine the entry points of a closed
-graph is *also* a hack.
-
-NR
-
--}
-
-
--- | if the graph being analyzed is open at the exit, I don't
---   quite understand the implications of possible other exits
-analyzeAndRewriteBwd
-   :: forall n f e x. NonLocal n
-   => BwdPass n f
-   -> Graph n e x -> Fact x f
-   -> FuelMonad (Graph n e x, FactBase f, MaybeO e f)
-analyzeAndRewriteBwd pass g f =
-  do (rg, fout) <- arbGraph pass g f
-     let (g', fb) = normalizeGraph rg
-     return (g', fb, distinguishedEntryFact g' fout)
-
-distinguishedEntryFact :: forall n e x f . Graph n e x -> Fact e f -> MaybeO e f
-distinguishedEntryFact g f = maybe g
-    where maybe :: Graph n e x -> MaybeO e f
-          maybe GNil       = JustO f
-          maybe (GUnit {}) = JustO f
-          maybe (GMany e _ _) = case e of NothingO -> NothingO
-                                          JustO _  -> JustO f
-
------------------------------------------------------------------------------
---      fixpoint: finding fixed points
------------------------------------------------------------------------------
-
-data TxFactBase n f
-  = TxFB { tfb_fbase :: FactBase f
-         , tfb_rg  :: RG f n C C -- Transformed blocks
-         , tfb_cha   :: ChangeFlag
-         , tfb_lbls  :: LabelSet }
- -- Note [TxFactBase change flag]
- -- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- -- Set the tfb_cha flag iff 
- --   (a) the fact in tfb_fbase for or a block L changes
- --   (b) L is in tfb_lbls.
- -- The tfb_lbls are all Labels of the *original* 
- -- (not transformed) blocks
-
-updateFact :: DataflowLattice f -> LabelSet -> (Label, f)
-           -> (ChangeFlag, FactBase f) 
-           -> (ChangeFlag, FactBase f)
--- See Note [TxFactBase change flag]
-updateFact lat lbls (lbl, new_fact) (cha, fbase)
-  | NoChange <- cha2        = (cha,        fbase)
-  | lbl `elemLabelSet` lbls = (SomeChange, new_fbase)
-  | otherwise               = (cha,        new_fbase)
-  where
-    (cha2, res_fact) -- Note [Unreachable blocks]
-       = case lookupFact fbase lbl of
-           Nothing -> (SomeChange, snd $ join $ fact_bot lat)  -- Note [Unreachable blocks]
-           Just old_fact -> join old_fact
-         where join old_fact = fact_join lat lbl (OldFact old_fact) (NewFact new_fact)
-    new_fbase = extendFactBase fbase lbl res_fact
-
-fixpoint :: forall block n f. (NonLocal n, NonLocal (block n))
-         => Bool       -- Going forwards?
-         -> DataflowLattice f
-         -> (block n C C -> FactBase f
-              -> FuelMonad (RG f n C C, [(Label, f)]))
-         -> FactBase f 
-         -> [block n C C]
-         -> FuelMonad (RG f n C C, FactBase f)
-fixpoint is_fwd lat do_block init_fbase untagged_blocks
-  = do { fuel <- getFuel  
-       ; tx_fb <- loop fuel init_fbase
-       ; return (tfb_rg tx_fb, 
-                 tfb_fbase tx_fb `delFromFactBase` map fst blocks) }
-            -- The successors of the Graph are the the Labels for which
-            -- we have facts, that are *not* in the blocks of the graph
-  where
-    blocks = map tag untagged_blocks
-     where tag b = ((entryLabel b, b), if is_fwd then [entryLabel b] else successors b)
-
-    tx_blocks :: [((Label, block n C C), [Label])]   -- I do not understand this type
-              -> TxFactBase n f -> FuelMonad (TxFactBase n f)
-    tx_blocks []              tx_fb = return tx_fb
-    tx_blocks (((lbl,blk), deps):bs) tx_fb = tx_block lbl blk deps tx_fb >>= tx_blocks bs
-     -- "deps" == Labels the block may _depend_ upon for facts
-
-    tx_block :: Label -> block n C C -> [Label]
-             -> TxFactBase n f -> FuelMonad (TxFactBase n f)
-    tx_block lbl blk deps tx_fb@(TxFB { tfb_fbase = fbase, tfb_lbls = lbls
-                                      , tfb_rg = blks, tfb_cha = cha })
-      | is_fwd && not (lbl `elemFactBase` fbase)
-      = return tx_fb {tfb_lbls = lbls `unionLabelSet` mkLabelSet deps} -- Note [Unreachable blocks]
-      | otherwise
-      = do { (rg, out_facts) <- do_block blk fbase
-           ; let (cha',fbase') 
-                   = foldr (updateFact lat lbls) (cha,fbase) out_facts
-                 lbls' = lbls `unionLabelSet` mkLabelSet deps
-           ; return (TxFB { tfb_lbls  = lbls'
-                          , tfb_rg    = rg `rgCat` blks
-                          , tfb_fbase = fbase', tfb_cha = cha' }) }
-
-    loop :: Fuel -> FactBase f -> FuelMonad (TxFactBase n f)
-    loop fuel fbase 
-      = do { let init_tx_fb = TxFB { tfb_fbase = fbase
-                                   , tfb_cha   = NoChange
-                                   , tfb_rg    = rgnilC
-                                   , tfb_lbls  = emptyLabelSet }
-           ; tx_fb <- tx_blocks blocks init_tx_fb
-           ; case tfb_cha tx_fb of
-               NoChange   -> return tx_fb
-               SomeChange -> do { setFuel fuel
-                                ; loop fuel (tfb_fbase tx_fb) } }
-
-{- Note [Unreachable blocks]
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-A block that is not in the domain of tfb_fbase is "currently unreachable".
-A currently-unreachable block is not even analyzed.  Reason: consider 
-constant prop and this graph, with entry point L1:
-  L1: x:=3; goto L4
-  L2: x:=4; goto L4
-  L4: if x>3 goto L2 else goto L5
-Here L2 is actually unreachable, but if we process it with bottom input fact,
-we'll propagate (x=4) to L4, and nuke the otherwise-good rewriting of L4.
-
-* If a currently-unreachable block is not analyzed, then its rewritten
-  graph will not be accumulated in tfb_rg.  And that is good:
-  unreachable blocks simply do not appear in the output.
-
-* Note that clients must be careful to provide a fact (even if bottom)
-  for each entry point. Otherwise useful blocks may be garbage collected.
-
-* Note that updateFact must set the change-flag if a label goes from
-  not-in-fbase to in-fbase, even if its fact is bottom.  In effect the
-  real fact lattice is
-       UNR
-       bottom
-       the points above bottom
-
-* Even if the fact is going from UNR to bottom, we still call the
-  client's fact_join function because it might give the client
-  some useful debugging information.
-
-* All of this only applies for *forward* fixpoints.  For the backward
-  case we must treat every block as reachable; it might finish with a
-  'return', and therefore have no successors, for example.
--}
-
------------------------------------------------------------------------------
---     RG: an internal data type for graphs under construction
---          TOTALLY internal to Hoopl; each block carries its fact
------------------------------------------------------------------------------
-
-type RG      f n e x = Graph' (FBlock f) n e x
-data FBlock f n e x = FBlock f (Block n e x)
-instance NonLocal n => NonLocal (FBlock f n) where
-  entryLabel (FBlock _ b) = entryLabel b
-  successors (FBlock _ b) = successors b
-
---- constructors
-
-rgnil  :: RG f n O O
-rgnilC :: RG f n C C
-rgunit :: NonLocal n => f -> Block n e x -> RG f n e x
-rgCat  :: NonLocal n => RG f n e a -> RG f n a x -> RG f n e x
-
----- observers
-
-type GraphWithFacts n f e x = (Graph n e x, FactBase f)
-  -- A Graph together with the facts for that graph
-  -- The domains of the two maps should be identical
-
-normalizeGraph :: forall n f e x .
-                  NonLocal n => RG f n e x -> GraphWithFacts n f e x
-
-normalizeGraph g = (graphMapBlocks dropFact g, facts g)
-    where dropFact (FBlock _ b) = b
-          facts :: RG f n e x -> FactBase f
-          facts GNil = noFacts
-          facts (GUnit _) = noFacts
-          facts (GMany _ body exit) = bodyFacts body `unionFactBase` exitFacts exit
-          exitFacts :: MaybeO x (FBlock f n C O) -> FactBase f
-          exitFacts NothingO = noFacts
-          exitFacts (JustO (FBlock f b)) = mkFactBase [(entryLabel b, f)]
-          bodyFacts :: Body (FBlock f) n -> FactBase f
-          bodyFacts body = foldLabelMap f noFacts body
-            where f (FBlock f b) fb = extendFactBase fb (entryLabel b) f
-
---- implementation of the constructors (boring)
-
-rgnil  = GNil
-rgnilC = GMany NothingO emptyMap NothingO
-
-rgunit f b@(BFirst  {}) = gUnitCO (FBlock f b)
-rgunit f b@(BMiddle {}) = gUnitOO (FBlock f b)
-rgunit f b@(BLast   {}) = gUnitOC (FBlock f b)
-rgunit f b@(BCat {})    = gUnitOO (FBlock f b)
-rgunit f b@(BSnoc {})   = gUnitCO (FBlock f b)
-rgunit f b@(BCons {})   = gUnitOC (FBlock f b)
-rgunit f b@(BClosed {}) = gUnitCC (FBlock f b)
-
-rgCat = U.splice fzCat
-  where fzCat (FBlock f b1) (FBlock _ b2) = FBlock f (b1 `U.cat` b2)
-
-----------------------------------------------------------------
---       Utilities
-----------------------------------------------------------------
-
--- Lifting based on shape:
---  - from nodes to blocks
---  - from facts to fact-like things
--- Lowering back:
---  - from fact-like things to facts
--- Note that the latter two functions depend only on the entry shape.
-class ShapeLifter e x where
-  unit      :: n e x -> Block n e x
-  elift     :: NonLocal n =>                      n e x -> f -> Fact e f
-  elower    :: NonLocal n => DataflowLattice f -> n e x -> Fact e f -> f
-  ftransfer :: FwdPass n f -> n e x -> f        -> Fact x f
-  btransfer :: BwdPass n f -> n e x -> Fact x f -> f
-  frewrite  :: FwdPass n f -> n e x -> f        -> Maybe (FwdRes n f e x)
-  brewrite  :: BwdPass n f -> n e x -> Fact x f -> Maybe (BwdRes n f e x)
-  spliceRgNode :: NonLocal n => RG f n a e -> f -> n e x -> RG f n a x
-  entry     :: NonLocal n => n e x -> Entries e
-
-instance ShapeLifter C O where
-  unit            = BFirst
-  elift      n f  = mkFactBase [(entryLabel n, f)]
-  elower lat n fb = getFact lat (entryLabel n) fb
-  ftransfer (FwdPass {fp_transfer = FwdTransfers (ft, _, _)}) n f = ft n f
-  btransfer (BwdPass {bp_transfer = BwdTransfers (bt, _, _)}) n f = bt n f
-  frewrite  (FwdPass {fp_rewrite  = FwdRewrites  (fr, _, _)}) n f = fr n f
-  brewrite  (BwdPass {bp_rewrite  = BwdRewrites  (br, _, _)}) n f = br n f
-  spliceRgNode (GMany e body NothingO) f n = GMany e body x
-     where x = JustO $ FBlock f $ BFirst n
-  entry n = JustC [entryLabel n]
-
-instance ShapeLifter O O where
-  unit         = BMiddle
-  elift    _ f = f
-  elower _ _ f = f
-  ftransfer (FwdPass {fp_transfer = FwdTransfers (_, ft, _)}) n f = ft n f
-  btransfer (BwdPass {bp_transfer = BwdTransfers (_, bt, _)}) n f = bt n f
-  frewrite  (FwdPass {fp_rewrite  = FwdRewrites  (_, fr, _)}) n f = fr n f
-  brewrite  (BwdPass {bp_rewrite  = BwdRewrites  (_, br, _)}) n f = br n f
-  spliceRgNode (GMany e body (JustO (FBlock f x))) _ n = GMany e body (JustO x')
-     where x' = FBlock f $ BSnoc x n
-  spliceRgNode (GNil) f n = GUnit $ FBlock f $ BMiddle n
-  spliceRgNode (GUnit (FBlock f b)) _ n = GUnit $ FBlock f $ b `BCat` BMiddle n
-  entry _ = NothingC
-
-instance ShapeLifter O C where
-  unit         = BLast
-  elift    _ f = f
-  elower _ _ f = f
-  ftransfer (FwdPass {fp_transfer = FwdTransfers (_, _, ft)}) n f = ft n f
-  btransfer (BwdPass {bp_transfer = BwdTransfers (_, _, bt)}) n f = bt n f
-  frewrite  (FwdPass {fp_rewrite  = FwdRewrites  (_, _, fr)}) n f = fr n f
-  brewrite  (BwdPass {bp_rewrite  = BwdRewrites  (_, _, br)}) n f = br n f
-  spliceRgNode (GMany e b1 (JustO (FBlock f x))) _ n = GMany e body' NothingO
-     where body' = unionLabelMap b1 b2
-           b2 = addBlock (FBlock f $ BClosed x $ BLast n) emptyMap
-  spliceRgNode (GNil) f n = GMany e emptyMap NothingO
-     where e = JustO $ FBlock f $ BLast n
-  spliceRgNode (GUnit (FBlock f b)) _ n = GMany e emptyMap NothingO
-     where e = JustO $ FBlock f (b `U.cat` BLast n)
-  entry _ = NothingC
-
--- Fact lookup: the fact `orelse` bottom
-lookupF :: FwdPass n f -> Label -> FactBase f -> f
-lookupF = getFact . fp_lattice
-
-getFact  :: DataflowLattice f -> Label -> FactBase f -> f
-getFact lat l fb = case lookupFact fb l of Just  f -> f
-                                           Nothing -> fact_bot lat
diff --git a/src/Compiler/Hoopl/OldDataflow.hs b/src/Compiler/Hoopl/OldDataflow.hs
deleted file mode 100644 (file)
index f750123..0000000
+++ /dev/null
@@ -1,698 +0,0 @@
-{-# LANGUAGE CPP, RankNTypes, ScopedTypeVariables, GADTs, TypeFamilies, MultiParamTypeClasses #-}
-{-# OPTIONS_GHC -fno-warn-incomplete-patterns #-} -- bug in GHC
-#if __GLASGOW_HASKELL__ >= 701
-{-# LANGUAGE Safe #-}
-#endif
-
-{- Notes about the genesis of Hoopl7
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-Hoopl7 has the following major chages
-
-a) GMany has symmetric entry and exit
-b) GMany closed-entry does not record a BlockId
-c) GMany open-exit does not record a BlockId
-d) The body of a GMany is called Body
-e) A Body is just a list of blocks, not a map. I've argued
-   elsewhere that this is consistent with (c)
-
-A consequence is that Graph is no longer an instance of NonLocal,
-but nevertheless I managed to keep the ARF and ARB signatures
-nice and uniform.
-
-This was made possible by
-
-* FwdTransfer looks like this:
-    type FwdTransfer n f
-      = forall e x. n e x -> Fact e f -> Fact x f 
-    type family   Fact x f :: *
-    type instance Fact C f = FactBase f
-    type instance Fact O f = f
-
-  Note that the incoming fact is a Fact (not just 'f' as in Hoopl5,6).
-  It's up to the *transfer function* to look up the appropriate fact
-  in the FactBase for a closed-entry node.  Example:
-       constProp (Label l) fb = lookupFact fb l
-  That is how Hoopl can avoid having to know the block-id for the
-  first node: it defers to the client.
-
-  [Side note: that means the client must know about 
-  bottom, in case the looupFact returns Nothing]
-
-* Note also that FwdTransfer *returns* a Fact too;
-  that is, the types in both directions are symmetrical.
-  Previously we returned a [(BlockId,f)] but I could not see
-  how to make everything line up if we do this.
-
-  Indeed, the main shortcoming of Hoopl7 is that we are more
-  or less forced into this uniform representation of the facts
-  flowing into or out of a closed node/block/graph, whereas
-  previously we had more flexibility.
-
-  In exchange the code is neater, with fewer distinct types.
-  And morally a FactBase is equivalent to [(BlockId,f)] and
-  nearly equivalent to (BlockId -> f).
-
-* I've realised that forwardBlockList and backwardBlockList
-  both need (NonLocal n), and that goes everywhere.
-
-* I renamed BlockId to Label
--}
-
-module Compiler.Hoopl.OldDataflow
-  ( DataflowLattice(..), JoinFun, OldFact(..), NewFact(..), Fact
-  , ChangeFlag(..), changeIf
-  , FwdPass(..), FwdTransfer, mkFTransfer, mkFTransfer', getFTransfers
-  , FwdRes(..),  FwdRewrite,  mkFRewrite,  mkFRewrite',  getFRewrites
-  , BwdPass(..), BwdTransfer, mkBTransfer, mkBTransfer', getBTransfers
-  , BwdRes(..),  BwdRewrite,  mkBRewrite,  mkBRewrite',  getBRewrites
-  , analyzeAndRewriteFwd,  analyzeAndRewriteBwd
-  , analyzeAndRewriteFwd', analyzeAndRewriteBwd'
-  )
-where
-
-import Data.Maybe
-
-import Compiler.Hoopl.Fuel
-import Compiler.Hoopl.Graph
-import Compiler.Hoopl.MkGraph
-import Compiler.Hoopl.Label
-import Compiler.Hoopl.Util
-
------------------------------------------------------------------------------
---             DataflowLattice
------------------------------------------------------------------------------
-
-data DataflowLattice a = DataflowLattice  
- { fact_name       :: String          -- Documentation
- , fact_bot        :: a               -- Lattice bottom element
- , fact_extend     :: JoinFun a       -- Lattice join plus change flag
-                                      -- (changes iff result > old fact)
- }
--- ^ A transfer function might want to use the logging flag
--- to control debugging, as in for example, it updates just one element
--- in a big finite map.  We don't want Hoopl to show the whole fact,
--- and only the transfer function knows exactly what changed.
-
-type JoinFun a = Label -> OldFact a -> NewFact a -> (ChangeFlag, a)
-  -- the label argument is for debugging purposes only
-newtype OldFact a = OldFact a
-newtype NewFact a = NewFact a
-
-data ChangeFlag = NoChange | SomeChange deriving (Eq, Ord)
-changeIf :: Bool -> ChangeFlag
-changeIf changed = if changed then SomeChange else NoChange
-
-
------------------------------------------------------------------------------
---             Analyze and rewrite forward: the interface
------------------------------------------------------------------------------
-
-data FwdPass n f
-  = FwdPass { fp_lattice  :: DataflowLattice f
-            , fp_transfer :: FwdTransfer n f
-            , fp_rewrite  :: FwdRewrite n f }
-
-newtype FwdTransfer n f 
-  = FwdTransfers { getFTransfers ::
-                     ( n C O -> f -> f
-                     , n O O -> f -> f
-                     , n O C -> f -> FactBase f
-                     ) }
-
-newtype FwdRewrite n f 
-  = FwdRewrites { getFRewrites ::
-                    ( n C O -> f -> Maybe (FwdRes n f C O)
-                    , n O O -> f -> Maybe (FwdRes n f O O)
-                    , n O C -> f -> Maybe (FwdRes n f O C)
-                    ) }
-data FwdRes n f e x = FwdRes (AGraph n e x) (FwdRewrite n f)
-  -- result of a rewrite is a new graph and a (possibly) new rewrite function
-
-mkFTransfer :: (n C O -> f -> f)
-            -> (n O O -> f -> f)
-            -> (n O C -> f -> FactBase f)
-            -> FwdTransfer n f
-mkFTransfer f m l = FwdTransfers (f, m, l)
-
-mkFTransfer' :: (forall e x . n e x -> f -> Fact x f) -> FwdTransfer n f
-mkFTransfer' f = FwdTransfers (f, f, f)
-
-mkFRewrite :: (n C O -> f -> Maybe (FwdRes n f C O))
-           -> (n O O -> f -> Maybe (FwdRes n f O O))
-           -> (n O C -> f -> Maybe (FwdRes n f O C))
-           -> FwdRewrite n f
-mkFRewrite f m l = FwdRewrites (f, m, l)
-
-mkFRewrite' :: (forall e x . n e x -> f -> Maybe (FwdRes n f e x)) -> FwdRewrite n f
-mkFRewrite' f = FwdRewrites (f, f, f)
-
-
-type family   Fact x f :: *
-type instance Fact C f = FactBase f
-type instance Fact O f = f
-
-analyzeAndRewriteFwd
-   :: forall n f. NonLocal n
-   => FwdPass n f
-   -> Body n -> FactBase f
-   -> FuelMonad (Body n, FactBase f)
-
-analyzeAndRewriteFwd pass body facts
-  = do { (rg, _) <- arfBody pass body facts
-       ; return (normaliseBody rg) }
-
--- | if the graph being analyzed is open at the entry, there must
---   be no other entry point, or all goes horribly wrong...
-analyzeAndRewriteFwd'
-   :: forall n f e x. NonLocal n
-   => FwdPass n f
-   -> Graph n e x -> Fact e f
-   -> FuelMonad (Graph n e x, FactBase f, MaybeO x f)
-analyzeAndRewriteFwd' pass g f =
-  do (rg, fout) <- arfGraph pass g f
-     let (g', fb) = normalizeGraph rg
-     return (g', fb, distinguishedExitFact g' fout)
-
-distinguishedExitFact :: forall n e x f . Graph n e x -> Fact x f -> MaybeO x f
-distinguishedExitFact g f = maybe g
-    where maybe :: Graph n e x -> MaybeO x f
-          maybe GNil       = JustO f
-          maybe (GUnit {}) = JustO f
-          maybe (GMany _ _ x) = case x of NothingO -> NothingO
-                                          JustO _  -> JustO f
-
-----------------------------------------------------------------
---       Forward Implementation
-----------------------------------------------------------------
-
-
-type ARF' n f thing e x
-  = FwdPass n f -> thing e x -> f -> FuelMonad (RG f n e x, Fact x f)
-  -- ^ Analyze and rewrite forward
-
-type ARFX' n f thing e x
-  = FwdPass n f -> thing e x -> Fact e f -> FuelMonad (RG f n e x, Fact x f)
-  -- ^ Analyze and rewrite forward extended -- can take @FactBase f@
-
-arfx :: NonLocal thing => ARF' n f thing C x -> ARFX' n f thing C x
-arfx arf pass thing fb = 
-    arf pass thing $ fromJust $ lookupFact (joinInFacts lattice fb) $ entryLabel thing
-  where lattice = fp_lattice pass
-  -- joinInFacts adds debugging information
-
-type ARF  thing n = forall f e x . ARF'  n f thing e x
-type ARFX thing n = forall f e x . ARFX' n f thing e x
-
-arfNode :: (NonLocal n, ShapeLifter e x) => ARF' n f n e x
-arfNode pass node f
-  = do { mb_g <- withFuel (frewrite pass node f)
-       ; case mb_g of
-           Nothing -> return (rgunit f (unit node),
-                              ftransfer pass node f)
-          Just (FwdRes ag rw) -> do { g <- graphOfAGraph ag
-                                     ; let pass' = pass { fp_rewrite = rw }
-                                     ; arfGraph pass' g (elift node f) } }
-
--- type demonstration
-_arfBlock :: NonLocal n => ARF' n f (Block n) e x
-_arfBlock = arfBlock
-
-arfBlock :: NonLocal n => ARF (Block n) n
--- Lift from nodes to blocks
-arfBlock pass (BFirst  node)  = arfNode pass node
-arfBlock pass (BMiddle node)  = arfNode pass node
-arfBlock pass (BLast   node)  = arfNode pass node
-arfBlock pass (BCat b1 b2)    = arfCat arfBlock arfBlock pass b1 b2
-arfBlock pass (BSnoc h n)     = arfCat arfBlock arfNode  pass h n
-arfBlock pass (BCons n t)     = arfCat arfNode  arfBlock pass n t
-arfBlock pass (BClosed h t)   = arfCat arfBlock arfBlock pass h t
-
-arfCat :: (pass -> thing1 -> info1 -> FuelMonad (RG f n e a, info2))
-       -> (pass -> thing2 -> info2 -> FuelMonad (RG f n a x, info2'))
-       -> (pass -> thing1 -> thing2 -> info1 -> FuelMonad (RG f n e x, info2'))
-{-# INLINE arfCat #-}
-arfCat arf1 arf2 pass thing1 thing2 f = do { (g1,f1) <- arf1 pass thing1 f
-                                           ; (g2,f2) <- arf2 pass thing2 f1
-                                           ; return (g1 `rgCat` g2, f2) }
-
-arfBody :: NonLocal n
-        => FwdPass n f -> Body n -> FactBase f
-        -> FuelMonad (RG f n C C, FactBase f)
-               -- Outgoing factbase is restricted to Labels *not* in
-               -- in the Body; the facts for Labels *in*
-                -- the Body are in the BodyWithFacts
-arfBody pass blocks init_fbase
-  = fixpoint True (fp_lattice pass) do_block init_fbase $
-    forwardBlockList (factBaseLabels init_fbase) blocks
-  where
-    do_block b f = do (g, fb) <- arfBlock pass b $ lookupF pass (entryLabel b) f
-                      return (g, factBaseList fb)
-
-arfGraph :: NonLocal n => ARFX (Graph n) n
--- Lift from blocks to graphs
-arfGraph _    GNil        = \f -> return (rgnil, f)
-arfGraph pass (GUnit blk) = arfBlock pass blk
-arfGraph pass (GMany NothingO body NothingO) = arfBody pass body
-arfGraph pass (GMany NothingO body (JustO exit))
-  = arfCat arfBody (arfx arfBlock) pass body exit
-arfGraph pass (GMany (JustO entry) body NothingO)
-  = arfCat arfBlock arfBody pass entry body
-arfGraph pass (GMany (JustO entry) body (JustO exit))
-  = arfCat arfeb (arfx arfBlock) pass (entry, body) exit
- where arfeb pass = uncurry $ arfCat arfBlock arfBody pass
-
-
--- Join all the incoming facts with bottom.
--- We know the results _shouldn't change_, but the transfer
--- functions might, for example, generate some debugging traces.
-joinInFacts :: DataflowLattice f -> FactBase f -> FactBase f
-joinInFacts (DataflowLattice {fact_bot = bot, fact_extend = fe}) fb =
-  mkFactBase $ map botJoin $ factBaseList fb
-    where botJoin (l, f) = (l, snd $ fe l (OldFact bot) (NewFact f))
-
-forwardBlockList :: (NonLocal n, LabelsPtr entry)
-                 => entry -> Body n -> [Block n C C]
--- This produces a list of blocks in order suitable for forward analysis,
--- along with the list of Labels it may depend on for facts.
-forwardBlockList entries blks = postorder_dfs_from (bodyMap blks) entries
-
------------------------------------------------------------------------------
---             Backward analysis and rewriting: the interface
------------------------------------------------------------------------------
-
-data BwdPass n f
-  = BwdPass { bp_lattice  :: DataflowLattice f
-            , bp_transfer :: BwdTransfer n f
-            , bp_rewrite  :: BwdRewrite n f }
-
-newtype BwdTransfer n f 
-  = BwdTransfers { getBTransfers ::
-                     ( n C O -> f          -> f
-                     , n O O -> f          -> f
-                     , n O C -> FactBase f -> f
-                     ) }
-newtype BwdRewrite n f 
-  = BwdRewrites { getBRewrites ::
-                    ( n C O -> f          -> Maybe (BwdRes n f C O)
-                    , n O O -> f          -> Maybe (BwdRes n f O O)
-                    , n O C -> FactBase f -> Maybe (BwdRes n f O C)
-                    ) }
-data BwdRes n f e x = BwdRes (AGraph n e x) (BwdRewrite n f)
-
-mkBTransfer :: (n C O -> f -> f) -> (n O O -> f -> f) ->
-               (n O C -> FactBase f -> f) -> BwdTransfer n f
-mkBTransfer f m l = BwdTransfers (f, m, l)
-
-mkBTransfer' :: (forall e x . n e x -> Fact x f -> f) -> BwdTransfer n f
-mkBTransfer' f = BwdTransfers (f, f, f)
-
-mkBRewrite :: (n C O -> f          -> Maybe (BwdRes n f C O))
-           -> (n O O -> f          -> Maybe (BwdRes n f O O))
-           -> (n O C -> FactBase f -> Maybe (BwdRes n f O C))
-           -> BwdRewrite n f
-mkBRewrite f m l = BwdRewrites (f, m, l)
-
-mkBRewrite' :: (forall e x . n e x -> Fact x f -> Maybe (BwdRes n f e x)) -> BwdRewrite n f
-mkBRewrite' f = BwdRewrites (f, f, f)
-
-
------------------------------------------------------------------------------
---             Backward implementation
------------------------------------------------------------------------------
-
-type ARB' n f thing e x
-  = BwdPass n f -> thing e x -> Fact x f -> FuelMonad (RG f n e x, f)
-
-type ARBX' n f thing e x
-  = BwdPass n f -> thing e x -> Fact x f -> FuelMonad (RG f n e x, Fact e f)
-
-type ARB  thing n = forall f e x. ARB'  n f thing e x 
-type ARBX thing n = forall f e x. ARBX' n f thing e x 
-
-arbx :: NonLocal thing => ARB' n f thing C x -> ARBX' n f thing C x
-arbx arb pass thing f = do { (rg, f) <- arb pass thing f
-                           ; let fb = joinInFacts (bp_lattice pass) $
-                                      mkFactBase [(entryLabel thing, f)]
-                           ; return (rg, fb) }
-
-arbNode :: (NonLocal n, ShapeLifter e x) => ARB' n f n e x
--- Lifts (BwdTransfer,BwdRewrite) to ARB_Node; 
--- this time we do rewriting as well. 
--- The ARB_Graph parameters specifies what to do with the rewritten graph
-arbNode pass node f
-  = do { mb_g <- withFuel (brewrite pass node f)
-       ; case mb_g of
-           Nothing -> return (rgunit entry_f (unit node), entry_f)
-                    where entry_f  = btransfer pass node f
-          Just (BwdRes ag rw) -> do { g <- graphOfAGraph ag
-                                     ; let pass' = pass { bp_rewrite = rw }
-                                     ; (g, f) <- arbGraph pass' g f
-                                     ; return (g, elower (bp_lattice pass) node f)} }
-
-arbBlock :: NonLocal n => ARB (Block n) n
--- Lift from nodes to blocks
-arbBlock pass (BFirst  node)  = arbNode pass node
-arbBlock pass (BMiddle node)  = arbNode pass node
-arbBlock pass (BLast   node)  = arbNode pass node
-arbBlock pass (BCat b1 b2)    = arbCat arbBlock arbBlock pass b1 b2
-arbBlock pass (BSnoc h n)     = arbCat arbBlock arbNode  pass h n
-arbBlock pass (BCons n t)     = arbCat arbNode  arbBlock pass n t
-arbBlock pass (BClosed h t)   = arbCat arbBlock arbBlock pass h t
-
-arbCat :: (pass -> thing1 -> info1 -> FuelMonad (RG f n e a, info1'))
-       -> (pass -> thing2 -> info2 -> FuelMonad (RG f n a x, info1))
-       -> (pass -> thing1 -> thing2 -> info2 -> FuelMonad (RG f n e x, info1'))
-{-# INLINE arbCat #-}
-arbCat arb1 arb2 pass thing1 thing2 f = do { (g2,f2) <- arb2 pass thing2 f
-                                           ; (g1,f1) <- arb1 pass thing1 f2
-                                           ; return (g1 `rgCat` g2, f1) }
-
-arbBody :: NonLocal n
-        => BwdPass n f -> Body n -> FactBase f
-        -> FuelMonad (RG f n C C, FactBase f)
-arbBody pass blocks init_fbase
-  = fixpoint False (bp_lattice pass) do_block init_fbase $
-    backwardBlockList blocks 
-  where
-    do_block b f = do (g, f) <- arbBlock pass b f
-                      return (g, [(entryLabel b, f)])
-
-arbGraph :: NonLocal n => ARBX (Graph n) n
-arbGraph _    GNil        = \f -> return (rgnil, f)
-arbGraph pass (GUnit blk) = arbBlock pass blk
-arbGraph pass (GMany NothingO body NothingO) = arbBody pass body
-arbGraph pass (GMany NothingO body (JustO exit)) =
-  arbCat arbBody (arbx arbBlock) pass body exit
-arbGraph pass (GMany (JustO entry) body NothingO) =
-  arbCat arbBlock arbBody pass entry body
-arbGraph pass (GMany (JustO entry) body (JustO exit)) =
-  arbCat arbeb (arbx arbBlock) pass (entry, body) exit
- where arbeb pass = uncurry $ arbCat arbBlock arbBody pass
-
-
-backwardBlockList :: NonLocal n => Body n -> [Block n C C]
--- This produces a list of blocks in order suitable for backward analysis,
--- along with the list of Labels it may depend on for facts.
-backwardBlockList body = reachable ++ missing
-  where reachable = reverse $ forwardBlockList entries body
-        entries = externalEntryLabels body
-        all = bodyList body
-        missingLabels =
-            mkLabelSet (map fst all) `minusLabelSet`
-            mkLabelSet (map entryLabel reachable)
-        missing = map snd $ filter (flip elemLabelSet missingLabels . fst) all
-
-{-
-
-The forward and backward dataflow analyses now use postorder depth-first
-order for faster convergence.
-
-The forward and backward cases are not dual.  In the forward case, the
-entry points are known, and one simply traverses the body blocks from
-those points.  In the backward case, something is known about the exit
-points, but this information is essentially useless, because we don't
-actually have a dual graph (that is, one with edges reversed) to
-compute with.  (Even if we did have a dual graph, it would not avail
-us---a backward analysis must include reachable blocks that don't
-reach the exit, as in a procedure that loops forever and has side
-effects.)
-
-Since in the general case, no information is available about entry
-points, I have put in a horrible hack.  First, I assume that every
-label defined but not used is an entry point.  Then, because an entry
-point might also be a loop header, I add, in arbitrary order, all the
-remaining "missing" blocks.  Needless to say, I am not pleased.  
-I am not satisfied.  I am not Senator Morgan.
-
-Wait! I believe that the Right Thing here is to require that anyone
-wishing to analyze a graph closed at the entry provide a way of
-determining the entry points, if any, of that graph.  This requirement
-can apply equally to forward and backward analyses; I believe that
-using the input FactBase to determine the entry points of a closed
-graph is *also* a hack.
-
-NR
-
--}
-
-
-analyzeAndRewriteBwd
-   :: forall n f. NonLocal n
-   => BwdPass n f 
-   -> Body n -> FactBase f 
-   -> FuelMonad (Body n, FactBase f)
-
-analyzeAndRewriteBwd pass body facts
-  = do { (rg, _) <- arbBody pass body facts
-       ; return (normaliseBody rg) }
-
--- | if the graph being analyzed is open at the exit, I don't
---   quite understand the implications of possible other exits
-analyzeAndRewriteBwd'
-   :: forall n f e x. NonLocal n
-   => BwdPass n f
-   -> Graph n e x -> Fact x f
-   -> FuelMonad (Graph n e x, FactBase f, MaybeO e f)
-analyzeAndRewriteBwd' pass g f =
-  do (rg, fout) <- arbGraph pass g f
-     let (g', fb) = normalizeGraph rg
-     return (g', fb, distinguishedEntryFact g' fout)
-
-distinguishedEntryFact :: forall n e x f . Graph n e x -> Fact e f -> MaybeO e f
-distinguishedEntryFact g f = maybe g
-    where maybe :: Graph n e x -> MaybeO e f
-          maybe GNil       = JustO f
-          maybe (GUnit {}) = JustO f
-          maybe (GMany e _ _) = case e of NothingO -> NothingO
-                                          JustO _  -> JustO f
-
------------------------------------------------------------------------------
---      fixpoint: finding fixed points
------------------------------------------------------------------------------
-
-data TxFactBase n f
-  = TxFB { tfb_fbase :: FactBase f
-         , tfb_rg  :: RG f n C C -- Transformed blocks
-         , tfb_cha   :: ChangeFlag
-         , tfb_lbls  :: LabelSet }
- -- Note [TxFactBase change flag]
- -- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- -- Set the tfb_cha flag iff 
- --   (a) the fact in tfb_fbase for or a block L changes
- --   (b) L is in tfb_lbls.
- -- The tfb_lbls are all Labels of the *original* 
- -- (not transformed) blocks
-
-updateFact :: DataflowLattice f -> LabelSet -> (Label, f)
-           -> (ChangeFlag, FactBase f) 
-           -> (ChangeFlag, FactBase f)
--- See Note [TxFactBase change flag]
-updateFact lat lbls (lbl, new_fact) (cha, fbase)
-  | NoChange <- cha2        = (cha,        fbase)
-  | lbl `elemLabelSet` lbls = (SomeChange, new_fbase)
-  | otherwise               = (cha,        new_fbase)
-  where
-    (cha2, res_fact) -- Note [Unreachable blocks]
-       = case lookupFact fbase lbl of
-           Nothing -> (SomeChange, snd $ join $ fact_bot lat)  -- Note [Unreachable blocks]
-           Just old_fact -> join old_fact
-         where join old_fact = fact_extend lat lbl (OldFact old_fact) (NewFact new_fact)
-    new_fbase = extendFactBase fbase lbl res_fact
-
-fixpoint :: forall block n f. NonLocal (block n)
-         => Bool       -- Going forwards?
-         -> DataflowLattice f
-         -> (block n C C -> FactBase f
-              -> FuelMonad (RG f n C C, [(Label, f)]))
-         -> FactBase f 
-         -> [block n C C]
-         -> FuelMonad (RG f n C C, FactBase f)
-fixpoint is_fwd lat do_block init_fbase untagged_blocks
-  = do { fuel <- getFuel  
-       ; tx_fb <- loop fuel init_fbase
-       ; return (tfb_rg tx_fb, 
-                 tfb_fbase tx_fb `delFromFactBase` map fst blocks) }
-            -- The successors of the Graph are the the Labels for which
-            -- we have facts, that are *not* in the blocks of the graph
-  where
-    blocks = map tag untagged_blocks
-     where tag b = ((entryLabel b, b), if is_fwd then [entryLabel b] else successors b)
-
-    tx_blocks :: [((Label, block n C C), [Label])]   -- I do not understand this type
-              -> TxFactBase n f -> FuelMonad (TxFactBase n f)
-    tx_blocks []              tx_fb = return tx_fb
-    tx_blocks (((lbl,blk), deps):bs) tx_fb = tx_block lbl blk deps tx_fb >>= tx_blocks bs
-     -- "deps" == Labels the block may _depend_ upon for facts
-
-    tx_block :: Label -> block n C C -> [Label]
-             -> TxFactBase n f -> FuelMonad (TxFactBase n f)
-    tx_block lbl blk deps tx_fb@(TxFB { tfb_fbase = fbase, tfb_lbls = lbls
-                                      , tfb_rg = blks, tfb_cha = cha })
-      | is_fwd && not (lbl `elemFactBase` fbase)
-      = return tx_fb {tfb_lbls = lbls `unionLabelSet` mkLabelSet deps} -- Note [Unreachable blocks]
-      | otherwise
-      = do { (rg, out_facts) <- do_block blk fbase
-           ; let (cha',fbase') 
-                   = foldr (updateFact lat lbls) (cha,fbase) out_facts
-                 lbls' = lbls `unionLabelSet` mkLabelSet deps
-           ; return (TxFB { tfb_lbls  = lbls'
-                          , tfb_rg    = rg `rgCat` blks
-                          , tfb_fbase = fbase', tfb_cha = cha' }) }
-
-    loop :: Fuel -> FactBase f -> FuelMonad (TxFactBase n f)
-    loop fuel fbase 
-      = do { let init_tx_fb = TxFB { tfb_fbase = fbase
-                                   , tfb_cha   = NoChange
-                                   , tfb_rg    = rgnilC
-                                   , tfb_lbls  = emptyLabelSet }
-           ; tx_fb <- tx_blocks blocks init_tx_fb
-           ; case tfb_cha tx_fb of
-               NoChange   -> return tx_fb
-               SomeChange -> do { setFuel fuel
-                                ; loop fuel (tfb_fbase tx_fb) } }
-
-{- Note [Unreachable blocks]
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-A block that is not in the domain of tfb_fbase is "currently unreachable".
-A currently-unreachable block is not even analyzed.  Reason: consider 
-constant prop and this graph, with entry point L1:
-  L1: x:=3; goto L4
-  L2: x:=4; goto L4
-  L4: if x>3 goto L2 else goto L5
-Here L2 is actually unreachable, but if we process it with bottom input fact,
-we'll propagate (x=4) to L4, and nuke the otherwise-good rewriting of L4.
-
-* If a currently-unreachable block is not analyzed, then its rewritten
-  graph will not be accumulated in tfb_rg.  And that is good:
-  unreachable blocks simply do not appear in the output.
-
-* Note that clients must be careful to provide a fact (even if bottom)
-  for each entry point. Otherwise useful blocks may be garbage collected.
-
-* Note that updateFact must set the change-flag if a label goes from
-  not-in-fbase to in-fbase, even if its fact is bottom.  In effect the
-  real fact lattice is
-       UNR
-       bottom
-       the points above bottom
-
-* Even if the fact is going from UNR to bottom, we still call the
-  client's fact_extend function because it might give the client
-  some useful debugging information.
-
-* All of this only applies for *forward* fixpoints.  For the backward
-  case we must treat every block as reachable; it might finish with a
-  'return', and therefore have no successors, for example.
--}
-
------------------------------------------------------------------------------
---     RG: an internal data type for graphs under construction
---          TOTALLY internal to Hoopl; each block carries its fact
------------------------------------------------------------------------------
-
-type RG      f n e x = Graph' (FBlock f) n e x
-data FBlock f n e x = FBlock f (Block n e x)
-
---- constructors
-
-rgnil  :: RG f n O O
-rgnilC :: RG f n C C
-rgunit :: f -> Block n e x -> RG f n e x
-rgCat  :: RG f n e a -> RG f n a x -> RG f n e x
-
----- observers
-
-type BodyWithFacts  n f     = (Body n, FactBase f)
-type GraphWithFacts n f e x = (Graph n e x, FactBase f)
-  -- A Graph together with the facts for that graph
-  -- The domains of the two maps should be identical
-
-normalizeGraph :: forall n f e x .
-                  NonLocal n => RG f n e x -> GraphWithFacts n f e x
-normaliseBody  :: NonLocal n => RG f n C C -> BodyWithFacts n f
-
-normalizeGraph g = (graphMapBlocks dropFact g, facts g)
-    where dropFact (FBlock _ b) = b
-          facts :: RG f n e x -> FactBase f
-          facts GNil = noFacts
-          facts (GUnit _) = noFacts
-          facts (GMany _ body exit) = bodyFacts body `unionFactBase` exitFacts exit
-          exitFacts :: MaybeO x (FBlock f n C O) -> FactBase f
-          exitFacts NothingO = noFacts
-          exitFacts (JustO (FBlock f b)) = mkFactBase [(entryLabel b, f)]
-          bodyFacts :: Body' (FBlock f) n -> FactBase f
-          bodyFacts (BodyUnit (FBlock f b)) = mkFactBase [(entryLabel b, f)]
-          bodyFacts (b1 `BodyCat` b2) = bodyFacts b1 `unionFactBase` bodyFacts b2
-
-normaliseBody rg = (body, fact_base)
-  where (GMany _ body _, fact_base) = normalizeGraph rg
-
---- implementation of the constructors (boring)
-
-rgnil  = GNil
-rgnilC = GMany NothingO BodyEmpty NothingO
-
-rgunit f b@(BFirst  {}) = gUnitCO (FBlock f b)
-rgunit f b@(BMiddle {}) = gUnitOO (FBlock f b)
-rgunit f b@(BLast   {}) = gUnitOC (FBlock f b)
-rgunit f b@(BCat {})    = gUnitOO (FBlock f b)
-rgunit f b@(BSnoc {})   = gUnitCO (FBlock f b)
-rgunit f b@(BCons {})   = gUnitOC (FBlock f b)
-rgunit f b@(BClosed {}) = gUnitCC (FBlock f b)
-
-rgCat = U.splice fzCat
-  where fzCat (FBlock f b1) (FBlock _ b2) = FBlock f (b1 `U.cat` b2)
-
-----------------------------------------------------------------
---       Utilities
-----------------------------------------------------------------
-
--- Lifting based on shape:
---  - from nodes to blocks
---  - from facts to fact-like things
--- Lowering back:
---  - from fact-like things to facts
--- Note that the latter two functions depend only on the entry shape.
-class ShapeLifter e x where
-  unit      :: n e x -> Block n e x
-  elift     :: NonLocal n =>                      n e x -> f -> Fact e f
-  elower    :: NonLocal n => DataflowLattice f -> n e x -> Fact e f -> f
-  ftransfer :: FwdPass n f -> n e x -> f        -> Fact x f
-  btransfer :: BwdPass n f -> n e x -> Fact x f -> f
-  frewrite  :: FwdPass n f -> n e x -> f        -> Maybe (FwdRes n f e x)
-  brewrite  :: BwdPass n f -> n e x -> Fact x f -> Maybe (BwdRes n f e x)
-
-instance ShapeLifter C O where
-  unit            = BFirst
-  elift      n f  = mkFactBase [(entryLabel n, f)]
-  elower lat n fb = getFact lat (entryLabel n) fb
-  ftransfer (FwdPass {fp_transfer = FwdTransfers (ft, _, _)}) n f = ft n f
-  btransfer (BwdPass {bp_transfer = BwdTransfers (bt, _, _)}) n f = bt n f
-  frewrite  (FwdPass {fp_rewrite  = FwdRewrites  (fr, _, _)}) n f = fr n f
-  brewrite  (BwdPass {bp_rewrite  = BwdRewrites  (br, _, _)}) n f = br n f
-
-instance ShapeLifter O O where
-  unit         = BMiddle
-  elift    _ f = f
-  elower _ _ f = f
-  ftransfer (FwdPass {fp_transfer = FwdTransfers (_, ft, _)}) n f = ft n f
-  btransfer (BwdPass {bp_transfer = BwdTransfers (_, bt, _)}) n f = bt n f
-  frewrite  (FwdPass {fp_rewrite  = FwdRewrites  (_, fr, _)}) n f = fr n f
-  brewrite  (BwdPass {bp_rewrite  = BwdRewrites  (_, br, _)}) n f = br n f
-
-instance ShapeLifter O C where
-  unit         = BLast
-  elift    _ f = f
-  elower _ _ f = f
-  ftransfer (FwdPass {fp_transfer = FwdTransfers (_, _, ft)}) n f = ft n f
-  btransfer (BwdPass {bp_transfer = BwdTransfers (_, _, bt)}) n f = bt n f
-  frewrite  (FwdPass {fp_rewrite  = FwdRewrites  (_, _, fr)}) n f = fr n f
-  brewrite  (BwdPass {bp_rewrite  = BwdRewrites  (_, _, br)}) n f = br n f
-
--- Fact lookup: the fact `orelse` bottom
-lookupF :: FwdPass n f -> Label -> FactBase f -> f
-lookupF = getFact . fp_lattice
-
-getFact  :: DataflowLattice f -> Label -> FactBase f -> f
-getFact lat l fb = case lookupFact fb l of Just  f -> f
-                                           Nothing -> fact_bot lat