1<!---2// Copyright 2018 The Go Authors. All rights reserved.3// Use of this source code is governed by a BSD-style4// license that can be found in the LICENSE file.5-->67## Introduction to the Go compiler's SSA backend89This package contains the compiler's Static Single Assignment form component. If10you're not familiar with SSA, its [Wikipedia11article](https://en.wikipedia.org/wiki/Static_single_assignment_form) is a good12starting point.1314It 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 an16overview of the compiler, and explains what is SSA's part and purpose in it.1718### Key concepts1920The names described below may be loosely related to their Go counterparts, but21note that they are not equivalent. For example, a Go block statement has a22variable scope, yet SSA has no notion of variables nor variable scopes.2324It may also be surprising that values and blocks are named after their unique25sequential IDs. They rarely correspond to named entities in the original code,26such as variables or function parameters. The sequential IDs also allow the27compiler to avoid maps, and it is always possible to track back the values to Go28code using debug and position information.2930#### Values3132Values are the basic building blocks of SSA. Per SSA's very definition, a33value is defined exactly once, but it may be used any number of times. A value34mainly consists of a unique identifier, an operator, a type, and some arguments.3536An operator or `Op` describes the operation that computes the value. The37semantics 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:4041 // var c uint8 = a + b42 v4 = Add8 <uint8> v2 v34344A value's type will usually be a Go type. For example, the value in the example45above 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 cover47`memory`, the most common of them.4849Some operators contain an auxiliary field. The aux fields are usually printed as50enclosed in `[]` or `{}`, and could be the constant op argument, argument type,51etc. For example:5253 v13 (?) = Const64 <int> [1]5455Here the aux field is the constant op argument, the op is creating a `Const64`56value of 1. One more example:5758 v17 (361) = Store <mem> {int} v16 v14 v85960Here the aux field is the type of the value being `Store`ed, which is int.6162See [value.go](value.go) and `_gen/*Ops.go` for more information.6364#### Memory types6566`memory` represents the global memory state. An `Op` that takes a memory67argument depends on that memory state, and an `Op` which has the memory type68impacts the state of memory. This ensures that memory operations are kept in the69right order. For example:7071 // *a = 372 // *b = *a73 v10 = Store <mem> {int} v6 v8 v174 v14 = Store <mem> {int} v7 v8 v107576Here, `Store` stores its second argument (of type `int`) into the first argument77(of type `*int`). The last argument is the memory state; since the second store78depends on the memory value defined by the first store, the two stores cannot be79reordered.8081See [cmd/compile/internal/types/type.go](../types/type.go) for more information.8283#### Blocks8485A block represents a basic block in the control flow graph of a function. It is,86essentially, a list of values that define the operation of this block. Besides87the list of values, blocks mainly consist of a unique identifier, a kind, and a88list of successor blocks.8990The simplest kind is a `plain` block; it simply hands the control flow to91another block, thus its successors list contains one block.9293Another common block kind is the `exit` block. These have a final value, called94control value, which must return a memory state. This is necessary for functions95to return some values, for example - the caller needs some memory state to96depend on, to ensure that it receives those return values correctly.9798The last important block kind we will mention is the `if` block. It has a single99control value that must be a boolean value, and it has exactly two successor100blocks. The control flow is handed to the first successor if the bool is true,101and to the second otherwise.102103Here is a sample if-else control flow represented with basic blocks:104105 // func(b bool) int {106 // if b {107 // return 2108 // }109 // return 3110 // }111 b1:112 v1 = InitMem <mem>113 v2 = SP <uintptr>114 v5 = Addr <*int> {~r1} v2115 v6 = Arg <bool> {b}116 v8 = Const64 <int> [2]117 v12 = Const64 <int> [3]118 If v6 -> b2 b3119 b2: <- b1120 v10 = VarDef <mem> {~r1} v1121 v11 = Store <mem> {int} v5 v8 v10122 Ret v11123 b3: <- b1124 v14 = VarDef <mem> {~r1} v1125 v15 = Store <mem> {int} v5 v12 v14126 Ret v15127128<!---129TODO: can we come up with a shorter example that still shows the control flow?130-->131132See [block.go](block.go) for more information.133134#### Functions135136A function represents a function declaration along with its body. It mainly137consists of a name, a type (its signature), a list of blocks that form its body,138and the entry block within said list.139140When a function is called, the control flow is handed to its entry block. If the141function terminates, the control flow will eventually reach an exit block, thus142ending the function call.143144Note that a function may have zero or multiple exit blocks, just like a Go145function can have any number of return points, but it must have exactly one146entry point block.147148Also note that some SSA functions are autogenerated, such as the hash functions149for each type used as a map key.150151For example, this is what an empty function can look like in SSA, with a single152exit block that returns an uninteresting memory state:153154 foo func()155 b1:156 v1 = InitMem <mem>157 Ret v1158159See [func.go](func.go) for more information.160161### Compiler passes162163Having a program in SSA form is not very useful on its own. Its advantage lies164in how easy it is to write optimizations that modify the program to make it165better. The way the Go compiler accomplishes this is via a list of passes.166167Each pass transforms a SSA function in some way. For example, a dead code168elimination pass will remove blocks and values that it can prove will never be169executed, and a nil check elimination pass will remove nil checks which it can170prove to be redundant.171172Compiler passes work on one function at a time, and by default run sequentially173and exactly once.174175The `lower` pass is special; it converts the SSA representation from being176machine-independent to being machine-dependent. That is, some abstract operators177are replaced with their non-generic counterparts, potentially reducing or178increasing the final number of values.179180<!---181TODO: Probably explain here why the ordering of the passes matters, and why some182passes like deadstore have multiple variants at different stages.183-->184185See the `passes` list defined in [compile.go](compile.go) for more information.186187### Playing with SSA188189A good way to see and get used to the compiler's SSA in action is via190`GOSSAFUNC`. For example, to see func `Foo`'s initial SSA form and final191generated assembly, one can run:192193 GOSSAFUNC=Foo go build194195The generated `ssa.html` file will also contain the SSA func at each of the196compile passes, making it easy to see what each pass does to a particular197program. You can also click on values and blocks to highlight them, to help198follow the control flow and values.199200The value specified in GOSSAFUNC can also be a package-qualified function201name, e.g.202203 GOSSAFUNC=blah.Foo go build204205This will match any function named "Foo" within a package whose final206suffix is "blah" (e.g. something/blah.Foo, anotherthing/extra/blah.Foo).207208The users may also print the Control Flow Graph(CFG) by specifying in209`GOSSAFUNC` value in the following format:210211 GOSSAFUNC="$FunctionName:$PassName1,$PassName2,..." go build212213For example, the following command will print SSA with CFGs attached to the214`sccp` and `generic deadcode` pass columns:215216 GOSSAFUNC="blah.Foo:sccp,generic deadcode" go build217218If non-HTML dumps are needed, append a "+" to the GOSSAFUNC value219and dumps will be written to stdout:220221 GOSSAFUNC=Bar+ go build222223<!---224TODO: need more ideas for this section225-->226227### Hacking on SSA228229While most compiler passes are implemented directly in Go code, some others are230code generated. This is currently done via rewrite rules, which have their own231syntax and are maintained in `_gen/*.rules`. Simpler optimizations can be written232easily and quickly this way, but rewrite rules are not suitable for more complex233optimizations.234235To read more on rewrite rules, have a look at the top comments in236[_gen/generic.rules](_gen/generic.rules) and [_gen/rulegen.go](_gen/rulegen.go).237238Similarly, the code to manage operators is also code generated from239`_gen/*Ops.go`, as it is easier to maintain a few tables than a lot of code.240After changing the rules or operators, run `go generate cmd/compile/internal/ssa`241to generate the Go code again.242243<!---244TODO: more tips and info could likely go here245-->
Findings
✓ No findings reported for this file.