an “integrated code generator” for the glasgow haskell ... · functional-programming ideas ease...
TRANSCRIPT
![Page 1: An “Integrated Code Generator” for the Glasgow Haskell ... · Functional-programming ideas ease the pain. Functional compiler writers should care about imperative code To run](https://reader034.vdocument.in/reader034/viewer/2022050516/5f9ffab533125402357c7220/html5/thumbnails/1.jpg)
An “Integrated Code Generator” for
the Glasgow Haskell Compiler
Joao Dias, Simon Marlow,Simon Peyton Jones, Norman Ramsey
Harvard University, Microsoft Research,and Tufts University
![Page 2: An “Integrated Code Generator” for the Glasgow Haskell ... · Functional-programming ideas ease the pain. Functional compiler writers should care about imperative code To run](https://reader034.vdocument.in/reader034/viewer/2022050516/5f9ffab533125402357c7220/html5/thumbnails/2.jpg)
Classic Dataflow “Optimization,”
Purely Functionally
Norman Ramsey
Microsoft Research and Tufts University
(also Jo ao Dias & Simon Peyton Jones)
![Page 3: An “Integrated Code Generator” for the Glasgow Haskell ... · Functional-programming ideas ease the pain. Functional compiler writers should care about imperative code To run](https://reader034.vdocument.in/reader034/viewer/2022050516/5f9ffab533125402357c7220/html5/thumbnails/3.jpg)
Functional compiler writersshould care about imperative code
To run FP as native code, I know two choices:1. Rewrite terms to functional CPS, ANF; then to
machine code2. Rewrite terms to imperative C --; then to
machine code
Why an imperative intermediate language?• Access to 40 years of code improvement• You’ll do it anyway (TIL, Objective Caml, MLton)
Functional-programming ideas ease the pain
![Page 4: An “Integrated Code Generator” for the Glasgow Haskell ... · Functional-programming ideas ease the pain. Functional compiler writers should care about imperative code To run](https://reader034.vdocument.in/reader034/viewer/2022050516/5f9ffab533125402357c7220/html5/thumbnails/4.jpg)
Functional compiler writersshould care about imperative code
To run FP as native code, I know two choices:1. Rewrite terms to functional CPS, ANF; then to
machine code2. Rewrite terms to imperative C --; then to
machine code
Why an imperative intermediate language?• Access to 40 years of code improvement• You’ll do it anyway (TIL, Objective Caml, MLton)
Functional-programming ideas ease the pain
![Page 5: An “Integrated Code Generator” for the Glasgow Haskell ... · Functional-programming ideas ease the pain. Functional compiler writers should care about imperative code To run](https://reader034.vdocument.in/reader034/viewer/2022050516/5f9ffab533125402357c7220/html5/thumbnails/5.jpg)
Functional compiler writersshould care about imperative code
To run FP as native code, I know two choices:1. Rewrite terms to functional CPS, ANF; then to
machine code2. Rewrite terms to imperative C --; then to
machine code
Why an imperative intermediate language?• Access to 40 years of code improvement• You’ll do it anyway (TIL, Objective Caml, MLton)
Functional-programming ideas ease the pain
![Page 6: An “Integrated Code Generator” for the Glasgow Haskell ... · Functional-programming ideas ease the pain. Functional compiler writers should care about imperative code To run](https://reader034.vdocument.in/reader034/viewer/2022050516/5f9ffab533125402357c7220/html5/thumbnails/6.jpg)
Optimization madness can be made sane
Flee the jargon of “dataflow optimization”• Constant prop agation, copy prop agation, code
motion, rematerialization, strength reduc tion. . .• Forward and back ward dataflow prob lems• Kill, gen, trans fer func tions• Iterative dataflow analysis
Instead consider• Substitution of equals for equals• Elimination of unused assignments• Strongest postcondition, weakest precondition• Iterative computation of fixed point
(Appeal to your inner semanticist)
![Page 7: An “Integrated Code Generator” for the Glasgow Haskell ... · Functional-programming ideas ease the pain. Functional compiler writers should care about imperative code To run](https://reader034.vdocument.in/reader034/viewer/2022050516/5f9ffab533125402357c7220/html5/thumbnails/7.jpg)
Optimization madness can be made sane
Flee the jargon of “dataflow optimization”• Constant prop agation, copy prop agation, code
motion, rematerialization, strength reduc tion. . .• Forward and back ward dataflow prob lems• Kill, gen, trans fer func tions• Iterative dataflow analysis
Instead consider• Substitution of equals for equals• Elimination of unused assignments• Strongest postcondition, weakest precondition• Iterative computation of fixed point
(Appeal to your inner semanticist)
![Page 8: An “Integrated Code Generator” for the Glasgow Haskell ... · Functional-programming ideas ease the pain. Functional compiler writers should care about imperative code To run](https://reader034.vdocument.in/reader034/viewer/2022050516/5f9ffab533125402357c7220/html5/thumbnails/8.jpg)
Optimization madness can be made sane
Flee the jargon of “dataflow optimization”• Constant prop agation, copy prop agation, code
motion, rematerialization, strength reduc tion. . .• Forward and back ward dataflow prob lems• Kill, gen, trans fer func tions• Iterative dataflow analysis
Instead consider• Substitution of equals for equals• Elimination of unused assignments• Strongest postcondition , weakest precondition• Iterative computation of fixed point
(Appeal to your inner semanticist)
![Page 9: An “Integrated Code Generator” for the Glasgow Haskell ... · Functional-programming ideas ease the pain. Functional compiler writers should care about imperative code To run](https://reader034.vdocument.in/reader034/viewer/2022050516/5f9ffab533125402357c7220/html5/thumbnails/9.jpg)
Dataflow’s roots are in Hoare logic
Assertions attached to points between statements:
{ i = 7 }
i := i + 1
{ i = 8 }
![Page 10: An “Integrated Code Generator” for the Glasgow Haskell ... · Functional-programming ideas ease the pain. Functional compiler writers should care about imperative code To run](https://reader034.vdocument.in/reader034/viewer/2022050516/5f9ffab533125402357c7220/html5/thumbnails/10.jpg)
Code rewriting is supported by assertions
Substitution of equals for equals
{ i = 7 } { i = 7 } { i = 7 }
i := i + 1 i := 7 + 1 i := 8
{ i = 8 } { i = 8 } { i = 8 }
“Constant “Constant
Propagation” Folding”
![Page 11: An “Integrated Code Generator” for the Glasgow Haskell ... · Functional-programming ideas ease the pain. Functional compiler writers should care about imperative code To run](https://reader034.vdocument.in/reader034/viewer/2022050516/5f9ffab533125402357c7220/html5/thumbnails/11.jpg)
Code rewriting is supported by assertions
Substitution of equals for equals
{ i = 7 } { i = 7 } { i = 7 }
i := i + 1 i := 7 + 1 i := 8
{ i = 8 } { i = 8 } { i = 8 }
“Constant “Constant
Propagation” Folding”
(Notice how dumb the logic is)
![Page 12: An “Integrated Code Generator” for the Glasgow Haskell ... · Functional-programming ideas ease the pain. Functional compiler writers should care about imperative code To run](https://reader034.vdocument.in/reader034/viewer/2022050516/5f9ffab533125402357c7220/html5/thumbnails/12.jpg)
Finding useful assertions is critical
Example coming up (more expressive logic now):
{ p = a + i * 12 }
i := i + 1
{ p = a + (i-1) * 12 }
p := p + 12
{ p = a + i * 12 }
![Page 13: An “Integrated Code Generator” for the Glasgow Haskell ... · Functional-programming ideas ease the pain. Functional compiler writers should care about imperative code To run](https://reader034.vdocument.in/reader034/viewer/2022050516/5f9ffab533125402357c7220/html5/thumbnails/13.jpg)
Dataflow analysis finds good assertions
Example coming up (more expressive logic now):
{ p = a + i * 12 }
i := i + 1
{ p = a + (i-1) * 12 }
p := p + 12
{ p = a + i * 12 }
p
a:
Imagine i = 4:
![Page 14: An “Integrated Code Generator” for the Glasgow Haskell ... · Functional-programming ideas ease the pain. Functional compiler writers should care about imperative code To run](https://reader034.vdocument.in/reader034/viewer/2022050516/5f9ffab533125402357c7220/html5/thumbnails/14.jpg)
Example: Classic array optimization
First running example (C code):
long double sum(long double a[], int n) {
long double x = 0.0;
int i;
for (i = 0; i < n; i++)
x += a[i];
return x;
}
![Page 15: An “Integrated Code Generator” for the Glasgow Haskell ... · Functional-programming ideas ease the pain. Functional compiler writers should care about imperative code To run](https://reader034.vdocument.in/reader034/viewer/2022050516/5f9ffab533125402357c7220/html5/thumbnails/15.jpg)
Array optimization at machine level
Same example (C -- code):
sum("address" bits32 a, bits32 n) {
bits80 x; bits32 i;
x = 0.0;
i = 0;
L1: if (i >= n) goto L2;
x = %fadd(x, %f2f80(bits96[a+i*12]));
i = i + 1;
goto L1;
L2: return x;
}
![Page 16: An “Integrated Code Generator” for the Glasgow Haskell ... · Functional-programming ideas ease the pain. Functional compiler writers should care about imperative code To run](https://reader034.vdocument.in/reader034/viewer/2022050516/5f9ffab533125402357c7220/html5/thumbnails/16.jpg)
Ad-hoc transformation
New variable satisfying p == a + i * 12
sum("address" bits32 a, bits32 n) {
bits80 x; bits32 i; bits32 p, lim;
x = 0.0;
i = 0; p = a; lim = a + n * 12;
L1: if (i >= n) goto L2;
x = %fadd(x, %f2f80(bits96[a+i*12]));
i = i + 1; p = p + 12;
goto L1;
L2: return x;
}
![Page 17: An “Integrated Code Generator” for the Glasgow Haskell ... · Functional-programming ideas ease the pain. Functional compiler writers should care about imperative code To run](https://reader034.vdocument.in/reader034/viewer/2022050516/5f9ffab533125402357c7220/html5/thumbnails/17.jpg)
“Induction-variable elimination”
Use p == a + i * 12 and (i >= n) == (p >= lim):
sum("address" bits32 a, bits32 n) {
bits80 x; bits32 i; bits32 p, lim;
x = 0.0;
i = 0; p = a; lim = a + n * 12;
L1: if (p >= lim) goto L2;
x = %fadd(x, %f2f80(bits96[p]));
i = i + 1; p = p + 12;
goto L1;
L2: return x;
}
![Page 18: An “Integrated Code Generator” for the Glasgow Haskell ... · Functional-programming ideas ease the pain. Functional compiler writers should care about imperative code To run](https://reader034.vdocument.in/reader034/viewer/2022050516/5f9ffab533125402357c7220/html5/thumbnails/18.jpg)
Finally, i is superfluous
“Dead-assignment elimination” (with a twist)
sum("address" bits32 a, bits32 n) {
bits80 x; bits32 i; bits32 p, lim;
x = 0.0;
i = 0; p = a; lim = a + n * 12;
L1: if (p >= lim) goto L2;
x = %fadd(x, %f2f80(bits96[p]));
i = i + 1; p = p + 12;
goto L1;
L2: return x;
}
![Page 19: An “Integrated Code Generator” for the Glasgow Haskell ... · Functional-programming ideas ease the pain. Functional compiler writers should care about imperative code To run](https://reader034.vdocument.in/reader034/viewer/2022050516/5f9ffab533125402357c7220/html5/thumbnails/19.jpg)
Finally, i is superfluous
“Dead-assignment elimination” (with a twist)
sum("address" bits32 a, bits32 n) {
bits80 x; bits32 p, lim;
x = 0.0;
p = a; lim = a + n * 12;
L1: if (p >= lim) goto L2;
x = %fadd(x, %f2f80(bits96[p]));
p = p + 12;
goto L1;
L2: return x;
}
![Page 20: An “Integrated Code Generator” for the Glasgow Haskell ... · Functional-programming ideas ease the pain. Functional compiler writers should care about imperative code To run](https://reader034.vdocument.in/reader034/viewer/2022050516/5f9ffab533125402357c7220/html5/thumbnails/20.jpg)
Things we can talk about
Here and now:• Example of code improvement (“optimization”)
grounded in Hoare logic• Closer look at assertions and logic
Possible sketches before I yield the floor:• Ingredients of a “best simple” optimizer• Bowdlerized code• Data structures for “imperative optimization”
in a functional world
Hallway hacking:• Real code! In GHC now!
![Page 21: An “Integrated Code Generator” for the Glasgow Haskell ... · Functional-programming ideas ease the pain. Functional compiler writers should care about imperative code To run](https://reader034.vdocument.in/reader034/viewer/2022050516/5f9ffab533125402357c7220/html5/thumbnails/21.jpg)
Things we can talk about
Here and now:• Example of code improvement (“optimization”)
grounded in Hoare logic• Closer look at assertions and logic
Possible sketches before I yield the floor:• Ingredients of a “best simple” optimizer• Bowdlerized code• Data structures for “imperative optimization”
in a functional world
Hallway hacking:• Real code! In GHC now!
![Page 22: An “Integrated Code Generator” for the Glasgow Haskell ... · Functional-programming ideas ease the pain. Functional compiler writers should care about imperative code To run](https://reader034.vdocument.in/reader034/viewer/2022050516/5f9ffab533125402357c7220/html5/thumbnails/22.jpg)
Things we can talk about
Here and now:• Example of code improvement (“optimization”)
grounded in Hoare logic• Closer look at assertions and logic
Possible sketches before I yield the floor:• Ingredients of a “best simple” optimizer• Bowdlerized code• Data structures for “imperative optimization”
in a functional world
Hallway hacking:• Real code! In GHC now!
![Page 23: An “Integrated Code Generator” for the Glasgow Haskell ... · Functional-programming ideas ease the pain. Functional compiler writers should care about imperative code To run](https://reader034.vdocument.in/reader034/viewer/2022050516/5f9ffab533125402357c7220/html5/thumbnails/23.jpg)
Assertions and logic
![Page 24: An “Integrated Code Generator” for the Glasgow Haskell ... · Functional-programming ideas ease the pain. Functional compiler writers should care about imperative code To run](https://reader034.vdocument.in/reader034/viewer/2022050516/5f9ffab533125402357c7220/html5/thumbnails/24.jpg)
Where do assertions come from?
Key observation:
Statements relate assertions to assertions
Example, Dijkstra’s weakest precondition:Ai−1 = wp(Si;Ai)(Also good: strongest postcondition)
Query : given fSig, A0 = True, can we solve for fAig?
Answer : Solution exists, but seldom in closed form.
Why not? Disjunction (from loops) ruins everything:fixed point is an infinite term.
![Page 25: An “Integrated Code Generator” for the Glasgow Haskell ... · Functional-programming ideas ease the pain. Functional compiler writers should care about imperative code To run](https://reader034.vdocument.in/reader034/viewer/2022050516/5f9ffab533125402357c7220/html5/thumbnails/25.jpg)
Dijkstra’s way out: hand write key A’s
Dijkstra says: write loop invariant :An assertion at a join point (loop header)• May be stronger than necessary• Can prove verification condition
My opinion: a great teaching tool• Dijkstra/Gries � imperative programming with
loops and arrays• Bird/Wadler � applicative programming with
equational reasoning
Not available to compiler
![Page 26: An “Integrated Code Generator” for the Glasgow Haskell ... · Functional-programming ideas ease the pain. Functional compiler writers should care about imperative code To run](https://reader034.vdocument.in/reader034/viewer/2022050516/5f9ffab533125402357c7220/html5/thumbnails/26.jpg)
Dijkstra’s way out: hand write key A’s
Dijkstra says: write loop invariant :An assertion at a join point (loop header)• May be stronger than necessary• Can prove verification condition
My opinion: a great teaching tool• Dijkstra/Gries � imperative programming with
loops and arrays• Bird/Wadler � applicative programming with
equational reasoning
Not available to compiler
![Page 27: An “Integrated Code Generator” for the Glasgow Haskell ... · Functional-programming ideas ease the pain. Functional compiler writers should care about imperative code To run](https://reader034.vdocument.in/reader034/viewer/2022050516/5f9ffab533125402357c7220/html5/thumbnails/27.jpg)
Dijkstra’s way out: hand write key A’s
Dijkstra says: write loop invariant :An assertion at a join point (loop header)• May be stronger than necessary• Can prove verification condition
My opinion: a great teaching tool• Dijkstra/Gries � imperative programming with
loops and arrays• Bird/Wadler � applicative programming with
equational reasoning
Not available to compiler
![Page 28: An “Integrated Code Generator” for the Glasgow Haskell ... · Functional-programming ideas ease the pain. Functional compiler writers should care about imperative code To run](https://reader034.vdocument.in/reader034/viewer/2022050516/5f9ffab533125402357c7220/html5/thumbnails/28.jpg)
Compiler’s way out: less expressive logic
Ultra-simple logics!(inexpressible predicates abandoned)
Results: weaker assertions at key points
Consequence:• Proliferation of inexpressive logics• Each has a name, often a program transformation• Transformation is usually substitution
Examples:P ::=? j P ^x = k “constant propagation”P ::=? j P ^x = y “copy propagation”
![Page 29: An “Integrated Code Generator” for the Glasgow Haskell ... · Functional-programming ideas ease the pain. Functional compiler writers should care about imperative code To run](https://reader034.vdocument.in/reader034/viewer/2022050516/5f9ffab533125402357c7220/html5/thumbnails/29.jpg)
Dataflow analysis solves recursion equations
Easy to think about least solutions:Ai−1 = wp(Si;Ai);Alast =? “Backward analysis”Ai = sp(Si;Ai−1);A0 =? “Forward analysis”
Classic method is iterative , uses mutable state :1. Set all Ai :=?2. Repeat for all i:
let A′i−1=Ai−1twp(Si;Ai)
If A′i−16=Ai−1, set Ai−1 :=A′i−1
3. Continue until fixed point is reached
Number of iterations is roughly loop nesting depth
![Page 30: An “Integrated Code Generator” for the Glasgow Haskell ... · Functional-programming ideas ease the pain. Functional compiler writers should care about imperative code To run](https://reader034.vdocument.in/reader034/viewer/2022050516/5f9ffab533125402357c7220/html5/thumbnails/30.jpg)
Beyond Hoare logic: The context
Classic assertions are about program state �• Example: { i = 7 }� 8� : �(i) = 7
Also want to assert about context or continuation �• Example: { dead(x) }� 8�;v : �(�) = �(�fx 7! vg)
(Undecidable, approximate by reachability)(Typically track live , not dead)
![Page 31: An “Integrated Code Generator” for the Glasgow Haskell ... · Functional-programming ideas ease the pain. Functional compiler writers should care about imperative code To run](https://reader034.vdocument.in/reader034/viewer/2022050516/5f9ffab533125402357c7220/html5/thumbnails/31.jpg)
A “best simple” optimizer for GHC
(Shout if you’d rather see code)
![Page 32: An “Integrated Code Generator” for the Glasgow Haskell ... · Functional-programming ideas ease the pain. Functional compiler writers should care about imperative code To run](https://reader034.vdocument.in/reader034/viewer/2022050516/5f9ffab533125402357c7220/html5/thumbnails/32.jpg)
Long-term goal: Haskell, optimized
Classic dataflow-based code improvement, plantedin the Glasgow Haskell Compiler (GHC)
The engineering question:• How to support 40 years of imperative-style
analysis and optimization simply, cleanly, and ina purely functional setting?
Answers:• Good data structures• Powerful code-rewriting engine based on
dataflow (i.e. Hoare logic)
![Page 33: An “Integrated Code Generator” for the Glasgow Haskell ... · Functional-programming ideas ease the pain. Functional compiler writers should care about imperative code To run](https://reader034.vdocument.in/reader034/viewer/2022050516/5f9ffab533125402357c7220/html5/thumbnails/33.jpg)
Long-term goal: Haskell, optimized
Classic dataflow-based code improvement, plantedin the Glasgow Haskell Compiler (GHC)
The engineering question :• How to support 40 years of imperative-style
analysis and optimization simply , cleanly , and ina purely functional setting ?
Answers:• Good data structures• Powerful code-rewriting engine based on
dataflow (i.e. Hoare logic)
![Page 34: An “Integrated Code Generator” for the Glasgow Haskell ... · Functional-programming ideas ease the pain. Functional compiler writers should care about imperative code To run](https://reader034.vdocument.in/reader034/viewer/2022050516/5f9ffab533125402357c7220/html5/thumbnails/34.jpg)
Long-term goal: Haskell, optimized
Classic dataflow-based code improvement, plantedin the Glasgow Haskell Compiler (GHC)
The engineering question :• How to support 40 years of imperative-style
analysis and optimization simply , cleanly , and ina purely functional setting ?
Answers:• Good data structures• Powerful code-rewriting engine based on
dataflow (i.e. Hoare logic)
![Page 35: An “Integrated Code Generator” for the Glasgow Haskell ... · Functional-programming ideas ease the pain. Functional compiler writers should care about imperative code To run](https://reader034.vdocument.in/reader034/viewer/2022050516/5f9ffab533125402357c7220/html5/thumbnails/35.jpg)
Optimization: a closer look
![Page 36: An “Integrated Code Generator” for the Glasgow Haskell ... · Functional-programming ideas ease the pain. Functional compiler writers should care about imperative code To run](https://reader034.vdocument.in/reader034/viewer/2022050516/5f9ffab533125402357c7220/html5/thumbnails/36.jpg)
It’s about registers, loops, and arrays
Dataflow-based optimization• Not glamorous like equational reasoning,�-lifting, closure conversion, CPS conversion• Needs to happen anyway, downstream
Lesson learned: low-level optimization matters• TIL (Tarditi)• Objective Caml (Leroy)• MLton (Weeks, Fluet, . . . )• GHC?
![Page 37: An “Integrated Code Generator” for the Glasgow Haskell ... · Functional-programming ideas ease the pain. Functional compiler writers should care about imperative code To run](https://reader034.vdocument.in/reader034/viewer/2022050516/5f9ffab533125402357c7220/html5/thumbnails/37.jpg)
It’s about registers, loops, and arrays
Dataflow-based optimization• Not glamorous like equational reasoning,�-lifting, closure conversion, CPS conversion• Needs to happen anyway, downstream
Lesson learned: low-level optimization matters• TIL (Tarditi)• Objective Caml (Leroy)• MLton (Weeks, Fluet, . . . )• GHC?
![Page 38: An “Integrated Code Generator” for the Glasgow Haskell ... · Functional-programming ideas ease the pain. Functional compiler writers should care about imperative code To run](https://reader034.vdocument.in/reader034/viewer/2022050516/5f9ffab533125402357c7220/html5/thumbnails/38.jpg)
Simple ingredients can do a lot
You must be able to• Represent assignments, control flow graphically
(at the machine level)• Have infinitely many registers (or facsimile)• Implement a few impoverished logics• Solve recursion equations (dataflow analysis)• Mutate assignments and branches
![Page 39: An “Integrated Code Generator” for the Glasgow Haskell ... · Functional-programming ideas ease the pain. Functional compiler writers should care about imperative code To run](https://reader034.vdocument.in/reader034/viewer/2022050516/5f9ffab533125402357c7220/html5/thumbnails/39.jpg)
We have 5 essential ingredients
Interleaved analysis and transformation(Lerner, Grove, and Chambers 2002)
Dataflow analysis
Dataflow monad
Zipper control-flow graph(Ramsey and Dias 2005)
. . . and a good register allocator
![Page 40: An “Integrated Code Generator” for the Glasgow Haskell ... · Functional-programming ideas ease the pain. Functional compiler writers should care about imperative code To run](https://reader034.vdocument.in/reader034/viewer/2022050516/5f9ffab533125402357c7220/html5/thumbnails/40.jpg)
We have 5 essential ingredients
Interleaved analysis and transformation(Lerner, Grove, and Chambers 2002)
Dataflow analysis
Dataflow monad
Zipper control-flow graph(Ramsey and Dias 2005)
. . . and a good register allocator
![Page 41: An “Integrated Code Generator” for the Glasgow Haskell ... · Functional-programming ideas ease the pain. Functional compiler writers should care about imperative code To run](https://reader034.vdocument.in/reader034/viewer/2022050516/5f9ffab533125402357c7220/html5/thumbnails/41.jpg)
We have 5 essential ingredients
Interleaved analysis and transformation(Lerner, Grove, and Chambers 2002)
Dataflow analysis
Dataflow monad
Zipper control-flow graph(Ramsey and Dias 2005)
. . . and a good register allocator
![Page 42: An “Integrated Code Generator” for the Glasgow Haskell ... · Functional-programming ideas ease the pain. Functional compiler writers should care about imperative code To run](https://reader034.vdocument.in/reader034/viewer/2022050516/5f9ffab533125402357c7220/html5/thumbnails/42.jpg)
We have 5 essential ingredients
Interleaved analysis and transformation(Lerner, Grove, and Chambers 2002)
Dataflow analysis
Dataflow monad
Zipper control-flow graph(Ramsey and Dias 2005)
. . . and a good register allocator
![Page 43: An “Integrated Code Generator” for the Glasgow Haskell ... · Functional-programming ideas ease the pain. Functional compiler writers should care about imperative code To run](https://reader034.vdocument.in/reader034/viewer/2022050516/5f9ffab533125402357c7220/html5/thumbnails/43.jpg)
We have 5 essential ingredients
Interleaved analysis and transformation(Lerner, Grove, and Chambers 2002)
Dataflow analysis
Dataflow monad
Zipper control-flow graph(Ramsey and Dias 2005)
. . . and a good register allocator
![Page 44: An “Integrated Code Generator” for the Glasgow Haskell ... · Functional-programming ideas ease the pain. Functional compiler writers should care about imperative code To run](https://reader034.vdocument.in/reader034/viewer/2022050516/5f9ffab533125402357c7220/html5/thumbnails/44.jpg)
We have 5 essential ingredients
Interleaved analysis and transformation(Lerner, Grove, and Chambers 2002)
Dataflow analysis
Dataflow monad
Zipper control-flow graph(Ramsey and Dias 2005)
. . . and a good register allocator
![Page 45: An “Integrated Code Generator” for the Glasgow Haskell ... · Functional-programming ideas ease the pain. Functional compiler writers should care about imperative code To run](https://reader034.vdocument.in/reader034/viewer/2022050516/5f9ffab533125402357c7220/html5/thumbnails/45.jpg)
Design philosophy
The “33-pass compiler”• Small, simple, composable transformations• “Existing optimizations clean up after new
optimizations”• Keep improving until code doesn’t change
![Page 46: An “Integrated Code Generator” for the Glasgow Haskell ... · Functional-programming ideas ease the pain. Functional compiler writers should care about imperative code To run](https://reader034.vdocument.in/reader034/viewer/2022050516/5f9ffab533125402357c7220/html5/thumbnails/46.jpg)
Simple debugging technique wins big!
Limitable supply of “optimization fuel”• Rewrite for performance consumes one unit• On failure, binary search on fuel supply
(spread over multiple compilation units)
Invented by David Whalley (1994)
Bookkeeping in a “fuel monad”
![Page 47: An “Integrated Code Generator” for the Glasgow Haskell ... · Functional-programming ideas ease the pain. Functional compiler writers should care about imperative code To run](https://reader034.vdocument.in/reader034/viewer/2022050516/5f9ffab533125402357c7220/html5/thumbnails/47.jpg)
Simple debugging technique wins big!
Limitable supply of “optimization fuel”• Rewrite for performance consumes one unit• On failure, binary search on fuel supply
(spread over multiple compilation units)
Invented by David Whalley (1994)
Bookkeeping in a “fuel monad”
![Page 48: An “Integrated Code Generator” for the Glasgow Haskell ... · Functional-programming ideas ease the pain. Functional compiler writers should care about imperative code To run](https://reader034.vdocument.in/reader034/viewer/2022050516/5f9ffab533125402357c7220/html5/thumbnails/48.jpg)
What’s important
![Page 49: An “Integrated Code Generator” for the Glasgow Haskell ... · Functional-programming ideas ease the pain. Functional compiler writers should care about imperative code To run](https://reader034.vdocument.in/reader034/viewer/2022050516/5f9ffab533125402357c7220/html5/thumbnails/49.jpg)
Things to remember
Dataflow analysis =weakest preconditions + impoverished logic
“Optimization” is largely “equals for equals”
“Movement” is achieved in three steps:1. Insert new code2. Rewrite code in place3. Delete old code
The compiler writer has three good friends:• Coalescing register allocator• Dataflow-based transformation engine• “Optimization fuel”
![Page 50: An “Integrated Code Generator” for the Glasgow Haskell ... · Functional-programming ideas ease the pain. Functional compiler writers should care about imperative code To run](https://reader034.vdocument.in/reader034/viewer/2022050516/5f9ffab533125402357c7220/html5/thumbnails/50.jpg)
Dataflow (from 10,000 ft)
(Shout if you prefer the zipper)
![Page 51: An “Integrated Code Generator” for the Glasgow Haskell ... · Functional-programming ideas ease the pain. Functional compiler writers should care about imperative code To run](https://reader034.vdocument.in/reader034/viewer/2022050516/5f9ffab533125402357c7220/html5/thumbnails/51.jpg)
Lies, damn lies, type signatures
Logical formula is “dataflow fact”
data DataflowLattice a = DataflowLattice {
bottom :: a,
join :: a -> a,
refines :: a -> a -> bool
}
Facts computed by “transfer function” ( wp or sp):
type Transfer a = a -> Node -> a
Fact might justify a rewrite:
type Rewrite a = a -> Node -> Maybe Graph
![Page 52: An “Integrated Code Generator” for the Glasgow Haskell ... · Functional-programming ideas ease the pain. Functional compiler writers should care about imperative code To run](https://reader034.vdocument.in/reader034/viewer/2022050516/5f9ffab533125402357c7220/html5/thumbnails/52.jpg)
Bigger, more interesting lies
solve :: DataflowLattice a-> Transfer a-> a -- fact in (at entry or exit)-> Graph-> BlockEnv a -- FP: {label |-> fact}
rewr :: DataflowLattice a-> Transfer a-> a-> RewritingDepth-> Rewrite a-> Graph-> FuelMonad (Graph, BlockEnv a)
![Page 53: An “Integrated Code Generator” for the Glasgow Haskell ... · Functional-programming ideas ease the pain. Functional compiler writers should care about imperative code To run](https://reader034.vdocument.in/reader034/viewer/2022050516/5f9ffab533125402357c7220/html5/thumbnails/53.jpg)
Simple, almost-true client: liveness
Lattice is set of live registers; join is union.
Transfer equations use traditional gen, kill:
gen, kill :: HasRegs a => a -> RegSet -> RegSet
gen = foldFreeRegs extendRegSet
kill = foldFreeRegs delOneFromRegSet
xfer :: Transfer RegSet
xfer :: Node -> RegSet -> RegSet
xfer (Comment {}) = id
xfer (Load reg expr) = gen expr . kill reg
xfer (Store addr rval) = gen addr . gen rval
xfer (Call f res args) = gen f . gen args . kill res
xfer (Return e) = \ _ -> gen e $ emptyRegSet
![Page 54: An “Integrated Code Generator” for the Glasgow Haskell ... · Functional-programming ideas ease the pain. Functional compiler writers should care about imperative code To run](https://reader034.vdocument.in/reader034/viewer/2022050516/5f9ffab533125402357c7220/html5/thumbnails/54.jpg)
Companion: dead-assignment elimination
Our most useful tool is dirt-simple:
removeDeads :: Rewrite RegSet
removeDeads :: RegSet -> Node -> Maybe Graph
removeDeads live (Load reg expr)
| not (reg ‘elemRegSet‘ live)
= Just emptyGraph
removeDeads live _ = Nothing
Combine with liveness xfer using rewr
![Page 55: An “Integrated Code Generator” for the Glasgow Haskell ... · Functional-programming ideas ease the pain. Functional compiler writers should care about imperative code To run](https://reader034.vdocument.in/reader034/viewer/2022050516/5f9ffab533125402357c7220/html5/thumbnails/55.jpg)
Win by isolating complexity
Function rewr is scary (= 1 POPL paper)
Clients are simple:• “Impoverished logic” = “easy to understand”• Not much code
More examples:• Spill/reload in 3 passes (1 to insert, 2 to sink)• Call elimination in 1 pass• Linear-scan register allocation in 4 passes! (Dias)
![Page 56: An “Integrated Code Generator” for the Glasgow Haskell ... · Functional-programming ideas ease the pain. Functional compiler writers should care about imperative code To run](https://reader034.vdocument.in/reader034/viewer/2022050516/5f9ffab533125402357c7220/html5/thumbnails/56.jpg)
The zipper
![Page 57: An “Integrated Code Generator” for the Glasgow Haskell ... · Functional-programming ideas ease the pain. Functional compiler writers should care about imperative code To run](https://reader034.vdocument.in/reader034/viewer/2022050516/5f9ffab533125402357c7220/html5/thumbnails/57.jpg)
A very simple flow graph
![Page 58: An “Integrated Code Generator” for the Glasgow Haskell ... · Functional-programming ideas ease the pain. Functional compiler writers should care about imperative code To run](https://reader034.vdocument.in/reader034/viewer/2022050516/5f9ffab533125402357c7220/html5/thumbnails/58.jpg)
Nodes have different static types
One basic block:
F
M
L
![Page 59: An “Integrated Code Generator” for the Glasgow Haskell ... · Functional-programming ideas ease the pain. Functional compiler writers should care about imperative code To run](https://reader034.vdocument.in/reader034/viewer/2022050516/5f9ffab533125402357c7220/html5/thumbnails/59.jpg)
Edges betweeen blocks use a finite map
L
F
L
F
M
L
F
L1 L2
L3 L3
L1L2L3
![Page 60: An “Integrated Code Generator” for the Glasgow Haskell ... · Functional-programming ideas ease the pain. Functional compiler writers should care about imperative code To run](https://reader034.vdocument.in/reader034/viewer/2022050516/5f9ffab533125402357c7220/html5/thumbnails/60.jpg)
Need operations on nodes
Not requiring mutation:• Forward, backward traversal
More imperative-looking:• Insert• Replace• Delete
All should be simple, easy, and functional
![Page 61: An “Integrated Code Generator” for the Glasgow Haskell ... · Functional-programming ideas ease the pain. Functional compiler writers should care about imperative code To run](https://reader034.vdocument.in/reader034/viewer/2022050516/5f9ffab533125402357c7220/html5/thumbnails/61.jpg)
The Zipper: Manipulating basic blocks
The focus represents the “current” edge:
Unfocused Focused on 1st edge
F
M
M
L
F
M
M
L
Focus
![Page 62: An “Integrated Code Generator” for the Glasgow Haskell ... · Functional-programming ideas ease the pain. Functional compiler writers should care about imperative code To run](https://reader034.vdocument.in/reader034/viewer/2022050516/5f9ffab533125402357c7220/html5/thumbnails/62.jpg)
Moving the focus
Traversal requires constant-space allocation:
Focused on 1st edge Focused on 2nd edge
F
M
M
L
Focus
F
M
M
L
Focus
![Page 63: An “Integrated Code Generator” for the Glasgow Haskell ... · Functional-programming ideas ease the pain. Functional compiler writers should care about imperative code To run](https://reader034.vdocument.in/reader034/viewer/2022050516/5f9ffab533125402357c7220/html5/thumbnails/63.jpg)
Inserting an instruction
Insertion also requires constant-space allocation:
Focused on 2nd edge Focused on edgeafter new instruction
F
M
L
Focus
F
M
M
L
Focus
![Page 64: An “Integrated Code Generator” for the Glasgow Haskell ... · Functional-programming ideas ease the pain. Functional compiler writers should care about imperative code To run](https://reader034.vdocument.in/reader034/viewer/2022050516/5f9ffab533125402357c7220/html5/thumbnails/64.jpg)
Replacing an instruction
Replacement requires constant-space allocation:
Focused after nodeto replace
Focused after newnode
F
M
M
L
Focus
F
M
M
M
L
Focus
![Page 65: An “Integrated Code Generator” for the Glasgow Haskell ... · Functional-programming ideas ease the pain. Functional compiler writers should care about imperative code To run](https://reader034.vdocument.in/reader034/viewer/2022050516/5f9ffab533125402357c7220/html5/thumbnails/65.jpg)
Deleting an instruction
Deletion requires (half) constant-space allocation:
Focused afterdelendum
Focused on newedge
F
M
M
L
Focus
F
M
M
L
Focus
![Page 66: An “Integrated Code Generator” for the Glasgow Haskell ... · Functional-programming ideas ease the pain. Functional compiler writers should care about imperative code To run](https://reader034.vdocument.in/reader034/viewer/2022050516/5f9ffab533125402357c7220/html5/thumbnails/66.jpg)
Benefits of the zipper
Representation with• No mutable pointers (or pointer invariants)• Single instruction per node• Easy forward and backward traversal• Incremental update (imperative feel)
![Page 67: An “Integrated Code Generator” for the Glasgow Haskell ... · Functional-programming ideas ease the pain. Functional compiler writers should care about imperative code To run](https://reader034.vdocument.in/reader034/viewer/2022050516/5f9ffab533125402357c7220/html5/thumbnails/67.jpg)
Haskell code
![Page 68: An “Integrated Code Generator” for the Glasgow Haskell ... · Functional-programming ideas ease the pain. Functional compiler writers should care about imperative code To run](https://reader034.vdocument.in/reader034/viewer/2022050516/5f9ffab533125402357c7220/html5/thumbnails/68.jpg)
The zipper in Haskell
The “first” node is always a unique identifierdata Block m l = Block BlockId (ZTail m l)data ZTail m l = ZTail m (ZTail m l) | ZLast (ZLast l)-- sequence of m’s followed by single l
data ZLast l = LastExit | LastOther l-- ’fall through’ or a real node
data ZHead m = ZFirst BlockId | ZHead (ZHead m) m-- (reversed) sequence of m’s preceded by BlockId
data Graph m l =Graph (ZTail m l) (BlockEnv (Block m l))-- entry sequence paired with collection of blocks
data LGraph m l =LGraph BlockId (BlockEnv (Block m l))-- for dataflow, every block bears a label
![Page 69: An “Integrated Code Generator” for the Glasgow Haskell ... · Functional-programming ideas ease the pain. Functional compiler writers should care about imperative code To run](https://reader034.vdocument.in/reader034/viewer/2022050516/5f9ffab533125402357c7220/html5/thumbnails/69.jpg)
Instantiating the zipper
data Middle= Assign CmmReg CmmExpr -- Assign to register| Store CmmExpr CmmExpr -- Store to memory| UnsafeCall CmmCallTarget CmmResults CmmActuals
-- a ’fat machine instruction’data Last= Branch BlockId -- Goto block in this proc| CondBranch { -- conditional branch
cml_pred :: CmmExpr,cml_true, cml_false :: BlockId
}| Return -- Function return| Jump CmmExpr -- Tail call| Call { -- Function call
cml_target :: CmmExpr,cml_cont :: Maybe BlockId }
-- cml_cont present if call returns
![Page 70: An “Integrated Code Generator” for the Glasgow Haskell ... · Functional-programming ideas ease the pain. Functional compiler writers should care about imperative code To run](https://reader034.vdocument.in/reader034/viewer/2022050516/5f9ffab533125402357c7220/html5/thumbnails/70.jpg)
Ask me about CmmSpillReload.hs
At every Call site,• Every live variable must be saved on the
“Haskell stack”
Given: C -- with local variables live across calls
Produce: C -- with spills and reloads,nothing live in a register at any call
(Code produced on demand)
![Page 71: An “Integrated Code Generator” for the Glasgow Haskell ... · Functional-programming ideas ease the pain. Functional compiler writers should care about imperative code To run](https://reader034.vdocument.in/reader034/viewer/2022050516/5f9ffab533125402357c7220/html5/thumbnails/71.jpg)
Beyond be dragons
![Page 72: An “Integrated Code Generator” for the Glasgow Haskell ... · Functional-programming ideas ease the pain. Functional compiler writers should care about imperative code To run](https://reader034.vdocument.in/reader034/viewer/2022050516/5f9ffab533125402357c7220/html5/thumbnails/72.jpg)
Simple facts might be enough
Transfers, rewrites can compose.
Conjoin facts:
(<*>) :: Transfer a -> Transfer b
-> Transfer (a, b)
Sum rewrites:
(<+) :: Rewrite a -> Rewrite a -> Rewrite a
Rewrite based on conjoined facts:
liftR :: (b -> a) -> Rewrite a -> Rewrite b