6 ms·
What I would give for the developers of the Go toolchain to have spent the last decade improving GCC or LLVM instead of their own bespoke toolchain. In many wa
by benesch 7y ago
What I would give for the developers of the Go toolchain to have spent the last decade improving GCC or LLVM instead of their own bespoke toolchain.
In many ways Go seems like an excuse for Google to fund the continued development of Plan 9. Three of the five most influential people on the Go team (Ken Thompson, Rob Pike, and Russ Cox) were heavily involved in Plan 9. And it shows. Go's toolchain is a direct descendant of the Plan 9 toolchain; in fact, the Go language is really just an evolution of the special C dialect that Plan 9 used [1]. Indeed, for a while, the Go compiler was written in this special dialect of C, and so building Go required building a C compiler (!) that could compile this custom dialect of C, and using that to compile the Go compiler [2].
By all rights, Plan 9 was an interesting research project, and seems well loved by those familiar with it. (I'm not personally familiar; it was well before my time.) But it never took off. What we ended up with is Linux, macOS, and Windows.
Go very much wants to be Plan 9. Sure, it's not a full-fledged operating system. But it's a linker, assembler, compiler, binutils, and scheduler. All it asks of the host system is memory management, networking, and filesystem support, and it will happily replace your system's DNS resolution with a pure Go version if you ask it to [3]. I wouldn't be surprised if Go ships its own TCP/IP stack someday [4].
This is, in my opinion, craziness. What other language ships its own assembler?! [5] To make matters worse, the assembly syntax is largely undocumented, and what is documented are the strange, unnecessary quirks, like
> Instructions, registers, and assembler directives are always in UPPER CASE to remind you that assembly programming is a fraught endeavor. (Exception: the g register renaming on ARM.)
> In the general case, the frame size is followed by an argument size, separated by a minus sign. (It's not a subtraction, just idiosyncratic syntax.)
> In Go object files and binaries, the full name of a symbol is the package path followed by a period and the symbol name: fmt.Printf or math/rand.Int. Because the assembler's parser treats period and slash as punctuation, those strings cannot be used directly as identifier names. Instead, the assembler allows the middle dot character U+00B7 and the division slash U+2215 in identifiers and rewrites them to plain period and slash.
The excuse for the custom toolchain has always been twofold, that a) LLVM is too slow, and fast compiles are one of Go's main features, and b) that the core team was too unfamiliar with GCC/LLVM, at least in the early days, and attempting to build Go on top of LLVM would have slowed the speed of innovation to a degree that Go might not exist [6].
I've always been skeptical of argument (b). After all, one of Go's creators literally won a Turing award, as this document not-so-subtly mentions. I'm quite sure they could have figured out how to build an LLVM frontend, given the desire. Rust, for example, is quite a bit more complicated than Go, and Mozilla's developers have had no trouble integrating with LLVM. I suspect the real reason was that hacking on the Plan 9 toolchain was more fun and more familiar—which is a very valid personal reason to work on something! But it doesn't mean it was the right strategic decision.
I will say that (a) is valid. I recently switched from writing Go to writing Rust, and I miss the compile times of Go desperately.
That said—and this is what I can't get past—the state of compilers would be much better off if the folks on the Go team had invested more in improving the compile and link times of LLVM or GCC. Every improvement to lld wouldn't just speed up compiles for Go; it would speed up compiles for C, C++, Swift, Rust, Fortran, Kotlin, and anything else with an LLVM frontend.
In the last year or so, the gollvm project [7] (which is exactly what you'd expect–a Go frontend for LLVM) has seen some very active development, and I'm following along excitedly. Unfortunately I still can't quite tell whether it's Than McIntosh's 20% time project or an actual staffed project of Google's, albeit a small time one. (There are really only two committers, Than and Cherry Zhang.) There are so many optimizations that will likely never be added to gc, like a register-based calling convention [8] and autovectorization, that you essentially get for "free" (i.e., with a bit of plumbing from the frontend) with a mature toolchain like LLVM.
There are not many folks who have the knowledge and expertise to work on compilers and linkers these days, and those that do can command high salaries. Google is in the luxurious position of being able to afford many dozens of these people. I just wish that someone with the power to effect change at Google would realize that the priorities are backwards. gccgo/gollvm are where the primary investment should be occurring, and the gc toolchain should be a side project that makes debug builds fast... not the production compiler, where the quality of the object code is the primary objective.
[0]: https://dave.cheney.net/2013/10/15/how-does-the-go-build-command-work https://dave.cheney.net/2013/10/15/how-does-the-go-build-com...
[1]: http://doc.cat-v.org/plan_9/programming/c_programming_in_plan_9 http://doc.cat-v.org/plan_9/programming/c_programming_in_pla...
[2]: https://docs.google.com/document/d/1P3BLR31VA8cvLJLfMibSuTdwTuF7WWLux71CYD0eeD8/edit https://docs.google.com/document/d/1P3BLR31VA8cvLJLfMibSuTdw...
[3]: https://golang.org/pkg/net/ https://golang.org/pkg/net/
[4]: https://github.com/google/netstack https://github.com/google/netstack
[5]: https://golang.org/doc/asm https://golang.org/doc/asm
[6]: https://golang.org/doc/faq#What_compiler_technology_is_used_to_build_the_compilers https://golang.org/doc/faq#What_compiler_technology_is_used_...
[7]: https://go.googlesource.com/gollvm/ https://go.googlesource.com/gollvm/
[8]: https://github.com/golang/go/issues/18597 https://github.com/golang/go/issues/18597
- enneff 7y ago> the state of compilers would be much better off if the folks on the Go team had invested more in improving the compile and link times of LLVM or GCC It never would have happened. How do you motivate people whose principal frustration is the state of C++ to work on a large C++ codebase? Heterogeneity is a huge benefit to any ecosystem. Improving existing things is great, but building new things is also very important. Go would simply not exist today if it were built on LLVM or GCC.
- loudmax 7y agoAgreed. This argument comes up a lot, especially in open source, that resources on one project would have better spent on some other project. Developer focus is not a fungible commodity. If the Golang devs hadn't been developing the Go compiler, they wouldn't necessarily have spent their efforts on LLVM, they'd just as likely be working on something other way to make Plan9 come about.
- nemo1618 7y ago100% agree -- enthusiasm is not fungible! Sometimes starting over is faster than incremental improvement.
- benesch 7y agoLet me refine my point a bit. Apologies; my original post had gotten a bit long. I agree that enthusiasm is important! And indeed, for the Go creators, their particular leanings might have been such that they couldn't get excited about building an LLVM/GCC frontend, and adapting the Plan 9 toolchain is literally the only way those three could have Go gotten off the ground. As a member of the Go team, you'd certainly know better than I. But Go is long past a personal passion project. Go is over ten years old. Go likely has over a million developers [0]. Go 1.0 has been stable for about seven years, and the first meaningful changes to the language are just now being talked about. In my opinion, it is several years past due for Google to start investing seriously in a Go toolchain based on a mature compiler stack. I realize the audacity of this claim and I don't make it lightly. But if I had the money to spend on a team of developers, I would spend it making llvm-as and lld fast enough and stable enough to be Go's assembler and linker, and abandon the custom Plan 9 ones. > It never would have happened. How do you motivate people whose principal frustration is the state of C++ to work on a large C++ codebase? Well, for one, once the language gets off the ground, you can write the frontend in the new language. Rustc manages to be almost entirely Rust, for example. > Heterogeneity is a huge benefit to any ecosystem. Improving existing things is great, but building new things is also very important. I agree, and I think Go is an interesting contribution to the P/L landscape—essentially it proved that stripping away a good deal of complexity (generics, inheritance, etc.) results in a very useful, highly productive language. But I don't think Go's custom assembler and linker are meaningfully contributing to the ecosystem. They're useful presently in that they improve Go developers' productivity with ultra-fast builds, but they're not suitable for use by anything but Go. Improvements to Go's linker and assembler benefit only Go. Improvements to lld or gold can benefit practically everyone using a compiled language. [0]: https://research.swtch.com/gophercount https://research.swtch.com/gophercount