sdcc -mstm8 test.cThe compiler incorrectly inserts a clr a followed by a div x,a instruction at the beginning of interrupt service routines when accessing array elements using bit-shift operations.
unsigned short my_uint16;
unsigned char my_uint8;
unsigned char my_array[256];
void my_isr1(void) __interrupt(13) {
/* Causes a "clr a; div x,a" to be inserted at the beginning of the ISR: */
my_uint8 = my_array[my_uint16 >> 8];
}
void my_isr2(void) __interrupt(14) {
/* No bug when using an intermediate variable: */
unsigned char shifted = my_uint16 >> 8;
my_uint8 = my_array[shifted];
}
_my_isr1:
clr a ; Sets a to 0
div x, a ; Divides by 0!
; test.c: 7: my_uint8 = my_array[my_uint16 >> 8];
ld a, _my_uint16+0
clrw x
ld xl, a
addw x, #(_my_array+0)
ld a, (x)
ld _my_uint8+0, a
; test.c: 8: }
iret
Note: When invoking the compiler with option --opt-code-size, the clr a disappears, but the div x, a still remains.
Ticket moved from /p/sdcc/bugs/3840/
Can't be converted:
Moved to feature requests, since the generated code is correct (just less efficient than it could be).
The
clr adisappearing for--opt-code-sizeis working as intended: it saves one byte of code, but (depending on the unknown value of a), thedivthen might take substantially more cycles to execute.In my_isr2, due to the result being assigned to an 8-bit type, the right shift is optimized into a GETBYTE iCode. This does not happen for my_isr1; in my_isr1, we have a RIGHT_OP (i.e. right shift) iCode. At the time the isr prologue is generated, code generation has incomplete information on how the right shift will be implemented later. For some (depending on the operands) right shifts by literals,
divordivwis used, and when generating the function prologue we err on the safe side, assuming that for any right shift by a more than 1 adivordivwmight be generated.