SDCC some times produce not-optimal code for single bit operations
Example
#include <stdint.h>
#define PORTB_ODR (*((uint8_t*) 0x5005))
// sdcc -mstm8 --std-c99 main.c
void main() {
// you should uncomment only ONE below
// line to produce correct optimal assembler output
// PORTB_ODR ^= 0x01; // -> bcpl
// PORTB_ODR &= ~0x01; // -> bres
// PORTB_ODR |= 0x01; // -> bset
}
but if several bit operations goes sequentially sdcc produce next
#include <stdint.h>
#define PORTB_ODR (*((uint8_t*) 0x5005))
// sdcc -mstm8 --std-c99 main.c
void main() {
PORTB_ODR |= 0x01;
PORTB_ODR &= ~0x01;
}
_main:
; main.c: 6: PORTB_ODR |= 0x01;
ld a, 0x5005
or a, #0x01
; main.c: 7: PORTB_ODR &= ~0x01;
ld 0x5005, a
and a, #0xfe
ld 0x5005, a
; main.c: 8: }
ret
and
#include <stdint.h>
#define PORTB_ODR (*((uint8_t*) 0x5005))
// sdcc -mstm8 --std-c99 main.c
void main() {
PORTB_ODR ^= 0x01;
PORTB_ODR |= 0x02;
}
_main:
; main.c: 6: PORTB_ODR ^= 0x01;
ld a, 0x5005
xor a, #0x01
; main.c: 7: PORTB_ODR |= 0x02;
ld 0x5005, a
or a, #0x02
ld 0x5005, a
; main.c: 8: }
ret
as you can see single-bit operations now is not atomiс and not optimal
Options --opt-code-size / --opt-code-speed have no any effects for current issue.
SDCC : mcs51/z80/z180/r2k/r2ka/r3ka/gbz80/tlcs90/ez80_z80/z80n/ds390/pic16/pic14/TININative/ds400/hc08/s08/stm8/pdk13/pdk14/pdk15 4.1.0 #12072 (Linux)
published under GNU General Public License (GPL)
This should fix your problem:
The Keyword volatile forces the compiler to read and write the same variable at each statement (Any mcu register or interrupt shared variable should be qualified as volatile).
Resulting in:
Later the optimizer converts it to:
Equivalent to:
thanks a lot !!!
I found case when volatile does not work
ODR register declared as volatile
Last edit: Oleksandr Dorogyh 2021-05-06
Without having compiled your code:
AFAIK the use of bit instructions is done by the peephole optimizer. The peephole optimizer will only do the optimization if a is not used subsequently. enableInterrupts() is implemented as a macro using inline asm. When the peephole optimizer sees inline asm it decides to err on the safe side and assume that no optimization is possible.
We can already see this in a minimal example:
As a workaround, you could use a critical section for disabling interrupts:
But I suspect that is SDCC-specific code that won't compile on Raisonance / IAR / Cosmic.
Last edit: Maarten Brock 2021-05-22
Well, the following code shows that the optimizer is somewhat "picky" about such optimizations:
Three equal statements. Yet the optimizer correctly optimized only the first two, but failed the third. Weird... :-(
Removing
__asm__makes all three be optimized fine, of course.Last edit: Arseny Vakhrushev 2021-05-24
Code generation generates something like
for each of them. Then the peephole optimizer sees that for the first two, the value in a is overwritten later, and optimizes it into bset. For the third, it sees that there is inline asm, and decides to not do anything. Without the inline asm, it arrives at ret, checks that the function returns void, so the value in a is not used, and also optimizes.
The peephole optimizer is an interesting beast. The workaround to the case above is this:
If
wfi()is inlined, no optimization for the third line. So it looks like the peephole optmizer sees the code after compiler optimizations (inlining, returns, etc.) and is akin of a "last wipe of dust". I guess I wish the compiler would work better at optimizing bit operations one day. :-) Anyways, thanks for the SDCC! It's a beautiful tool!Yes, the peephole optimizer is the last stage before asm output. To see what it does, options --no-peep and --fverbose-asm can be helpful.
The use of __sfr __at can be a workaround for the case discussed here, as then code generation might already generate the bit instructions.
But it is clearly less elegant and not portable.
by specification for STM8
sometime reading whole register leads to reset some internal state
and code doesnt work as expected at all.
Because of the C part does not generate predictive code for single-bit instruction I should write some parts on assembler and this yet more not elegant and not portable.
For example
I believe
__sfrand__atare not available for STM8.I'm observing a similar behaviour:
whereas:
Can you provide a minimal compileable example? Which compiler version do you use with which options?
Well... sure! Please take a look:
Phillip, please disregard my input! In my case, it's not a single bit. Sorry.
Arseny, you have not a single-bit operation, using OR in your case is correct
0x22 = 0b00100010 - two bits
Oh, right! My bad. Please disregard my five cents.