| 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. |