Question about generated asm

classic Classic list List threaded Threaded
3 messages Options
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Question about generated asm

Eric Tang
Hi avr-gcc mailing list,

I have a question about the asm generated for C code that sequentially checks the bits of an integer in a loop. From what I can gather, during each iteration of the loop, the integer is shifted right until the bit to be checked becomes the least significant bit of its least significant byte, at which point that bit is checked. This seems to be the case both when the loop index counts up and when it counts down. I am wondering why the shifting starts over every time, and if it would be better to retain the shifted result and shift it one bit more every iteration of the loop or to maintain a mask which is used in an AND operation with the integer and shifted one bit more during every iteration of the loop?

#include <stdint.h>
#include <avr/io.h>

int main(void)
{
    uint8_t temp;

    temp = 0xA5;
    DDRB |= 0xFF;
    for (uint8_t i = 0; i < 8; ++i)
        if (temp & 1 << i)
            PORTB ^= 0xFF;
    for (uint8_t i = 8; i--;)
        if (temp & 1 << i)
            PORTB ^= 0xFF;
    return 0;
}

.file "avr_asm_src.c"
__SP_H__ = 0x3e
__SP_L__ = 0x3d
__SREG__ = 0x3f
__tmp_reg__ = 0
__zero_reg__ = 1
.section .text.startup,"ax",@progbits
.global main
.type main, @function
main:
/* prologue: function */
/* frame size = 0 */
/* stack size = 0 */
.L__stack_usage = 0
in r24,0x4
ldi r24,lo8(-1)
out 0x4,r24
ldi r24,0
ldi r25,0
ldi r20,lo8(-91)
ldi r21,0
.L3:
movw r18,r20
mov r0,r24
rjmp 2f
1:
asr r19
ror r18
2:
dec r0
brpl 1b
sbrs r18,0
rjmp .L2
in r18,0x5
com r18
out 0x5,r18
.L2:
adiw r24,1
cpi r24,8
cpc r25,__zero_reg__
brne .L3
ldi r24,lo8(8)
ldi r18,lo8(-91)
ldi r19,0
.L4:
subi r24,1
brcs .L15
movw r20,r18
mov r0,r24
rjmp 2f
1:
asr r21
ror r20
2:
dec r0
brpl 1b
sbrs r20,0
rjmp .L4
in r25,0x5
com r25
out 0x5,r25
rjmp .L4
.L15:
ldi r24,0
ldi r25,0
ret
.size main, .-main
.ident "GCC: (GNU) 4.9.3"

Thanks,
Eric

_______________________________________________
AVR-GCC-list mailing list
[hidden email]
https://lists.nongnu.org/mailman/listinfo/avr-gcc-list
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Re: Question about generated asm

Russell Shaw
On 13/08/16 11:40, Eric Tang wrote:

> Hi avr-gcc mailing list,
>
> I have a question about the asm generated for C code that sequentially checks
> the bits of an integer in a loop. From what I can gather, during each iteration
> of the loop, the integer is shifted right until the bit to be checked becomes
> the least significant bit of its least significant byte, at which point that bit
> is checked. This seems to be the case both when the loop index counts up and
> when it counts down. I am wondering why the shifting starts over every time, and
> if it would be better to retain the shifted result and shift it one bit more
> every iteration of the loop or to maintain a mask which is used in an AND
> operation with the integer and shifted one bit more during every iteration of
> the loop?
>
> #include <stdint.h>
> #include <avr/io.h>
>
> int main(void)
> {
>      uint8_t temp;
>
>      temp = 0xA5;
>      DDRB |= 0xFF;
>      for (uint8_t i = 0; i < 8; ++i)
>          if (temp & 1 << i)
>              PORTB ^= 0xFF;
>      for (uint8_t i = 8; i--;)
>          if (temp & 1 << i)
>              PORTB ^= 0xFF;
>      return 0;
> }
>
> .file"avr_asm_src.c"
...

You could do something like:

int main(void)
{
     uint8_t temp = 0xA5;
     uint8_t temp_orig = temp;

     DDRB |= 0xFF;
     for (uint8_t i = 0; i < 8; ++i) {
         if (temp & 1)
             PORTB ^= 0xFF;
        temp >>= 1;
     }
     temp = temp_orig;
     for (uint8_t i = 8; i--;) {
         if (temp & 128)
             PORTB ^= 0xFF;
        temp <<= 1;
     }
     return 0;
}


_______________________________________________
AVR-GCC-list mailing list
[hidden email]
https://lists.nongnu.org/mailman/listinfo/avr-gcc-list
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Re: Question about generated asm

David Brown-40
In reply to this post by Eric Tang
On 13/08/16 03:40, Eric Tang wrote:

> Hi avr-gcc mailing list,
>
> I have a question about the asm generated for C code that sequentially
> checks the bits of an integer in a loop. From what I can gather, during
> each iteration of the loop, the integer is shifted right until the bit
> to be checked becomes the least significant bit of its least significant
> byte, at which point that bit is checked. This seems to be the case both
> when the loop index counts up and when it counts down. I am wondering
> why the shifting starts over every time, and if it would be better to
> retain the shifted result and shift it one bit more every iteration of
> the loop or to maintain a mask which is used in an AND operation with
> the integer and shifted one bit more during every iteration of the loop?
>

It looks like a missed optimisation opportunity here.  What version of
avr-gcc have you got, and what optimisation options are you using?
Unless you have the latest compiler version and are using either -O2 or
-Os, it s not worth complaining about something like this.  (I don't
have a recent version on hand to test it.)

In general, avr-gcc has cases with sub-optimal code, especially when C
integer promotion means that what looks like 8-bit arithmetic is
actually 16-bit.  In many situations, avr-gcc's optimisers can fix
improve things - but in other situations, it can't.  Newer versions of
the compiler are better then older ones, but these kinds of
optimisations are very specific to the avr, and thus only handled by the
over-worked avr port developers.  Cases like this, where you can easily
do the optimisation "manually" (as suggested by Russell), are lower
priority than ones that affect more common code.

But if your compiler is up to date, then you can file a "missed
optimisation" bug.  It might not get fixed in the near future, but it
won't be forgotten.


(Try compiling with -O3 - it gives an interesting alternative solution!)



_______________________________________________
AVR-GCC-list mailing list
[hidden email]
https://lists.nongnu.org/mailman/listinfo/avr-gcc-list
Loading...