cmd/compile/internal/ssa: add initial README

This is the first version of an introductory document that should help
developers who want to get started with this package.

I recently started poking around this part of the compiler, and was
confused by a few basic ideas such as memory arguments. I also hadn't
heard about GOSSAFUNC until another developer pointed it out. Both of
those are essential if one wants to do any non-trivial work here.

This document can of course be expanded with more pointers and tips to
better understand this package's code and behavior. Its intent is not to
cover all of its features; but it should be enough for most developers
to start playing with it without extensive compiler experience.

Change-Id: Ifd2d047fbd038ab50f4625a15c4d49932b42fd66
Reviewed-on: https://go-review.googlesource.com/99715
Reviewed-by: Josh Bleecher Snyder <josharian@gmail.com>
This commit is contained in:
Daniel Martí 2018-03-08 21:47:17 +00:00
parent 8a525b8e7f
commit ec60e4a0d2

View file

@ -0,0 +1,59 @@
This package contains the compiler's Static Single Assignment form
component. If you're not familiar with SSA, Wikipedia is a good starting
point:
https://en.wikipedia.org/wiki/Static_single_assignment_form
SSA is useful to perform transformations and optimizations, which can be
found in this package in the form of compiler passes and rewrite rules.
The former can be found in the "passes" array in compile.go, while the
latter are generated from gen/*.rules.
Like most other SSA forms, funcs consist of blocks and values. Values
perform an operation, which is encoded in the form of an operator and a
number of arguments. The semantics of each Op can be found in
gen/*Ops.go.
gen/* is used to generate code in the ssa package. This includes
opGen.go from gen/*Ops.go, and the rewrite*.go files from gen/*.rules.
To regenerate these files, see gen/README.
Blocks can have multiple forms. For example, BlockPlain will always hand
the control flow to another block, and BlockIf will flow to one of two
blocks depending on a value. See block.go for more details.
Values also have types. For example, a constant boolean value will have
a Bool type, and a variable definition value will have a memory type.
The memory type is special - it represents the global memory state. For
example, an Op that takes a memory argument depends on that memory
state, and an Op which has the memory type impacts the state of memory.
This is important so that memory operations are kept in the right order.
For example, take this program:
func f(a, b *int) {
*a = 3
*b = *a
}
The two generated stores may show up as follows:
v10 (4) = Store <mem> {int} v6 v8 v1
v14 (5) = Store <mem> {int} v7 v8 v10
Since the second store has a memory argument v10, it cannot be reordered
before the first store, which sets that global memory state. And the
logic translates to the code; reordering the two assignments would
result in a different program.
A good way to see and get used to the compiler's SSA in action is via
GOSSAFUNC. For example, to see func Foo's initial SSA form and final
generated assembly, one can run:
GOSSAFUNC=Foo go build
The generated ssa.html file will also contain the SSA func at each of
the compile passes, making it easy to see what each pass does to a
particular program. You can also click on values and blocks to highlight
them, to help follow the control flow and values.