Michael Tiemann wrote this retrospective about working on GCC in 1987. It’s an interesting look back on some of the aspects of change that gcc wrought. I share some of his experience. In 1992 or so, I was working on a PostScript laser printer for Adobe that was based on the Motorola 68000. It was meant to be a low-cost printer, so it was using a near-obsolete CPU and as few components as possible and limited resources as possible. Laser printers work like CRT monitors – there is a beam that scans left to right and it gets turned on and off to set and clear pixels. When a pixel is set (beam on), a small static charge (IIRC) on the paper causes toner to adhere to it. When the paper continues on past a fuser, heat melts the toner to become permanent. The main difference between a laser printer and a CPU is that the paper moves top to bottom and the beam only goes left to right.
To offload some of the work, there is usually a hardware FIFO (first in, first out). When the paper starts feeding, the CPU fills the FIFO. The FIFO empties itself, turning the laser on and off. When the FIFO gets low, it sends an interrupt to the CPU which fills it back up.
The problem is that the CPU is not just doing this work (otherwise, we wouldn’t even need the FIFO!). This particular printer has serial, LocalTalk, and parallel interfaces, each of which could be active at any one time. It could buffer up jobs on all three communications ports at once. In addition, pages to be rendered were pipelined and queued up, all in parallel. We did what we could do to make this little CPU work. We found that with all communications ports active and an active job, the FIFO could get starved. This is bad, because unlike inkjet or film recorders, you can’t stop the paper once it starts moving. Instead, you get blank patches on the paper or if I adjusted the priority of the tasks, lost bytes in communication. Bad news either way.
There were several solutions available, each of which helped. The first was to apply Duff’s device to the FIFO filling code (as an aside, if Tom Duff ever reads this, I was that kid in the UNIX room at Murray Hill Bell Labs who kept coming in at night to read and try to write BLIT code – thanks for inadvertently teaching me so much). The second was pushing the customer to spend money on a deeper FIFO (which they didn’t agree to). The final task was to switch to GCC.
That was scary. We had a 68K compiler that we used, but PostScript is, shall we say, challenging for any C compiler. Portable as it was, we knew for a fact that we couldn’t ship any 68K device with the C compiler we were using set with optimizations on. The PostScript code base triggered bugs in the optimized that generated incorrect code. Yikes. The technical challenge of using GCC was that we couldn’t use any of GCC’s runtime code or risk being in violation of GPL. That meant that we couldn’t use GCC’s floating point library and floating point is necessary for PostScript. Our existing 68K library used register passing for arguments, so my job was to make it work with GCC. Choice 1 was to write wrapper routines that load the registers and call, but that’s would make performance even worse, so my task was to make GCC have register passing.
Echoing Tiemann’s sentiment, I discovered that register passing was available, but shut off because of a bug. I spent a week getting familiar with this section of the code, found the bug, fixed it and off we went. Performance and code size both improved substantially. Problem solved.
What started happening at this point, is that GCC nearly turned C compilers into a commodity. Whenever a new CPU became available, developers demanded a C compiler. Without the short turnaround created by GCC’s architecture, the CPU manufacturer usually held all the cards and could charge what they wanted for a C compiler, which also allowed them to dictate your development environment. Instead, GCC took the cards away from them and also created new businesses for people who specifically made new processor back ends for GCC.
Coincidentally enough, the first printer I worked with was one based on one of the National 32000 series, the National 32CG16, which was supposed to be a cheaper, faster alternative to the 68020. The problem we had with it was three-fold:
- The C compiler from National was ungainly and hard to get into our build system.
- Floating point was provided in an off-chip FPU, which when interfaced took half the registers away from the CPU. This in turn meant that we either had to demand that the customer had the FP unit (which we ended up doing) or write tricky wrapper code to use or emulate the FPU as needed and assume that half the registers were unusable except for FP. This hurt optimization badly.
- GCC generated better code.
At one point, I had the unpalatable task of arguing with compiler engineers from National about performance and demonstrated benchmarks showing what I had found.
It’s interesting to see how that has changed the expectation for development tools for new platforms, .NET, CPU or whatever. The platform providers have realized that if they want their platform to succeed, they can’t risk alienating the developers, so the development tools and test rigs need to be cheap. There is one arena where this hasn’t changed, though: game consoles/units. SDKs for these systems are hugely expensive because they specifically DON’T want developers other than elite ones. Sony and Nintendo are afraid of the problem that Atari had with the 2600: there were scores of games made that were pure crap and that killed the platform. The exception to that is XBox, which has been trying to make it easier for ordinary developers to get a hold of the SDK. I wonder if Sony and Nintendo will follow suit.
About the AuthorFollow on Twitter More Content by Steve Hawley