
New SSA Back End for the Go Compiler (2015) - gjvc
https://docs.google.com/document/d/1szwabPJJc4J-igUZU4ZKprOrNRNJug2JPD8OYi3i1K0/edit
======
willtim
I find it somewhat ironic that most mainstream compilers now transform
imperative code into a functional language in order to reason about the code.

~~~
chubot
And then your CPU does it again! After all that work, your compiler outputs a
totally ordered stream of instructions; then the CPU tries to figure out data
dependencies in hardware and execute instructions out of order and in
parallel.

It seems as though C-like imperative languages and x86 are baked in forever...
but the _world_ is actually parallel.

~~~
marssaxman
I've recently been thinking that we are looking at a situation analogous to
the one Ben Franklin was in when he identified the two types of electrical
charge as "positive" or "negative" pressure in the "electrical fluid" \- he
took a guess, which happened to be wrong, and ever since we have been stuck
describing a surplus of electrons as "negative" and a deficit as "positive".
This is no obstacle for the experienced but will remain an eternal hangup for
beginners.

By analogy, of course, I am suggesting that the Church model of computation
might have served us better as a foundation than the Turing model has done,
since it seems that everything's turning up lambdas as the technology S-curve
for silicon computers continues to flatten out.

~~~
chubot
I don't really agree... One reason is that computing models don't say anything
useful about I/O, which we need in real computers. Turing machines have a
straightforward extension to incorporate I/O -- execute it as a side effect at
a given step.

In contrast, the Church model doesn't really have any notion of time, so it's
not clear how to reason about I/O. What evaluation order is used?

In terms of computation, they're of course equivalent, so you can execute the
Church model on the Turing-like machines (or more specifically a Von Neumann
architecture). So maybe that was the right "choice" (if there ever was one).

There was an entire movement around dataflow processors AND dataflow languages
in the 80's, where the instruction sets were not totally ordered (e.g. SISAL
was single assignment). But these didn't fare well in the market.

Closer to the ground, there is a pattern of "throwing away information at
interfaces" in computing. Interfaces like x86, C, Unix, etc. get solidified by
evolutionary forces. The cost of that modularity is global inefficiency.

Another good example of that is the Java code gen architecture. People say
"static types in Java code let you generated better code!" Well, no. The Java
compiler throws out all the type information, generating Java byte code, which
is dynamically typed. Then the JIT takes the byte code and has to re-infer all
the type invariants to generate machine code.

~~~
dang
> _There was an entire movement around dataflow processors AND dataflow
> languages in the 80 's, where the instruction sets were not totally ordered
> (e.g. SISAL was single assignment). But these didn't fare well in the
> market._

My understanding is that the dataflow architectures didn't fare well for
technical reasons. The instruction-level parallelism they worked with turned
out to be too fine-grained, i.e. the cost of scheduling was greater than the
win of parallelism for many programs, especially normal sequential programs
that still need to be fast. This led to research in coarse-grained dataflow,
but it doesn't seem that much has come of that.

[https://www.cs.ucf.edu/~dcm/Teaching/COT4810-Fall%202012/Lit...](https://www.cs.ucf.edu/~dcm/Teaching/COT4810-Fall%202012/Literature/DataFlowProgrammingLanguages.pdf)

------
dantillberg
Previous discussion:
[https://news.ycombinator.com/item?id=9099744](https://news.ycombinator.com/item?id=9099744)

------
jheriko
i do wonder why they didn't go with llvm...

~~~
tomp
It's answered in the post:

 _A common question that comes up is “why not just convert to the IR of
{llvm,gcc,...} and go from there?” I think there are 3 major reasons:

\- Compiler speed. I intend our SSA IR, and the optimizer passes implemented
on top of that IR, to be fast by design. We’ll aim for linear-time algorithms
wherever possible. The backends of other possible compilers weren’t really
designed with fast compile speed in mind.

\- Runtime information. The runtime needs accurate maps of stack frames for
both GC and stack copying, something that is not available from standard
backends today.

\- An additional dependence. Do we want a {llvm,gcc,...} backend as a
prerequisite for building Go? (Note that this would only be an issue for those
developing Go, not those writing Go programs.)

I’m happy to be convinced otherwise - maybe we should throw our effort into
getting frame maps out of {llvm,gcc,...} and figuring out how to configure the
backend (e.g. which optimizations to turn on) to make it compile quickly._

~~~
DannyBee
Note, for the record, none of these are correct except for the last one:

1\. LLVM's SSA based compiler currently uses more linear time algorithms than
Go's SSA backend (IE phi placement, etc), and in more places. So yeah. While
parts of LLVM definitely could be sped up ( _particularly the backend_ ), it
was _originally_ designed with fast compile speed in mind, just like go! Given
how many years it's taken so far, you easily could have gotten the same thing
out of LLVM. Would it have been more work? Probably, but not much. Are the
other reasons not to do it? Yes. But the idea that their compiler is somehow
the only one designed with fast compile time in mind is, honestly, pretty
arrogant

2\. Stack maps have been supported for quite a while, and statepoint support
now exists and is used by real people in real places.

But i'll also just point out he's never actually asked, or talked to the LLVM
folks about it (search the mailing list, see if you can find any mail about
it).

Note: I honestly don't care whether they write their own compiler or not. I
suspect it's better for them to do it because of the community they want to
build, because of how much control they want over their toolchain, etc.

But i'm not a fan of saying "someone else's infrastructure sucks, so we are
doing it", when

1\. That's not the real reason as far as i can tell

2\. People are using, in production, the very things they claim don't exist
(and they've been told this, it turns out)

3\. Answers about linear time algorithms are honestly just BS.

~~~
wyldfire
Is "Stack maps" the same as "segmented stacks" that Mr Cox refers to?

~~~
DannyBee
Segmented stacks are basically what safestack offers, and that is also
something llvm does :)

~~~
riscy
No it's not. Segmented stacks are a way of allocating smaller stack segments
that are linked together with pointers and kept in the heap and is a means of
implementing coroutines. Safestack is more complicated and it segregates the
stack into 2 parts to prevent stack buffer overflow attacks.

------
charlieegan3
I was wondering what SSA meant, I think I'm right in saying this is the
correct wikipedia page:
[https://en.wikipedia.org/wiki/Static_single_assignment_form](https://en.wikipedia.org/wiki/Static_single_assignment_form)

~~~
DanWaterworth
Yes. SSA intermediate representations are now common in compilers. Many will
have been exposed to SSA via LLVM.

------
wund
> Just as an experiment I cleaned up the runtime function mapaccess1_fast64 by
> hand in assembly and made it 29% smaller and with a speed improvement too
> small to measure.

This doesn't sound very exciting.

------
sievebrain
Why was the Go compiler not based on SSA form originally? Isn't that kind of
an embarrassment? All industrial compilers I'm aware of completed their
transition to SSA ~15 years ago ... it seems bizarre that a compiler for a
language started in 2009 wouldn't have been that way from the start.

~~~
steveklabnik
Alternative viewpoint: go has also accomplished a lot of its goals for years
without needing this. It could reasonably be viewed as a premature
optimization.

~~~
sievebrain
It's a pretty big architectural change to any compiler, and when _all_ other
major compilers have paid that refactoring cost, it's very strange to want to
go through the transition pain instead of just doing SSA up front like LLVM
did.

