It’s no secret that compilers fulfil a critical role in application development – compiling efficient source code to efficient machine code. And with that role comes huge responsibility. Our experience is that widely used C and C++ compilers for mainstream processor architectures, such as x86 and ARM, are typically reliable (though never perfect…). But what about compilers for application-oriented processors such as DSPs and application-specific 8-bit microcontrollers?
Application oriented processors make a lot of sense: they can be much more cost effective than their big brother counterparts and often come conveniently packaged with appropriate on-chip I/O functions. Application developers rely on compilers for these devices to be as dependable as their mainstream brethren. Unfortunately, at Solid Sands we have found that this is not always the case.
We were recently asked to qualify such a compiler. Despite being a commercial-grade compiler from a well-known vendor, this must have been the first time it had been confronted by a comprehensive test suite such as SuperTest. We quickly found two major run-time errors: one in value propagation and another in register allocation in combination with the calling conventions. These two errors alone affected dozens of tests, all leading to run-time failures. It’s worth noting that value propagation is normally considered an optimization that needs to be explicitly turned on, but this compiler applied it by default!
Not only were the potential consequences of such errors for the application significant (this compiler qualification was part of our customer’s functional safety process), they also threatened the customer’s entire project schedule. Halfway through compiler qualification, we had to report errors to the compiler vendor, wait for fixes or workarounds, and discuss appropriate changes to the compiler settings with our customer – potentially disrupting their application development process.
This is not the first time it’s happened. Last year we evaluated a compiler that incorrectly re-ordered aliased load and store instructions in the instruction scheduling for a target processor with an exposed pipeline. The scheduler plays a crucial role for every single program that is compiled and therefore has to work well every time.
Test all compilers, especially the ‘little’ ones
So what can you do to avoid the pitfalls? At the very least, ask your compiler vendor about their test procedures. Have they passed their compiler through a reputable test-suite such as SuperTest? If you’re operating in a mission-critical or safety-critical market, then you want to – have to – know the weak points of the compiler you are using. Even if errors can’t be fixed, knowing the weak spots allows you to take preventive measures or implement work-arounds, or ‘mitigations’ as they are called in the world of functional safety. Of course, you can always ask us to qualify your chosen compiler, but it may be better to have the qualification capability and acquired knowledge in-house by obtaining a license to use SuperTest directly. You can then use it for as many compilers as you like!