hidden gem

Go To Last Post
57 posts / 0 new
Author
Message
#1
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Guys, I found this wee gem on the internet.  Instead of say using a for loop to go from 10 to 0 ect you can use the -->

 

for example.

 

int x = 10;

 

while( x --> 0 ) // x goes to 0

{

printf("%d ", x);

}

 

Slán

 

Does anyone have there own little gems?  Like the ternary operator?

Last Edited: Wed. Oct 9, 2019 - 02:11 AM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 1

That example is fairly obvious for most of us. There's plenty that will have you scratching your head. Best to avoid those methinks. Simple code = simple defects. If you have to stop and think too much about precedence and operation order, then you might want to rewrite the code.

 

As to whether your example generates more/less or the same code as the equivalent for loop - that's something for investigation. 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

This is a good thread for joeymorin.

 

JIm

I would rather attempt something great and fail, than attempt nothing and succeed - Fortune Cookie

 

"The critical shortage here is not stuff, but time." - Johan Ekdahl

 

"Step N is required before you can do step N+1!" - ka7ehk

 

"If you want a career with a known path - become an undertaker. Dead people don't sue!" - Kartman

"Why is there a "Highway to Hell" and only a "Stairway to Heaven"? A prediction of the expected traffic load?"  - Lee "theusch"

 

Speak sweetly. It makes your words easier to digest when at a later date you have to eat them ;-)  - Source Unknown

Please Read: Code-of-Conduct

Atmel Studio6.2/AS7, DipTrace, Quartus, MPLAB, RSLogix user

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Best to avoid those methinks. Simple code = simple defects.

