avr-gcc-list
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: [avr-gcc-list] Optimisation mixes up registers in inline assembly


From: Michael Kwasnicki
Subject: Re: [avr-gcc-list] Optimisation mixes up registers in inline assembly
Date: Wed, 24 Jul 2019 23:53:27 +0200

Hello David.
Thanks for the explanation.
I intentionally reduced the code to not bother you with details that didn't 
help with pointing out my issue.
So as a conclusion it was my misconception of how inline assembly works.
In the full code I not only count 8 bits and count some bytes but also load 
each byte, shift each bit out and change the actual duty cycle according to the 
bit that lands in the carry bit.
I am new to inline assembly so the first steps are not always useful but 
playful and educational. So I learn more from the inner workings of AVR MCUs.

Cheers,

Michael K.




> Am 24.07.2019 um 23:00 schrieb David Brown <address@hidden>:
> 
> On 24/07/2019 21:41, Michael Kwasnicki wrote:
>> So the inputs to inline assembly are by value and not by reference, as I 
>> thought. Right?
> 
> Correct.  The inputs are used to initialise the registers.
> 
>> The correlation between my named registers and those C variables was pure 
>> coincidence.
> 
> No, it is pure optimisation, not coincidence.  And of course you don't 
> necessarily get registers for variables in C - certainly not for const values.
> 
>> And by making the named registers both - input and output - it creates a 
>> reference to the original C variable.
> 
> Yes, roughly.
> 
> The big question here is why you are using assembly at all.  Why not just 
> write in C?
> 
> void test2(void) {
>    uint8_t size = 42;
>    const uint8_t start = _BV(WGM02) |  _BV(CS00);
>    const uint8_t stop = 0x00;
>    TCCR0A = _BV(COM0B1) | _BV(WGM01) | _BV(WGM00);
>    OCR0A = 9;                              // TOP
>    const uint8_t zero = 1;                 // 0 < i <= TOP
>    const uint8_t one = 7;                        // 0 < i <= TOP
> 
>    OCR0B = one;
>    TCCR0B = start;
> 
>    while (size--) {
>        for (uint8_t bits = 0; bits < 8; bits++) {
>            OCR0B = one;
>        }
>        OCR0B = zero;
>    }
>    TCCR0B = stop;
> }
> 
> It is simpler, easier to understand, much easier to get right, and gives code 
> that is marginally smaller and faster than your hand-written assembly.  (It 
> is even better with -O2, which is the optimisation level I recommend as 
> usually giving smaller and faster code than -Os.)
> 
> mvh.,
> 
> David
> 
> 
> 
>> Regards,
>> Michael K.
>>> Am 24.07.2019 um 19:17 schrieb Joseph C. Sible <address@hidden 
>>> <mailto:address@hidden>>:
>>> 
>>> Since you intend to modify the inputs, you need to declare them as outputs 
>>> as well (with the + constraint). If you don't do this, GCC is allowed to 
>>> assume you don't write to them, and can share any that have the same values.
>>> 
>>> Joseph C. Sible
>>> 
>>> 
>>> On Wed, Jul 24, 2019, 13:04 Michael Kwasnicki <address@hidden 
>>> <mailto:address@hidden>> wrote:
>>> 
>>>    Hello dear list members,
>>> 
>>>    I am new to this list because I need someone to discuss a
>>>    potential compiler bug.
>>> 
>>> 
>>>    I try to mix inline assembly in C code. In the assembly I use
>>>    passed in variables which are named:
>>> 
>>>    _https://godbolt.org/z/w8wuJy_
>>>    _
>>>    _
>>>    The register mapping is:
>>>    [rZero] -> R20
>>>    [rOne] -> R21
>>>    [rStart] -> R18
>>>    [rStop] -> R19
>>>    [rSize] -> R22
>>>    [bits] -> R19
>>> 
>>>    If I look at the output assembly I can see the compiler did some
>>>    optimisation.
>>>    R19 is shared between [bits] and [rStop].
>>>    In this case this is okay as the bit count reaches zero at the end
>>>    and thus [bits] and [rStop] have the same value then.
>>> 
>>> 
>>>    But when I change the initial value of `bitcount` in C to 7 all
>>>    hell breaks loose.
>>> 
>>>    https://godbolt.org/z/F7rrB_
>>> 
>>>    The register mapping is:
>>>    [rZero] -> R20
>>>    [rOne] -> R18
>>>    [rStart] -> R19
>>>    [rStop] -> R21
>>>    [rSize] -> R22
>>>    [bits] -> R18
>>> 
>>>    This time the compiler optimisation corrupted the program.
>>>    R18 is shared between [rOne] and [bits]. [rOne] was supposed to be
>>>    a constant that is cached in a register. But [bits] gets decremented.
>>>    Thus the value passed to OCR0B varies and is not constant any more
>>>    changing the logic of the inline assembly.
>>> 
>>>    I am not experienced with inline assembly so I might have missed
>>>    something but my general expectation for assembly is that if I
>>>    name things differently, they are different things (registers in
>>>    this case).
>>> 
>>>    The issue does not show up with -O0 but anything above.
>>>    Locally I am running avr-gcc (GCC) 9.1.0. Not sure what the exact
>>>    version at godbolt is.
>>> 
>>>    Cheers,
>>> 
>>>    Michael
>>>    _______________________________________________
>>>    AVR-GCC-list mailing list
>>>    address@hidden <mailto:address@hidden>
>>>    https://lists.nongnu.org/mailman/listinfo/avr-gcc-list
>>> 
>> _______________________________________________
>> AVR-GCC-list mailing list
>> address@hidden
>> https://lists.nongnu.org/mailman/listinfo/avr-gcc-list




reply via email to

[Prev in Thread] Current Thread [Next in Thread]