Compiler Quality and C's volatile Keyword
At at a meeting with a client yesterday, I was reminded of a conversation we'd had about eighteen months ago at an Embedded Systems Conference. At that time the client, I'll call him John, was having a problem with C's volatile keyword on a PIC microcontroller.
John had written a few lines of C code to swap the contents of two peripheral registers, perhaps something along these lines:
where pRegisterA and pRegisterB were pointers to memory-mapped I/O locations.
Since the data pointed to by pRegisterA and pRegisterB wasn't being used anywhere else in the code, the compiler's optimizer was completely ignoring the above code; outputting zero opcodes of machine code for that sequence.
As John and I discussed then, redeclaring the pointers as pointer to volatile integers (e.g., uint8_t volatile * pRegisterA = /* address */;), should have instructed the compiler to treat those lines of code as sacred and output corresponding machine instructions. Having tried this already, though, his compiler continued to output nothing.
Wow! John didn't realize it at the time but he had just found a bug in his compiler.
I advised John to try another compiler, rather than the free compiler he was using. You generally do get what you pay for with C cross compilers. And, indeed, his problem went away with the new compiler.
Although it is common for embedded programmers to believe their compiler's optimizer is broken when the flaw is really their failure to declare certain variables volatile, this was a genuine case of an internal compiler bug.
John had written a few lines of C code to swap the contents of two peripheral registers, perhaps something along these lines:
uint8_t temp;
temp = *pRegisterA;
*pRegisterA = *pRegisterB;
*pRegisterB = temp;
where pRegisterA and pRegisterB were pointers to memory-mapped I/O locations.
Since the data pointed to by pRegisterA and pRegisterB wasn't being used anywhere else in the code, the compiler's optimizer was completely ignoring the above code; outputting zero opcodes of machine code for that sequence.
As John and I discussed then, redeclaring the pointers as pointer to volatile integers (e.g., uint8_t volatile * pRegisterA = /* address */;), should have instructed the compiler to treat those lines of code as sacred and output corresponding machine instructions. Having tried this already, though, his compiler continued to output nothing.
Wow! John didn't realize it at the time but he had just found a bug in his compiler.
I advised John to try another compiler, rather than the free compiler he was using. You generally do get what you pay for with C cross compilers. And, indeed, his problem went away with the new compiler.
Although it is common for embedded programmers to believe their compiler's optimizer is broken when the flaw is really their failure to declare certain variables volatile, this was a genuine case of an internal compiler bug.
Labels: embedded, programming
1 Comments:
Michael-
The situation regarding compilation of volatile accesses is worse than you indicate here, and paying money for a compiler is no guarantee. If you get a minute check out some work that we recently wrote up on this subject.
John Regehr
By
Anonymous, at 4/18/2008 12:34 PM
Post a Comment
Links to this post:
Create a Link
<< Home