Amen.  Remember that someday, someone who doesn't know, or doesn't remember, these sorts of cute tricks (perhaps they're barely competent in C, since Javascript and Visual Basic are their main thing) will need to read/modify/fix that code.   It might be you.

 

Quick: is the first number printer 10, or 9?  Is the last number 0, or 1?  (not that it's so much worse than the standardish C "for" loop...)

 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

ok, other question then.......

if you create this, or a for loop, will the assembly output be the same or is there a code difference?

most important, the use of RAM space and the number of instruction cycles needed to do either one of them.

 

and what will happen if you at one point decide to make things more readable and do while( (x --) > 0 ) // x goes to 0

 

 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

meslomp wrote:
will the assembly output be the same or is there a code difference?
If I build this in AS7/avr-gcc:

#include <avr/io.h>

int main(void)
{	
	int x = 10;
#if 1		
	while(x --> 0) {
		PORTB = x;
	}
#else		
	for (x = 10; x; x--) {
		PORTB = x;
	}
#endif
	while(1);
}

then built with #if 1 it yields:

00000080 <main>:
#include <avr/io.h>

int main(void)
{	
  80:	89 e0       	ldi	r24, 0x09	; 9
	int x = 10;
#if 1		
	while(x --> 0) {
		PORTB = x;
  82:	85 b9       	out	0x05, r24	; 5
  84:	81 50       	subi	r24, 0x01	; 1
  86:	e8 f7       	brcc	.-6      	; 0x82 <main+0x2>
  88:	ff cf       	rjmp	.-2      	; 0x88 <main+0x8>

and built with #if 0 it is:

00000080 <main>:
#include <avr/io.h>

int main(void)
{	
  80:	8a e0       	ldi	r24, 0x0A	; 10
	while(x --> 0) {
		PORTB = x;
	}
#else		
	for (x = 10; x; x--) {
		PORTB = x;
  82:	85 b9       	out	0x05, r24	; 5
  84:	81 50       	subi	r24, 0x01	; 1
#if 0
	while(x --> 0) {
		PORTB = x;
	}
#else		
	for (x = 10; x; x--) {
  86:	e9 f7       	brne	.-6      	; 0x82 <main+0x2>
  88:	ff cf       	rjmp	.-2      	; 0x88 <main+0x8>

So, no, it doesn't seem to make a lot of difference to the generated code.

 

But to be honest I would always write C with a space on either side or an operator apart from per/post increment. So if you write the code as:

	while(x-- > 0) {

There's little mystery to it. Using --> in this is a bit like those folks who rearrange the spacing of the letters in their car's number plate to spell out some name or phrase! Like "SEX80MB" simply split as "SEX 80MB" or whatever ;-)

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Fianawarrior wrote:
you can use the -->

Eh?

 

That's just two perfectly standard, everyday 'C' operators:

  1.  -- is the decrement operator;
  2. > is the "is greater than" operator.

 

The code is just

int x = 10;

while( x-- > 0 ) // check x > 0 with post-decrement
{
    printf("%d ", x);
}

 

Any for loop can always be implemented as an equivalent while loop - and vice versa:

 

 

 

https://www.coursera.org/lecture/programming-fundamentals/equivalent-for-and-while-loops-8LVp2

Top Tips:

  1. How to properly post source code - see: https://www.avrfreaks.net/comment... - also how to properly include images/pictures
  2. "Garbage" characters on a serial terminal are (almost?) invariably due to wrong baud rate - see: https://learn.sparkfun.com/tutorials/serial-communication
  3. Wrong baud rate is usually due to not running at the speed you thought; check by blinking a LED to see if you get the speed you expected
  4. Difference between a crystal, and a crystal oscillatorhttps://www.avrfreaks.net/comment...
  5. When your question is resolved, mark the solution: https://www.avrfreaks.net/comment...
  6. Beginner's "Getting Started" tips: https://www.avrfreaks.net/comment...
Last Edited: Wed. Oct 9, 2019 - 08:50 AM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 1

Fianawarrior wrote:

while( x --> 0 ) // x goes to 0

{

printf("%d ", x);

}

I wouldn't call this a hidden gem, I would call it a hidden piece of nonsense.

You could at least write it as

while (x-- > 0)

 

The idiom

while (x--) {}

is quite common for situations where you can loop 0 or more times (ie x can be 0).

 

For situations where the num of loops are known at compile time, personally I always prefer for loop, and let the compiler optimise it.

(For example, if the compiler knows you are looping 10 times it might implement the for loop in the form of do {} while(); since it knows that 10 times is definitely 1 or more times).

 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

and if it's terse code you like, why not just have

    int x = 10;

    while( x-- ) 
    {
        printf("%d ", x);
    }

which could equally be written as

    for( int x = 10; x--; )
    {
        printf("%d ", x);
    }

which saves you a source line!

Top Tips:

  1. How to properly post source code - see: https://www.avrfreaks.net/comment... - also how to properly include images/pictures
  2. "Garbage" characters on a serial terminal are (almost?) invariably due to wrong baud rate - see: https://learn.sparkfun.com/tutorials/serial-communication
  3. Wrong baud rate is usually due to not running at the speed you thought; check by blinking a LED to see if you get the speed you expected
  4. Difference between a crystal, and a crystal oscillatorhttps://www.avrfreaks.net/comment...
  5. When your question is resolved, mark the solution: https://www.avrfreaks.net/comment...
  6. Beginner's "Getting Started" tips: https://www.avrfreaks.net/comment...
Last Edited: Wed. Oct 9, 2019 - 08:59 AM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

MrKendo wrote:
I wouldn't call this a hidden gem, I would call it a hidden piece of nonsense.

Indeed!

 

 

Top Tips:

  1. How to properly post source code - see: https://www.avrfreaks.net/comment... - also how to properly include images/pictures
  2. "Garbage" characters on a serial terminal are (almost?) invariably due to wrong baud rate - see: https://learn.sparkfun.com/tutorials/serial-communication
  3. Wrong baud rate is usually due to not running at the speed you thought; check by blinking a LED to see if you get the speed you expected
  4. Difference between a crystal, and a crystal oscillatorhttps://www.avrfreaks.net/comment...
  5. When your question is resolved, mark the solution: https://www.avrfreaks.net/comment...
  6. Beginner's "Getting Started" tips: https://www.avrfreaks.net/comment...
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

westfw wrote:
cute tricks

It's not even a "cute trick" - it's just perfectly standard code.

 

The worst thing about it is probably the "x goes to 0" comment - suggesting that it is something special ... ?

Top Tips:

  1. How to properly post source code - see: https://www.avrfreaks.net/comment... - also how to properly include images/pictures
  2. "Garbage" characters on a serial terminal are (almost?) invariably due to wrong baud rate - see: https://learn.sparkfun.com/tutorials/serial-communication
  3. Wrong baud rate is usually due to not running at the speed you thought; check by blinking a LED to see if you get the speed you expected
  4. Difference between a crystal, and a crystal oscillatorhttps://www.avrfreaks.net/comment...
  5. When your question is resolved, mark the solution: https://www.avrfreaks.net/comment...
  6. Beginner's "Getting Started" tips: https://www.avrfreaks.net/comment...
Last Edited: Wed. Oct 9, 2019 - 09:06 AM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 1

Fianawarrior wrote:
I found this wee gem on the internet

 

Go on - where, exactly, did you find it?

 

EDIT

 

Too much Stack Overflow, perhaps?

 

https://stackoverflow.com/questions/1642028/what-is-the-operator-in-c

 

EDIT 2

 

Did you also see the "slides to 0" operator?

while (x --\
            \
             \
              \
               > 0)
     printf("%d ", x);

laugh laugh laugh laugh 

Top Tips:

  1. How to properly post source code - see: https://www.avrfreaks.net/comment... - also how to properly include images/pictures
  2. "Garbage" characters on a serial terminal are (almost?) invariably due to wrong baud rate - see: https://learn.sparkfun.com/tutorials/serial-communication
  3. Wrong baud rate is usually due to not running at the speed you thought; check by blinking a LED to see if you get the speed you expected
  4. Difference between a crystal, and a crystal oscillatorhttps://www.avrfreaks.net/comment...
  5. When your question is resolved, mark the solution: https://www.avrfreaks.net/comment...
  6. Beginner's "Getting Started" tips: https://www.avrfreaks.net/comment...
Last Edited: Wed. Oct 9, 2019 - 09:15 AM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0


awneil wrote:
It's not even a "cute trick"
Well it is in the same way that a "SEX 80MB" number plate is ;-)

 

(and yes, folks, I know that is not a valid UK registration - I'm just trying to illustrate a point!)

 

PS my own registration - I know, I know...

 

Last Edited: Wed. Oct 9, 2019 - 09:13 AM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

So now we can check that your tax & MoT are up-to-date ...

 

https://www.gov.uk/check-vehicle-tax

Top Tips:

  1. How to properly post source code - see: https://www.avrfreaks.net/comment... - also how to properly include images/pictures
  2. "Garbage" characters on a serial terminal are (almost?) invariably due to wrong baud rate - see: https://learn.sparkfun.com/tutorials/serial-communication
  3. Wrong baud rate is usually due to not running at the speed you thought; check by blinking a LED to see if you get the speed you expected
  4. Difference between a crystal, and a crystal oscillatorhttps://www.avrfreaks.net/comment...
  5. When your question is resolved, mark the solution: https://www.avrfreaks.net/comment...
  6. Beginner's "Getting Started" tips: https://www.avrfreaks.net/comment...
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0


Completely legal ...

 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

You think the OP's trick was bad? Try the latest from Microsoft... https://devblogs.microsoft.com/c...

 

Ligatures in monospaced fonts, yet, in source code. Sometimes I despair.

 

Neil

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

MrKendo wrote:
I would call it a hidden piece of nonsense.

It probably started as a joke/prank (April fool?) - but someone missed the smiley ... ?

 

frown

Top Tips:

  1. How to properly post source code - see: https://www.avrfreaks.net/comment... - also how to properly include images/pictures
  2. "Garbage" characters on a serial terminal are (almost?) invariably due to wrong baud rate - see: https://learn.sparkfun.com/tutorials/serial-communication
  3. Wrong baud rate is usually due to not running at the speed you thought; check by blinking a LED to see if you get the speed you expected
  4. Difference between a crystal, and a crystal oscillatorhttps://www.avrfreaks.net/comment...
  5. When your question is resolved, mark the solution: https://www.avrfreaks.net/comment...
  6. Beginner's "Getting Started" tips: https://www.avrfreaks.net/comment...
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Isn't there some thing in C where something like a++++++a is valid or something? (and no I didn't count the '+' but I know it involves quite a few)

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

MrKendo wrote:

The idiom

while (x--) {}

is quite common for situations where you can loop 0 or more times (ie x can be 0).

awneil wrote:

and if it's terse code you like, why not just have

    int x = 10;

    while( x-- )
    {
        printf("%d ", x);
    }

 

my favorite loop for simple countdowns. +1

 

 

Majid

Last Edited: Wed. Oct 9, 2019 - 02:03 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Any for loop can always be implemented as an equivalent while loop - and vice versa:

Any for loop can be generated using a while loop, but not the reverse 

 

When in the dark remember-the future looks brighter than ever.   I look forward to being able to predict the future!

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

clawson wrote:
a++++++a

 

Take a couple of + out and it's fine:

a++ + ++a

Not sure what happens if you try and increment an incremented(ing) value, mind.

 

Neil

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 1

barnacle wrote:

Take a couple of + out and it's fine:

a++ + ++a

Thta's still undefined behaviour (modifying a twice without a sequence point in between)

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 1

The obvious code produces the same code as the non-obvious-

https://godbolt.org/z/GnIWgw

so may as well make it obvious

 

Compilers are not impressed by anything clever. They may have been in the past, but not anymore. It becomes a hard habit to break if in the past you had to be 'clever' to get a compiler to do things in a certain way. Now, you just feed it straight-forward code and its already optimized to a degree more than you expected in many cases. I'm sure I still code in 'clever' mode at times mostly out of habit, but it is rarely a good thing.

 

 

 

 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Compilers are not impressed by anything clever.

I'd like one that could at least understand my programming jokes.  Even synthesized laughter would be appreciated. 

When in the dark remember-the future looks brighter than ever.   I look forward to being able to predict the future!

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

't is cute, but unless it compiles to something faster, it's not real helpful.  Of course, you could do like me, and write assembler to start with - Then there's no issues about how fast it compiles to, you already know...  ;-)   S.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

awneil wrote:

So now we can check that your tax & MoT are up-to-date ...

 

https://www.gov.uk/check-vehicle-tax

We could do that a long time already as Cliff posted about his custom plate when he got it, and to me that already seems a long time ago.

 

thanks for the test Cliff, indeed does not seem to reduce instruction cycles nor time so it is up to the person who wrote the code as to what he found better looking.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Scroungre wrote:
Then there's no issues about how fast it compiles to, you already know...
Ah yes, assembler. Always bound to be quicker! Take a look at the code generated in #6 - can you shave a byte or a cycle from that using your mythical assembler? ;-)

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

My last boss used to insist on assembler being used 'because it's harder to make mistakes in assembler...'

 

Neil

 

p.s. PIC14 assembler at that :( mostly, though the high precision floating point for z80 was fun.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Given trivia, no.  But I was curious how a C compiler would have handled something else I just wrote in assembler - It's a three-way switch statement that really only does one of three memory moves - but the source for the three memory moves is always the same, so I moved the 'source' pointer out of the switch statement results.  Saved myself several cycles and bytes there.

 

Pseudo-code:

If X == 1 Then copy SRAM A to SRAM P

If X == 2 Then copy SRAM A to SRAM Q

If X == 3 Then copy SRAM A to SRAM R

 

I would also like to see a C compiler pull off my zero-cycle divide by 256.  ;-P

 

S.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

(As another aside, and this is really something I hope is in Xilinx's new 'C for FPGAs' kit, C can't do arbitrary bit-size integers.  Just accumulating 256x of 16-bit values only needs 24 bits, but is there a 24-bit integer type?  I don't think so, so using 32 bits for a 24-bit number is inherently wasteful!  Tell that to your C compilers.  Plbbht.)  S.

 

Edited to add: Not that you care, but I've done work in 12 bits, 18 bits, 24 bits, 40 bits (that one was in an AVR, too)...  Yeah, given an AVR using 8-bit multiples is easier, but with arbitrary programmable logic, you can have just as many bits as you need... no more, no fewer.  That 40-bit processor would not have fit in a tiny2313 if someone insisted on using 64-bit values!

Last Edited: Thu. Oct 10, 2019 - 05:33 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Scroungre wrote:
Just accumulating 256x of 16-bit values only needs 24 bits, but is there a 24-bit integer type?
an exception due to XMEGA

http://gcc.gnu.org/wiki/avr-gcc#Types

Microchip AVR GCC is dependent on GMP.

The GNU MP Bignum Library

The GNU Multiple Precision Arithmetic Library

 


AVR and SAM Downloads Archive | Microchip Technology

[3/4 page]

 

AVR GCC

...

AVR GCC 3.6.2

 

Attachment(s): 

"Dare to be naïve." - Buckminster Fuller

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Excellent!  Now, is there a type for 22 bits or 26 bits, as implemented in a 'soft processor core' in an FPGA?  wink

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Scroungre wrote:
I would also like to see a C compiler pull off my zero-cycle divide by 256.  ;-P

P indeed.  The same way you'd just "tell" your assembler code to use the most-significant-byte of a two-byte value, you'd do the same in C.  (I'll bet on your AVR8 it is in the low address as well...)

You can put lipstick on a pig, but it is still a pig.

I've never met a pig I didn't like, as long as you have some salt and pepper.

Last Edited: Thu. Oct 10, 2019 - 09:41 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I would also like to see a C compiler pull off my zero-cycle divide by 256.  ;-P

Here you go.   It's a shame that the compiler didn't do a better job constructing the 16bit number in the first place...

 

void main() {
    uint16_t x;
    x = (PORTC << 8) | PORTD;
  74:    28 b1           in    r18, 0x08    ; 8
  76:    8b b1           in    r24, 0x0b    ; 11
  78:    90 e0           ldi    r25, 0x00    ; 0
  7a:    92 2b           or    r25, r18
    PORTB = x/256;
  7c:    95 b9           out    0x05, r25    ; 5
    while (1);
  7e:    ff cf           rjmp    .-2          ; 0x7e <main+0xa>

 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

With gcc 8.3 the construction of the 16-bit number is optimized.

 

Source:

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

int main()
{
    uint16_t x = ( PORTC << 8 ) | PORTD;

    PORTB = x / 256;

    for ( ;; ) {}
}

Compiled with the following flags:

-std=c++17 -Werror -Wall -Wextra -Wpointer-arith -Wold-style-cast -mmcu=atmega328p -Os -g

Disassembly (main only):

int main()
{
    uint16_t x = ( PORTC << 8 ) | PORTD;
  80:	98 b1       	in	r25, 0x08	; 8
  82:	8b b1       	in	r24, 0x0b	; 11

    PORTB = x / 256;
  84:	95 b9       	out	0x05, r25	; 5

    for ( ;; ) {}
  86:	ff cf       	rjmp	.-2      	; 0x86 <main+0x6>

 

github.com/apcountryman/build-avr-gcc: a script for building avr-gcc

github.com/apcountryman/toolchain-avr-gcc: a CMake toolchain for cross compiling for the Atmel AVR family of microcontrollers

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

All of which are lovely for dividing a 16-bit number by 256, but not a 24-bit number.  S.

 

Edited to add, once more, that the point is not necessarily sheer speed.  The point is knowing EXACTLY how many cycles you are going to get, every time.  Since I work with time-sensitive external hardware, I often throw in piles of NOP instructions to keep the speed to EXACTLY what I want it to be.  Is your compiler going to optimize out my NOPs?  If so, then I don't want it! 

Last Edited: Fri. Oct 11, 2019 - 05:58 AM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

but not a 24-bit number. 

 

Hmm?   It still works...

 

void main() {
    __uint24 x;
    x = (PORTC << 8) | PORTD;
  38:    25 b3           in    r18, 0x15    ; 21
  3a:    82 b3           in    r24, 0x12    ; 18
  3c:    90 e0           ldi    r25, 0x00    ; 0
  3e:    92 2b           or    r25, r18
  40:    09 2e           mov    r0, r25
  42:    00 0c           add    r0, r0
  44:    aa 0b           sbc    r26, r26
  46:    89 2f           mov    r24, r25
  48:    9a 2f           mov    r25, r26
  4a:    aa 27           eor    r26, r26
    PORTB = x/256;
  4c:    88 bb           out    0x18, r24    ; 24
  4e:    ff cf           rjmp    .-2          ; 0x4e

 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

westfw wrote:

but not a 24-bit number. 

 

Hmm?   It still works...

 

void main() {
    __uint24 x;
    x = (PORTC << 8) | PORTD;
  38:    25 b3           in    r18, 0x15    ; 21
  3a:    82 b3           in    r24, 0x12    ; 18
  3c:    90 e0           ldi    r25, 0x00    ; 0
  3e:    92 2b           or    r25, r18
  40:    09 2e           mov    r0, r25
  42:    00 0c           add    r0, r0
  44:    aa 0b           sbc    r26, r26
  46:    89 2f           mov    r24, r25
  48:    9a 2f           mov    r25, r26
  4a:    aa 27           eor    r26, r26
    PORTB = x/256;
  4c:    88 bb           out    0x18, r24    ; 24
  4e:    ff cf           rjmp    .-2          ; 0x4e

 

 

I lurv "ldi r25, 0x00".  And then OR with r18?  What?  Can't 'mov' do it all?  And 'add r0, r0'?  What's r0 got to do with this?  I know the AVR has lots of registers, but this is getting silly!  Finally, a 24-bit number only needs three registers, not four.  How many registers did you use in that?  Lemme count...  r0, r18, r24, r25, r26... five?  And what's with the mov instructions?  In assembler, you don't have to move them around, because they're already where you can use them!  crying

 

And now, in pseudo-code, the same thing in assembler:

 

in r16, PINA

in r17, PINB

in r18, PINC

out PORTD, r17

out PORTE, r18

 

Any further questions?

Last Edited: Fri. Oct 11, 2019 - 07:17 AM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I don't know if it is still the case, but a few years ago, the PIC C compiler, free version, was carefully optimised to ensure maximum time was taken for shifts. Shifting a 24-bit value by eight required that all three bytes were shifted one bit at a time, eight times...

 

Neil

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

In the very early days, the Imagecraft compiler for AVR did the same. I pointed this out to Richard and he quickly added the optimisation by byte shuffling.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I lurv "ldi r25, 0x00".  And then OR with r18?  What?  Can't 'mov' do it all?

Yeah.  Some of that is that I didn't cast the RHS math to __UINT24, so it's probably doing 16bit math and then carefully converting to 24bits.   It looks  slightly better fixed, but not a lot (even with avr-gcc9.2, which does well on the 16bit case (and only so-so on 32bits.)

 

But you asked about the /256, which it seems to be doing fine in all cases.

 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Indeed it does.  As well it should.  Congrats to the compiler writers.  Of course, nobody took me up on the 'moving the loading of the source pointer out of the switch statement' remark.  You busy?  (I'm getting wildfires around and should be 350 miles away, so I'll get back to you later on that one...)  S.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Well, you want to see gcc screw-up because it thinks it's smart? Easy devil

 

#include <avr/io.h>

int main() {
	DDRB = 0x01;
	uint8_t parallel_data = PIND, mask = 0x01;
	while (mask) {
		parallel_data & mask ? PORTB |= 0x01 : PORTB &= ~0x01;
		mask <<= 1;
	}
	while (1);
}

 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

El Tangas wrote:
Well, you want to see gcc screw-up because it thinks it's smart? Easy devil

If compiled as C code, it  won't compile, syntax error due to operator precedence.

Seems smart enough to me :)

Needs extra brackets, or be normal and just use if/else.

Maybe it is different if compiled as C++ (I haven't tried).

 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

MrKendo wrote:
Maybe it is different if compiled as C++ (I haven't tried).

Yeah I did write it in C++, my bad. Like this, then:

 

#include <avr/io.h>

int main() {
	DDRB = 0x01;
	uint8_t parallel_data = PIND, mask = 0x01;
	while (mask) {
		(parallel_data & mask) ? (PORTB |= 0x01) : (PORTB &= ~0x01);
		mask <<= 1;
	}
	while (1);
}

 

MrKendo wrote:
Needs extra brackets, or be normal and just use if/else.

I though ternary operator was normal... But ok, for those who have issues:

 

#include <avr/io.h>

int main() {
	DDRB = 0x01;
	uint8_t parallel_data = PIND, mask = 0x01;
	while (mask) {
		if (parallel_data & mask) {
			PORTB |= 0x01;
		}
		else {
			PORTB &= ~0x01;
		}
		mask <<= 1;
	}
	while (1);
}

 

Last Edited: Sat. Oct 12, 2019 - 01:19 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

El Tangas wrote:

I though ternary operator was normal... But ok, for those who have issues:

Just one of my pet hates :)

Not the ternary operator itself, I'm quite happy when you're making use of value returned eg.

x = condn ? this_value : that_value;

just never liked it for

condn ? do_this : do_that

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

MrKendo wrote:

Not the ternary operator itself, I'm quite happy when you're making use of value returned

 

Yeah I understand that. I have this tendency to maybe overuse it because I once saw an old version of gcc generating better code for the ternary operator than for if;else.

Modern versions usually generate the exact same code.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0
	uint8_t parallel_data = PIND, mask = 0x01;
	while (mask) {
		(parallel_data & mask) ? (PORTB |= 0x01) : (PORTB &= ~0x01);
		mask <<= 1;

Is that one of the cases where gcc decides that you want to do something 8 times, and therefore creates an entirely unnecessary counter?

 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

 

westfw wrote:

Is that one of the cases where gcc decides that you want to do something 8 times, and therefore creates an entirely unnecessary counter?

Looks like it, yes (and 16 bit counter as well).

(this is with avr-gcc (GCC) 4.9.2 -Os, maybe newer version is better?)

 

int main(void)
{
    DDRB = 0x01;
  80:   81 e0           ldi     r24, 0x01       ; 1
  82:   84 b9           out     0x04, r24       ; 4
    uint8_t parallel_data = PIND, mask = 0x01;
  84:   39 b1           in      r19, 0x09       ; 9
  86:   88 e0           ldi     r24, 0x08       ; 8
  88:   90 e0           ldi     r25, 0x00       ; 0
  8a:   21 e0           ldi     r18, 0x01       ; 1
    while (mask) {
        if (parallel_data & mask)
  8c:   42 2f           mov     r20, r18
  8e:   43 23           and     r20, r19
  90:   11 f0           breq    .+4             ; 0x96 <main+0x16>
            PORTB |= 0x01;
  92:   28 9a           sbi     0x05, 0 ; 5
  94:   01 c0           rjmp    .+2             ; 0x98 <main+0x18>
        else
            PORTB &= ~0x01;
  96:   28 98           cbi     0x05, 0 ; 5
        mask <<= 1;
  98:   22 0f           add     r18, r18
  9a:   01 97           sbiw    r24, 0x01       ; 1

int main(void)
{
    DDRB = 0x01;
    uint8_t parallel_data = PIND, mask = 0x01;
    while (mask) {
  9c:   b9 f7           brne    .-18            ; 0x8c <main+0xc>
            PORTB |= 0x01;
        else
            PORTB &= ~0x01;
        mask <<= 1;
    }
    while (1);
  9e:   ff cf           rjmp    .-2             ; 0x9e <main+0x1e>

 

 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Is there a way to tell GCC that, say RPM, is an important 16 bit value (in a motor controller app) & should be kept in a register pair, rather than delegated to sram with "lower-importance" values.  This  is a matter of efficiency, since, of  course, register values can be read, compared, & manipulated much more efficiently.  I don't think GCC would be able to determine which variables are most critical, in terms of impacting efficiency---or does it?.  I've meant to look into this, but just declare my variables & move on!!

When in the dark remember-the future looks brighter than ever.   I look forward to being able to predict the future!

Last Edited: Sat. Oct 12, 2019 - 10:09 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

(note: reply to #48 & #49)

 

Yes, this is, let's say, my pet peeve with the gcc optimizer. So it's not the first time I mention it: https://www.avrfreaks.net/forum/...

There is a workaround, explained in that thread.

 

And even the most recent avr-gcc version I have, v9.1.0, still auto-generates a 16 bit counter to count to 8.

So, when people say "Just trust the compiler, it will generate better code than the average programmer would hand code in assembly"... err, no. Maybe it will most of the time, but then mess up a time critical loop. I always double check important parts of the generated code.
 

Last Edited: Sat. Oct 12, 2019 - 10:11 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I think the phrase "will generate code as good as an Asm programmer" is usually with something like "about 90% of the time". Sure there are occasions where it's suboptimal but the positives outweigh the negatives.

 

As a simple exercise write a JPEG encoder. Your choice: C or Asm.

 

Report back in 2 weeks ;-)

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

clawson wrote:

I think the phrase "will generate code as good as an Asm programmer" is usually with something like "about 90% of the time". Sure there are occasions where it's suboptimal but the positives outweigh the negatives.

 

Actually the positives _far_ outweigh the negatives, I'm not arguing about that. Just saying, that if the compiler screws up 10% of the time, and 10% of the code is time critical, there is a 1% chance that the compiler will screw up time critical code. It happens. So I like to check the quality of generated code in these parts just to be sure.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 1

avrcandies wrote:
I don't think GCC would be able to determine which variables are most critical, in terms of impacting efficiency---or does it?

 

In 9 cases out of 10 GCC will much better than the user at determining it.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

avrcandies wrote:

Is there a way to tell GCC that, say RPM, is an important 16 bit value (in a motor controller app) & should be kept in a register pair, rather than delegated to sram with "lower-importance" values.

 

I believe there is a keyword modifier 'register' that you can apply to variables, but it would probably depend on the compiler.  S.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

clawson wrote:

I think the phrase "will generate code as good as an Asm programmer" is usually with something like "about 90% of the time". Sure there are occasions where it's suboptimal but the positives outweigh the negatives.

 

The problem I have there is that you don't know when it's being weird, without inspecting the asm code, which isn't that far off writing it in the first place.  Freely granted, most of the time it doesn't matter, but when it does, you might want to know.

 

clawson wrote:

As a simple exercise write a JPEG encoder. Your choice: C or Asm.

 

Report back in 2 weeks ;-)

 

My AVRs don't do that.  They interact with external hardware, not pushing pixels around!  If you want to push pixels, get a Rasp Pi or something, and yes, use C to your heart's content therein.

 

It's very rarely raw speed (is if you're calculating Mersenne primes, but that's an oddball case), it's much more frequently needing precise timing to interact with the other hardware.  Yes, it would be nice to have optimized code in the user interface.  That is absolutely not worth it if the compiler optimizes out the 'nop's that provide the precision timing!  (Oh, I'm sure there's ways to force the compiler to behave itself, but why bother fighting it?)

 

I like to write down not what I want the chip to do, but exactly what the chip is going to do.  So I cut out the middleman.  Call me a Luddite if you want to.  I write my AVR code in assembler.  So there.  ;-P   S.

 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Scroungre wrote:
I believe there is a keyword modifier 'register' that you can apply to variables, but it would probably depend on the compiler

The keyword is part of the language standard.

 

What - if any - effect it has will depend upon the particular compiler.

 

I think it is largely ignored by modern compilers ... ?

Top Tips:

  1. How to properly post source code - see: https://www.avrfreaks.net/comment... - also how to properly include images/pictures
  2. "Garbage" characters on a serial terminal are (almost?) invariably due to wrong baud rate - see: https://learn.sparkfun.com/tutorials/serial-communication
  3. Wrong baud rate is usually due to not running at the speed you thought; check by blinking a LED to see if you get the speed you expected
  4. Difference between a crystal, and a crystal oscillatorhttps://www.avrfreaks.net/comment...
  5. When your question is resolved, mark the solution: https://www.avrfreaks.net/comment...
  6. Beginner's "Getting Started" tips: https://www.avrfreaks.net/comment...