
Golang dev.ssa branch merged into tip - signa11
https://github.com/golang/go/commit/a6fb2aede7c8d47b4d913eb83fa45bbeca76c433
======
nikolay
[https://en.wikipedia.org/wiki/Static_single_assignment_form](https://en.wikipedia.org/wiki/Static_single_assignment_form)

------
UniQP
After libfirm [1], the Go compiler now seems to be the second mature compiler
with an SSA-based backend. I hope more compilers will follow.

I missed some references to corresponding papers in the source code. For
instance, is the register allocator an implementation of "Linear Scan Register
Allocation on SSA Form" [2]?

Also some facts mention in comments [3] are a bit scary but I guess this will
be resolved over time.

[1] [http://pp.ipd.kit.edu/firm/](http://pp.ipd.kit.edu/firm/)

[2]
[http://www.christianwimmer.at/Publications/Wimmer10a/Wimmer1...](http://www.christianwimmer.at/Publications/Wimmer10a/Wimmer10a.pdf)

[3]
[https://github.com/golang/go/blob/master/src/cmd/compile/int...](https://github.com/golang/go/blob/master/src/cmd/compile/internal/ssa/regalloc.go#L66)

~~~
electrum
According to Wikipedia, SSA is used extensively by GCC, LLVM and every major
JIT:
[https://en.wikipedia.org/wiki/Static_single_assignment_form#...](https://en.wikipedia.org/wiki/Static_single_assignment_form#Compilers_using_SSA_form)

~~~
UniQP
Yes, in the middle end, but they don't have an SSA-based back end (for example
SSA-based register allocation).

~~~
DannyBee
Most of LLVM's backend is SSA, actually. At some point it lowers out of SSA,
but you have to do that at some point anyway.

It happens that LLVM does instruction selection and scheduling on SSA but not
regalloc (it does phi elimination before regalloc, though uses ssa based
liveness info in regalloc)

My take: Who cares? If someone wants to make register allocation SSA based,
and demonstrates code or speed or maintenance or whatever benefits, great.

There are theoretical benefits, but in practice, LLVM does pretty well with
it's current scheme.

Because of this, it's not really near the top of any todo list, nor should it
be.

~~~
UniQP
> At some point it lowers out of SSA, but you have to do that at some point
> anyway.

libfirm never goes out of SSA (since it uses a graph-based representation it's
simply impossible: the data dependency edges need _one_ target). It converts
the programm to CSSA and assigns the same register to all phi operands. When
finally emitting the program, phi nodes emit nothing.

~~~
DannyBee
Okay, sure, this is pretty much the same thing for a graph based IR. You can
argue this isn't a form of lowering, but in practice, it doesn't matter.

Note that your claim "(since it uses a graph-based representation it's simply
impossible: the data dependency edges need one target)"

is wrong :)

SSA also requires that things have a single, unique, reaching definition.

The fact that the graph edges have one target does not guarantee this (it is
instead a representation that requires this for correctness) Open64 is another
compiler with factored use-def chains like this (though the rest is not graph
based), and has the same issue -

If you hoist something to various valid points (IE across existing live
ranges), it's possible to generate multiple reaching definitions. This is
because the dataflow definition of reaching definitions is not "whatever is on
the end of this graph edge". So the fact that the graph edges only point to
one of those definitions just makes the graph edges wrong.

So it's not impossible, but libfirm avoids it or performs the necessary phi
insertion in various places to avoid creating invalid SSA for the
representation it has.

(Note: It is possible to have IR's where the _only_ ordering is a data
dependence ordering, and so the graph is the source of truth and where it
points is where it points. There are also representations where the control
flow is implied by the graph nodes. In these representations, what you say
would be correct. From what i know of libfirm, it has basic blocks and control
flow edges, and it uses that to give some ordering. In this world, it's
possible to screw up the SSA properties with pretty simple operations, and
make the graph _no longer correct_ )

~~~
UniQP
> So it's not impossible, but libfirm avoids it or performs the necessary phi
> insertion in various places to avoid creating invalid SSA for the
> representation it has.

It's impossible to have one edge pointing to multiple reaching definitions.

~~~
DannyBee
Of course, but I think you missed the point of what i said. Which was: It's
possible to get into situations where that that node _could have multiple
possible reaching definitions_ , even if it only points to one at a given
time. That is still not SSA. In that case, the edge is just wrong, even if it
only points to one arbitrarily selected possible reaching definition.

In short: Your argument is "it's SSA because the data structures only allow
for a single reaching definition". This is not right. If i don't insert phi
nodes, and just have the IR point at random reaching definitions, it's not
magically SSA, because _there is not actually a unique reaching definition for
each point_ , it just happens you've pointed the edges at arbitrarily selected
reaching definitions (IE made the graph wrong :P)

------
goldfire
So... not been closely following development on Go. What does this mean?

~~~
vastbinderj
It is the new backend for the Go Compiler

See:
[https://docs.google.com/document/d/1szwabPJJc4J-igUZU4ZKprOr...](https://docs.google.com/document/d/1szwabPJJc4J-igUZU4ZKprOrNRNJug2JPD8OYi3i1K0)

~~~
gansai
So, currently Stage1 is complete. 2 more to go

~~~
tux1968
From the referenced doc:

    
    
      I’m not entirely convinced that stages 2 & 3 are
      necessary, maybe we stop at stage 1.  It all depends on
      what optimizations we’d like to do that can’t be done
      because the IR is in the wrong form.  Proceeding with
      stages 2 and 3 might gain some efficiency in the compiler
      itself because then we don’t have to generate the old IR
      at all.  I suspect that effect will be small, however.

------
mangeletti
Does this change also pave the way for future changes that would make Go
programs to run faster (e.g., easier to make optimizations during compile
time, something else)?

