| | 13 | |
| | 14 | == CURRENT STATUS == |
| | 15 | |
| | 16 | {{{ |
| | 17 | -- $phase_control |
| | 18 | -- #phase_control# |
| | 19 | -- |
| | 20 | -- Compiler /core phases/ represent contiguous intervals of time spent in the core pipeline. They are used |
| | 21 | -- to control when core-to-core passes, inlining and rule activation take place. The phases @Foo@ and @Bar@ |
| | 22 | -- would be used in @INLINE@ and @RULES@ pragmas like so: |
| | 23 | -- |
| | 24 | -- > {-# INLINE [Foo] myIdentifier #-} |
| | 25 | -- > {-# RULES "myrule" [~Bar] map f (map g xs) = map (f . g) xs #-} |
| | 26 | -- |
| | 27 | -- Phases, with the constraints on when they can run are introduced by the @PHASE@ pragma syntax. So, a phase |
| | 28 | -- called @Foo@ that must run before one called @Bar@, after one called @Baz@ and at the same time as one |
| | 29 | -- called @Spqr@ is written like so: |
| | 30 | -- |
| | 31 | -- > {-# PHASE Foo < Bar, > Baz, = Spqr #-} |
| | 32 | -- |
| | 33 | -- All the constraints above are so-called /strong/ constraints: there are also /weak/ constraints, which are |
| | 34 | -- suggestions but not commands to the compiler as to when to run phases. If, for example, a cycle is formed |
| | 35 | -- by including these constraints into the phase partial ordering then the compiler may ignore them, at it's |
| | 36 | -- discretion. Weak constraints are indicated by enclosing the constraint in square brackets: |
| | 37 | -- |
| | 38 | -- > {-# PHASE Foo [< Bar], [> Baz] #-} |
| | 39 | -- |
| | 40 | -- Note that it is not currently possible for an equality constraint (phase alias) to be weak. |
| | 41 | -- |
| | 42 | -- Phases may be imported and exported: |
| | 43 | -- |
| | 44 | -- > import MyModule ({-# PHASE Foo #-} {-# PHASE Bar #-}) |
| | 45 | -- |
| | 46 | -- There are three built-in phases that are implicitly imported, and these have the special names @0@, @1@ and |
| | 47 | -- @2@. These are constrained such that @2@ must run first, then @1@ and finally @0@. The GHC compiler also |
| | 48 | -- exports a number of phases from @GHC.Prim@ that correspond to the particular optimizations and analyses |
| | 49 | -- that it may run. |
| | 50 | -- |
| | 51 | -- When constructing the core pipeline, GHC gathers all the phases available to it, and then imposes a total |
| | 52 | -- order than respects all the strong constraints of those phases and as many of the weak constraints as it |
| | 53 | -- wishes. This linearises the core phase graph, which serves as the scaffolding on which the actual Core |
| | 54 | -- transformations are hung. |
| | 55 | -- |
| | 56 | -- Now we come to /core passes/, which represent a concrete transformation to be applied to GHCs current Core. |
| | 57 | -- Passes will typically just do a single action, but it is possible to specify a \"core pass\" that just runs a |
| | 58 | -- list of several other core passes. /Core to-dos/ then associates a core pass with a particular core phase. |
| | 59 | -- |
| | 60 | -- After solving for some linearisation of the available core phases, the compiler takes the core passes associated |
| | 61 | -- with each phase in that linearisation by way of a core to-do and concatenates them in order. This yields |
| | 62 | -- the final compiler pipeline, which is what is actually run. |
| | 63 | |
| | 64 | -- The above is actually a somewhat simplified picture. It gives the /user model/ for what we do with core phases |
| | 65 | -- and passes, but actually we implement a number of optimizations to this process. What is there to optimize? Well, |
| | 66 | -- we want to minimize the number of simplifier passes that we perform. A naive approach would be to just do one |
| | 67 | -- simplifier run per core phase, to deal with activating the rules and inlinings in that phase. However, this |
| | 68 | -- results in a lot of simplification! So, we optimize in three ways: |
| | 69 | -- |
| | 70 | -- 1) When solving for a linearisation of the phases, we group phases together into so-called /phase groups/, which |
| | 71 | -- have the property that every phase within the group is depedent only on the phases in other groups. Hence the |
| | 72 | -- phases within a phase group are independent, and may be treated by a single simplifier run that "acts as though" |
| | 73 | -- it were a simplifier run for every pass individually. |
| | 74 | -- |
| | 75 | -- 2) Before running a simplifier pass introduced for the sole purpose of performing the rules and inlining activations |
| | 76 | -- associated with a particular phase, the compiler does a pre-pass to check if there exists any actual uses of that |
| | 77 | -- phase in the source code being compiled. If not, it doesn't bother running that simplifier pass. |
| | 78 | -- |
| | 79 | -- 3) When building up the core pass pipeline, as far as is possible simplifier passes are moved to the end of the part |
| | 80 | -- of the core pipeline belonging to their associated phase group. This gives them their maximum effectiveness, while |
| | 81 | -- simultaneously allowing us to "coalesce" those simplifier passes that are adjacent into a single simplifier pass |
| | 82 | -- that performs the union of the operations of each individual simplifier pass. |
| | 83 | }}} |