Go Time – Episode #27

The Go Compiler and Go 1.8

with Keith Randall

All Episodes

Keith Randall from the Go team joined the show to talk about why a new compiler, what we gain from SSA, what’s next for the compiler, Go 1.8, and the goals/plans for Go 1.9.

Featuring

Sponsors

Linode – Our cloud server of choice. Get one of the fastest, most efficient SSD cloud servers for only $5/mo. Use the code changelog2017 to get 4 months free!

Fastly – Our bandwidth partner. Fastly powers fast, secure, and scalable digital experiences. Move beyond your content delivery network to their powerful edge cloud platform.

StackImpact – StackImpact is all about profiling and monitoring for Go. Laser focus on the performance of your Go applications.

Backtrace – Reduce your time to resolution. Go beyond stacktraces and logs. Get to the root cause quickly with deep application introspection at your fingertips.

Notes & Links

📝 Edit Notes

Free Software Friday

Transcript

📝 Edit Transcript

Changelog

Play the audio to listen along while you enjoy the transcript. 🎧

It is episode #27 of GoTime. Today on the show we have myself, Erik St. Martin, we have Carlisia Pinto…

Brian Ketelsen is out today, and filling in for him today is Bill Kennedy. Say hello, Bill…

Hi, everybody.

And our special guest today actually taught us all how to make a lot of profit using maps at GopherCon. I’m still waiting for my check, but on the show today is Keith Randall from the Go team.

Hello, everybody.

Do you wanna give everybody a rundown - who you are, what you do specifically on the Go team?

Sure. I work on Go runtime internals and compilers. I work on making Go faster, all behind the scenes. You don’t sort of see anything I do in APIs or anything like that, but every release we make things a little bit faster and a little bit less memory, and all-around better.

That’s awesome. So you specifically work on the compiler and runtime?

Correct. I sort of started out working on Go, working on runtime things like maps, scheduler, some of the type conversion stuff and so on. More recently I’ve been working on compiler internals, making generated code better, smaller, that sort of thing.

That’s awesome. Have you played a big role in SSA stuff that happened over the last couple of releases?

Yeah, so I started the SSA backend project, proposed it, got people on board with it and sort of was the tech lead for it. I wrote the first prototype and then got a bunch of other people both from inside Google and outside to help work on it. It was released in 1.7 for amd64. For this upcoming release, 1.8, it’s gonna be available on all of the other architectures: arm, MIPS, PowerPC and so on. I think maybe even there’s a SPARC one coming, I’m not sure whether that’s gonna make 1.8.

Oh, nice.

Yeah, and the performance we get on x86, it was something like 20% better. It very much depends on the application, but we’re getting on average about 20% better, mostly because the x86 chips are really good at executing bad code, so you really have to do a good job of making better code before you can see the performance improvements. We’re getting something more like 40% better on ARM chips, which are not as good as hiding the old bad code. I think it turned out pretty well overall.

Yeah, and ARM needs the love even more, because ARM typically doesn’t have the clock rate that an x86 chip does.

Right, absolutely.

Those performance improvements help a lot.

And the performance improvements help save power, too. That’s also a big thing.

Yeah, that’s true as well. We should probably circle back a little bit to when we talked about SSA and maybe give a brief explanation of what SSA is and why that benefits us to have the compiler leverage SSA.

Okay. I guess at first it’d help to describe what the old compiler was like. The old compiler used to take the abstract syntax tree of a Go program and would generate code sort of node-by-node on that syntax tree. If there was a plus, it would load both arguments into registers, do the plus and then store the result somewhere.

[04:02] It would do that one at a time on the nodes of the syntax tree, with no look ahead, very little look behind… The code it generated wasn’t very good, because there were a lot of moves you didn’t need, there were a lot of operations that if you did that same add twice, it would execute that add twice instead of reusing the result.

So SSA instead takes the abstract syntax tree and builds a control flow graph, and a value graph. And then we can do all sorts of optimizations on that graph, like common self-expression elimination, we can do bounds check elimination, we can do better scheduling, dead code elimination, all that sort of stuff - all of which benefit the generated code and make it better than what was generated previously straight from the abstract syntax tree.

SSA compilers have been around for a while. I know I’ve worked on one 15 years ago, so it’s a pretty mature compiler technology. GCC uses it, LLVM uses it… It’s a pretty common compiler technology. This is not sort of a researchy thing; SSA is known to be a good way to generate code for compilers. We need to get Go up to speed so that we can compete with the other languages.

I’ve got a quick question, because I’ve always tried to visualize these things that are going on… So this piece is happening inside of the compiler; is this helping to generate that intermediate assembly? Is that kind of where this is? Where in the toolchain between the compiler, the assembler and the linker is all this sitting?

Fair enough. So when you start with Go code, there is a parser that basically takes that Go code and makes an internal in-memory representation of the abstract syntax tree. From there, SSA takes that abstract syntax tree and generates assembly code, that is actually sort of an in-memory representation of the assembly code. It’s sort of semi already assembled, and then that gets passed to the linker and the code generator from there. Basically, the input is an abstract syntax tree and the output is an in-memory representation of assembly.

Okay, so this would actually be an IR… Bill and I were actually kind of having this debate before the show - the difference between an intermediate representation and an intermediate language. And the best I could come up with is that an intermediate language is actually produced code, whereas IR is typically in-memory data structure, but I could be completely wrong there, too.

Yeah, I don’t think I’ve ever heard the term “intermediate code”…

Or intermediate language.

Yeah, or intermediate language… I don’t know. It’s a good question. So LLVM has something which maybe I would call an intermediate language; it’s an actual textual representation of the IR.

Yeah, that was my interpretation of the difference between the two. I’ve always heard IR, and then Bill said IL this morning and I was like, “Hm…”

I think I got that from the .NET side of things over there… They have a whole intermediate language over there between what the C# compiler is producing, if I remember…

Yeah, I believe it’s like Java, they have some sort of bytecode thing, right?