shithub: mc

Download patch

ref: 0c14bdce7f2c20becd103d0c8d0641a038b5d83b
parent: 4f90a4d919cc5862fd3ecbffc62b94b515dda7d3
author: Ori Bernstein <[email protected]>
date: Wed Aug 22 16:28:04 EDT 2012

More documentation.

--- a/doc/compiler.txt
+++ b/doc/compiler.txt
@@ -13,8 +13,9 @@
         2.5. Serialization
         2.6. Usefiles
     3. FLATTENING
-        3.1. Control Flow
-        3.2. Complex Expressions
+        3.1. Flattening Conditionals
+        3.2. Flattening Complex Expressions
+        3.3. Building the Control Flow Graph
     4. OPTIMIZATION
         4.1. Constant Folding
     5. CODE GENERATION
@@ -197,7 +198,8 @@
     phase should be made machine independent, and passed as a parameter
     a machine description describing known integer and pointer sizes, among
     other machine attributes. However, for now, it is machine dependent,
-    and lives in 6/simp.c.
+    and lives in 6/simp.c, implemented through the callees of simpnode(),
+    such as simpif(), simploop(), and so on.
 
     The goal of flattening a tree is to take semantically involved constructs
     such as looping, and simplify things into something that is easy to
@@ -204,7 +206,7 @@
     generate code for, as well as something that is easier to analyze for
     optimization.
 
-    3.1. Control Flow:
+    3.1. Flattening Conditionals:
 
         All if statements, loops, and other complex constructs are simplified
         to jumps and conditional jumps. Loops are generally simplified from
@@ -230,12 +232,17 @@
         Boolean expressions are simplified to a location to jump to, as
         described in section 8.4 of the Dragon book[1].
 
-    3.2. Complex Expressions:
+    3.2. Flattening Complex Expressions:
 
-        Complex expressions such as copying types larger than a single machine
-        word, pulling members out of structures, emulated multiplication and
-        division for larger integers sizes, and similar operations are reduced
-        to trees that are expressible in terms of simple machine operations.
+        Complex expressions such as copying types larger than a single
+        machine word, pulling members out of structures, emulated
+        multiplication and division for larger integers sizes, and similar
+        operations are reduced to trees that are expressible in terms of
+        simple machine operations.  This is implemented in lval() and rval()
+        in 6/simp.c, which reduce expressions to lvals (assignable
+        expressions which may appear on the left hand side of an assignemnt)
+        or rvals (value-yeilding expressions which may appear on the right
+        side of an assignment.
 
         By the end of the simplification pass, the following operators should
         not be present in the trees:
@@ -246,12 +253,81 @@
             Oslbase Osllen Ocast
 
 
+        After flattening, all nodes must either be pure, or impure roots.
+        With the exception of assignments to a temporary, no inner nodes
+        may be impure. For example, the following sequence of root nodes
+        is valid, as all impure nodes are either roots, or children of
+        rooted assignments to temporaries:
+
+            Oadd
+                Ovar "temp0"
+                Olit int(123)
+            Oasn
+                Ovar "temp1"
+                Ocall
+                    Ovar "func"
+                    Ovar "arg1"
+                    Ovar "arg2"
+            Ocall
+                Ovar "std.put"
+                Olit "some string\n"
+
+        The following tree is invalid because the Ocall node is impure, but
+        it is not the root node or the direct child of a rooted assignment:
+
+            Oasn
+                Ovar "result"
+                Oadd
+                    Ovar "temp0"
+                    Oasn
+                        Ovar "temp1"
+                        Ocall
+                            Ovar "somefunc"
+                            Ovar "arg0"
+                            Ovar "arg1"
+                
+        In order to make it valid, it must be transformed to the following
+        form:
+
+            Oasn
+                Ovar "temp1"
+                Ocall
+                    Ovar "somefunc"
+                    Ovar "arg0"
+                    Ovar "arg1"
+            Oasn
+                Ovar "result"
+                Oadd
+                    Ovar "temp0"
+                    Ovar "temp1"
+
+        Note that Oasn, Oblit, and other assignment nodes may only appear as
+        rooted nodes.
+
+
+    3.3. Building the Control Flow Graph
+
+        Once everything is simplified to relatively flat trees made of
+        primitve operations, a control flow graph is built. The
+        structureless list is split into basic blocks (sequences of
+        instructions where the control flows straight through), and
+        put into the 'Cfg' data structure defined in opt/opt.h. The
+        fact that each Bb within the Cfg has linear flow makes it easier
+        to reason about the code, and thus generate code and implement
+        optimizations.
+
+        This pass is machine independent, as it looks only at the leaders
+        (ie, labels) and trailers (ie, jumps and conditional jumps) for
+        blocks. There are no machine independent components to this process.
+
 4. OPTIMIZATION:
 
     Currently, there is virtually no optimization done on the trees after
-    flattening. The only optimization that is done is constant folding.
+    flattening. The only optimization that is done is constant folding. All
+    optimizations currently operate on a per-function basis, and preserve
+    [or are required to update] the control flow graph.
 
-    4.1. Constant Folding:
+    4.2. Constant Folding:
 
         Expressions with constant values are simplified algebraically. For
         example, the expression 'x*1' is simplified to simply 'x', '0/n' is
@@ -265,8 +341,17 @@
         Instruction selection is done via a simple hand written bottom up pass
         over the tree. Common patterns such as scaled or offset indexing are
         recognized by the patterns, but no attempts at finding an optimal
-        tiling are made.
+        tiling are made. This is implemented in 6/isel.c and is very machine
+        specific.
 
+        The structure of the control flow graph is preserved by the
+        instruction selection transformation, with each basic block in the
+        flattened-node flow graph mirrored by an assembly node in the flow
+        graph. This is because there is no need to make the assembly flow
+        graph different when translating, and it is simpler to simply
+        preserve the structure of the flow graph than to rebuild the
+        structure from scratch.
+
     5.2. Register Allocation:
 
         Register allocation is done via the algorithm described in "Iterated
@@ -275,6 +360,9 @@
         register classes. This will be done as described in "A generalized
         algorithm for graph-coloring register allocation", by Smith, Ramsey,
         and Holloway.
+
+        The full description will not be mirrored here, as the papers do a
+        far more thorough job of describing the algorithm than I could.
 
 6: TUTORIAL: ADDING A STATEMENT:
 
--- a/parse/infer.c
+++ b/parse/infer.c
@@ -662,7 +662,7 @@
     settype(st, n, mktyarray(n->line, type(st, n->lit.seqval[0]), mkintlit(n->line, n->lit.nelt)));
 }
 
-static void inferpat(Inferstate *st, Node *n, Node ***bind, size_t *nbind)
+static void inferpat(Inferstate *st, Node *n, Node *val, Node ***bind, size_t *nbind)
 {
     size_t i;
     Ucon *uc;
@@ -693,6 +693,7 @@
             } else {
                 t = mktyvar(n->line);
                 s = mkdecl(n->line, n->expr.args[0], t);
+                s->decl.init = val;
                 settype(st, n, t);
                 lappend(bind, nbind, s);
             }