by Richard Man
"Late to bed and early to rise, work like hell and advertise."
- Werner Von Braun
GOOD TECHNOLOGY IS NO SUBSTITUTE FOR GOOD SUPPORT; on the other hand, you can't make a good product based on bad technology.
Writing good compilers is in our blood, so to speak. My first task at my first job was to rewrite a byte code interpreter from C to 68K machine code for a proprietary test language. After that, I knew I want to work in the compiler fields. At Whitesmiths, I initiated an effort to produce a machine independent optimizer. Optimizers are usually written by a team of people, not by a single person, but I had to make do with the resources I had. After that, a couple of stints at DEC and HP, working on advanced optimizing compilers for DEC Alpha and the then-undisclosed HP PA-WW (which would eventually become the Intel EPIC), I did the obvious thing and co-founded ImageCraft (see "About Us" under the Company menu).
While compiler optimization and code generation are built on solid theories, in practice there are real world factors that make productizing compilers a non-trivial commercial endeavor. Some of the projects we have produced over the years include:
The ICC HC11 compiler
How about getting a compiler working with nothing but this:
This is a blazing 2MHz 8-bit HC11 with a primitive "monitor" called BUFFALO! Code is downloaded to the SRAM, and run. There is no trace, source level breakpoints, or source anything.
We have since ported our compilers to the CPU16, CPU12, Atmel AVR, Cypress PSoC1 M8c, TI MSP430, ARM ARM7, Parallax Propeller, and ARM Cortex-M. The 32-bit ARM Cortex-M chips are now the most attractive option for embedded work, as they are much more powerful than 8/16-bit chips, and they cost as little as $1 or below. The major issue is the difficulty of getting started using them, but we have addressed that by introducing the JumpStart API (below).
LCC ANSI C front end: the theories behind the language processing portion of a compiler (known as the front end) are well-known. However, writing a good and fast one suitable for production work is not trivial. Rather than starting with Small C (no support for full Standard C) or GCC (too big, too slow and too much baggage), we invested in licensing the LCC front end by Christopher Fraser and David Hanson. It's a high quality front end for which they even wrote a book. Besides efficiently process the C language, LCC includes a "bottom-up rewriting system" (BURS) for optimal instruction and addressing mode selection, performs expression level Common Subexpression Elimination (CSE), algebraic simplification, and multiple strategies for switch table code generation.
We have done much customization of course, mainly to make it work well for 8/16-bit microcontroller targets.
Linear Scan Register Allocation: a good register allocator is important in the quality of generated code for register-rich machines like the AVR and the ARM Cortex-M. A Linear Scan register allocator is much faster than and nearly as good as a "coloring" allocator. Using it and BURS (see above) contribute greatly to our speed advantage over GCC.
Whole Program Compression Optimizer: with the Atmel AVR, an effective code saving optimization is to "compress" common code fragments into subroutines. It can save as much as 25% of code space on the AVR.
Machine Independent Function Global Optimizer: not satisfied with the optimizations mentioned, we added a Machine Independent Optimizer (MIO) pass to our compiler. Notably it retains the LCC front end structure, and adds a state-of-art Static Single Assignment based optimizer that performs function-level CSE and constant propagation without affecting the rest of the compiler chain.
Optimal 8-Bit Code Generation: the C language has some surprising requirements that sometimes make 8-bit expression code generation suboptimal for 8-bit targets such as the Atmel AVR. A properly written attribute propagation pass solves the problem for any 8-bit target.
C99/C++ Features: the original LCC processes input conforming to the C90 language standard. While the embedded C user requirements are not necessarily better served by newer C01 or C11 standards, nevertheless there are new features that are quite useful, including anonymous structs and unions, interspersed declarations and statements, and C with Classes. Using these features can improve the maintainability of program code and make it possible to define a user friendly API (Application Programming Interface) such as the JumpStart API.
JumpStart API: We are so proud of our JumpStart API that we have devoted a separate page to describing it! For this and other descriptions of technologies used in our products, please click on items in the "Technologies" menu.