The MSP430 has one of the simplest RISC ISAs out there, let alone CISC ISAs. However, after using assembly for some time I got tired of hand optimizing it over and over again. Here I compare some of the C compilers available for the MSP430. At the end we’ll see IAR does the best job.
Compiler comparison is usually done by benchmarking. I’d like to take a different approach by writing a simple routine in assembly and comparing it to the compiler’s output. By doing this we don’t get just bare numbers but can actually see how smart the compiler is.
Let’s assume we need to do division on some MSP430 which doesn’t have an MPY. To simplify the example we ignore division by zero and demand the numerator to be greater or equal than the denominator.
To do this we simply count how many times the denominator can be subtracted from the numerator.
; r12 numerator, must be greater or equal than the denominator
; r13 denominator, must be != 0
; r14 result
mov #0, r14 ; clear counter
loop:
add #1, r14
sub r13, r12
jge loop ; repeat until r12 < 0
sub #1, r14 ; loop goes 1 to far
mov r14, r12 ; return counter
ret
int16_t i = 0;
do {
i++;
a -= b;
} while (a >= 0);
i--;
return i;
This is the output using -Os:
mov r15, r13
mov #0, r15
inv r14
add #1, r14
jmp .L2
.L3:
mov r12, r15
.L2:
mov r15, r12
add #1, r12
add r14, r13
cmp #0, r13
jge .L3
ret
Again, this is the output using -Os:
MOV.W #0, R14
.L2:
MOV.W R14, R15
ADD.W #1, R15
SUB.W R13, R12
CMP.W #0, R12 { JL .L5
MOV.W R15, R14
BR #.L2
.L5:
MOV.W R14, R12
RET
This is the output using -Ohz, which stands for high optimizations, tuned for small code size:
MOV.W #0x0, R15
??div_0:
ADD.W #0x1, R15
SUB.W R13, R12
CMP.W #0x0, R12
JGE ??div_0
ADD.W #0xffff, R15
MOV.W R15, R12
RET
I didn’t find out how to generate assembly output with CrossWorks. Their support didn’t reply to my question.
| hand written | community gcc | Red Hat / Somnium | IAR | |
|---|---|---|---|---|
| total size | 14B | 24B | 20B | 16B |
| loop cycles | 4 | 7 | 9 | 5 |
cmp #0 which would not be necessary when counting down.add instead of just using sub.{ followed by an instruction in the same line which probably isn’t valid assembly.2018-01-12