The first thing to consider is what needs optimising. Does the code need to take less program memory or should it run faster? Sometimes these things can both be achieved by reducing the number of instructions, however this depends on the underlying microcontroller and the number of cycles each instruction takes.
It is completely possible to generate smaller code that takes more cycles to run, especially if branches are involved.
To start experimenting it is important to isolate the smallest code portion possible. I created the simple test case below which includes the function from the question and which is portable between different microcontroller families:
#include <stdint.h>
uint32_t MyFunction(uint32_t crc, uint8_t *buffer, uint16_t length) {
uint16_t i;
uint16_t j;
for (i = 0; i < length; i++) {
crc = crc ^ *buffer++;
for (j = 0; j < 8; j++) {
if (crc & 1)
crc = (crc >> 1) ^ 0xEDB88320;
else
crc = crc >> 1;
}
}
return crc;
}
int main(int argc, char** argv) {
uint8_t data[] = "ABCDEF";
uint32_t ret = 0;
ret = MyFunction(ret, data, 6);
while(1);
}
As noted in the comments on the other question the value of the variable i
is never directly used, it is only ever compared to length
. Therefore we could rewrite it as follows:
uint32_t MyFunction(uint32_t crc, uint8_t *buffer, uint16_t length) {
uint16_t j;
while (length--) {
// .. do work ..
}
return crc;
}
For comparison purposes I used avr-gcc version 4.7.2 (targeting atmega8) and Microchip's XC8 1.21 (targeting PIC 18F). For XC8 I enabled PRO optimisations, for avr-gcc the arguments given were: avr-gcc -g -c -Os -Wall -mmcu=atmega8 test.c -o test-Os
.
Note it is important to check that ret
is not optimised away because the compiler thinks it is unused. Both variations on the C code generate the same assembly from avr-gcc. However XC8 does not notice the unused variable, therefore the code using a while(..)
loop compiles to 4 bytes smaller with 2 RAM bytes saved.
As noted in a comment on this question it would also be more efficient to make j
a uint8_t
, as the input will never be more than 8 bits wide. Testing on XC8 shows that making this change saves another 8 bytes of program space and 1 byte of RAM. It also reduces the output generated with avr-gcc by 4 bytes and one register byte.
In conclusion it is always worth giving the compiler the best chance of generating good code, in this case by not using extra unnecessary variables and by using the smallest possible storage class. Some optimising compilers will cope better than others but both perform well if the input C code has been well thought through.