1<!---
2// Copyright 2018 The Go Authors. All rights reserved.
3// Use of this source code is governed by a BSD-style
4// license that can be found in the LICENSE file.
5-->
6
7## Introduction to the Go compiler's SSA backend
8
9This package contains the compiler's Static Single Assignment form component. If
10you're not familiar with SSA, its [Wikipedia
11article](https://en.wikipedia.org/wiki/Static_single_assignment_form) is a good
12starting point.
13
14It is recommended that you first read [cmd/compile/README.md](../../README.md)
15if you are not familiar with the Go compiler already. That document gives an
16overview of the compiler, and explains what is SSA's part and purpose in it.
17
18### Key concepts
19
20The names described below may be loosely related to their Go counterparts, but
21note that they are not equivalent. For example, a Go block statement has a
22variable scope, yet SSA has no notion of variables nor variable scopes.
23
24It may also be surprising that values and blocks are named after their unique
25sequential IDs. They rarely correspond to named entities in the original code,
26such as variables or function parameters. The sequential IDs also allow the
27compiler to avoid maps, and it is always possible to track back the values to Go
28code using debug and position information.
29
30#### Values
31
32Values are the basic building blocks of SSA. Per SSA's very definition, a
33value is defined exactly once, but it may be used any number of times. A value
34mainly consists of a unique identifier, an operator, a type, and some arguments.
35
36An operator or `Op` describes the operation that computes the value. The
37semantics of each operator can be found in `_gen/*Ops.go`. For example, `OpAdd8`
38takes two value arguments holding 8-bit integers and results in their addition.
39Here is a possible SSA representation of the addition of two `uint8` values:
40
41 // var c uint8 = a + b
42 v4 = Add8 <uint8> v2 v3
43
44A value's type will usually be a Go type. For example, the value in the example
45above has a `uint8` type, and a constant boolean value will have a `bool` type.
46However, certain types don't come from Go and are special; below we will cover
47`memory`, the most common of them.
48
49Some operators contain an auxiliary field. The aux fields are usually printed as
50enclosed in `[]` or `{}`, and could be the constant op argument, argument type,
51etc.
52for example:
53
54 v13 (?) = Const64 <int> [1]
55
56Here the aux field is the constant op argument, the op is creating a `Const64`
57value of 1. One more example:
58
59 v17 (361) = Store <mem> {int} v16 v14 v8
60
61Here the aux field is the type of the value being `Store`ed, which is int.
62
63See [value.go](value.go) and `_gen/*Ops.go` for more information.
64
65#### Memory types
66
67`memory` represents the global memory state. An `Op` that takes a memory
68argument depends on that memory state, and an `Op` which has the memory type
69impacts the state of memory. This ensures that memory operations are kept in the
70right order. For example:
71
72 // *a = 3
73 // *b = *a
74 v10 = Store <mem> {int} v6 v8 v1
75 v14 = Store <mem> {int} v7 v8 v10
76
77Here, `Store` stores its second argument (of type `int`) into the first argument
78(of type `*int`). The last argument is the memory state; since the second store
79depends on the memory value defined by the first store, the two stores cannot be
80reordered.
81
82See [cmd/compile/internal/types/type.go](../types/type.go) for more information.
83
84#### Blocks
85
86A block represents a basic block in the control flow graph of a function. It is,
87essentially, a list of values that define the operation of this block. Besides
88the list of values, blocks mainly consist of a unique identifier, a kind, and a
89list of successor blocks.
90
91The simplest kind is a `plain` block; it simply hands the control flow to
92another block, thus its successors list contains one block.
93
94Another common block kind is the `exit` block. These have a final value, called
95control value, which must return a memory state. This is necessary for functions
96to return some values, for example - the caller needs some memory state to
97depend on, to ensure that it receives those return values correctly.
98
99The last important block kind we will mention is the `if` block. It has a single
100control value that must be a boolean value, and it has exactly two successor
101blocks. The control flow is handed to the first successor if the bool is true,
102and to the second otherwise.
103
104Here is a sample if-else control flow represented with basic blocks:
105
106 // func(b bool) int {
107 // if b {
108 // return 2
109 // }
110 // return 3
111 // }
112 b1:
113 v1 = InitMem <mem>
114 v2 = SP <uintptr>
115 v5 = Addr <*int> {~r1} v2
116 v6 = Arg <bool> {b}
117 v8 = Const64 <int> [2]
118 v12 = Const64 <int> [3]
119 If v6 -> b2 b3
120 b2: <- b1
121 v10 = VarDef <mem> {~r1} v1
122 v11 = Store <mem> {int} v5 v8 v10
123 Ret v11
124 b3: <- b1
125 v14 = VarDef <mem> {~r1} v1
126 v15 = Store <mem> {int} v5 v12 v14
127 Ret v15
128
129<!---
130TODO: can we come up with a shorter example that still shows the control flow?
131-->
132
133See [block.go](block.go) for more information.
134
135#### Functions
136
137A function represents a function declaration along with its body. It mainly
138consists of a name, a type (its signature), a list of blocks that form its body,
139and the entry block within said list.
140
141When a function is called, the control flow is handed to its entry block. If the
142function terminates, the control flow will eventually reach an exit block, thus
143ending the function call.
144
145Note that a function may have zero or multiple exit blocks, just like a Go
146function can have any number of return points, but it must have exactly one
147entry point block.
148
149Also note that some SSA functions are autogenerated, such as the hash functions
150for each type used as a map key.
151
152For example, this is what an empty function can look like in SSA, with a single
153exit block that returns an uninteresting memory state:
154
155 foo func()
156 b1:
157 v1 = InitMem <mem>
158 Ret v1
159
160See [func.go](func.go) for more information.
161
162### Compiler passes
163
164Having a program in SSA form is not very useful on its own. Its advantage lies
165in how easy it is to write optimizations that modify the program to make it
166better. The way the Go compiler accomplishes this is via a list of passes.
167
168Each pass transforms a SSA function in some way. For example, a dead code
169elimination pass will remove blocks and values that it can prove will never be
170executed, and a nil check elimination pass will remove nil checks which it can
171prove to be redundant.
172
173Compiler passes work on one function at a time, and by default run sequentially
174and exactly once.
175
176The `lower` pass is special; it converts the SSA representation from being
177machine-independent to being machine-dependent. That is, some abstract operators
178are replaced with their non-generic counterparts, potentially reducing or
179increasing the final number of values.
180
181<!---
182TODO: Probably explain here why the ordering of the passes matters, and why some
183passes like deadstore have multiple variants at different stages.
184-->
185
186See the `passes` list defined in [compile.go](compile.go) for more information.
187
188### Playing with SSA
189
190A good way to see and get used to the compiler's SSA in action is via
191`GOSSAFUNC`. For example, to see func `Foo`'s initial SSA form and final
192generated assembly, one can run:
193
194 GOSSAFUNC=Foo go build
195
196The generated `ssa.html` file will also contain the SSA func at each of the
197compile passes, making it easy to see what each pass does to a particular
198program. You can also click on values and blocks to highlight them, to help
199follow the control flow and values.
200
201The value specified in GOSSAFUNC can also be a package-qualified function
202name, e.g.
203
204 GOSSAFUNC=blah.Foo go build
205
206This will match any function named "Foo" within a package whose final
207suffix is "blah" (e.g. something/blah.Foo, anotherthing/extra/blah.Foo).
208
209If non-HTML dumps are needed, append a "+" to the GOSSAFUNC value
210and dumps will be written to stdout:
211
212 GOSSAFUNC=Bar+ go build
213
214<!---
215TODO: need more ideas for this section
216-->
217
218### Hacking on SSA
219
220While most compiler passes are implemented directly in Go code, some others are
221code generated. This is currently done via rewrite rules, which have their own
222syntax and are maintained in `_gen/*.rules`. Simpler optimizations can be written
223easily and quickly this way, but rewrite rules are not suitable for more complex
224optimizations.
225
226To read more on rewrite rules, have a look at the top comments in
227[_gen/generic.rules](_gen/generic.rules) and [_gen/rulegen.go](_gen/rulegen.go).
228
229Similarly, the code to manage operators is also code generated from
230`_gen/*Ops.go`, as it is easier to maintain a few tables than a lot of code.
231After changing the rules or operators, run `go generate cmd/compile/internal/ssa`
232to generate the Go code again.
233
234<!---
235TODO: more tips and info could likely go here
236-->
View as plain text