C AVR32_GCC compiler and compile time const (modulo optimization)

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

Hi,

I currently have trouble making the compiler to optimize a modulo if a variable is the power of two.

 

#define RING_BUFFER_SIZE1 256
#define RING_BUFFER_SIZE2 512

struct RING_BUFFER
{
	const uint32_t size;
	uint32_t head;
	...
};

struct RING_BUFFER ring1 = { RING_BUFFER_SIZE1 };
struct RING_BUFFER ring2 = { RING_BUFFER_SIZE2 };

uint32_t calc( struct RING_BUFFER *ring )
{
	return ( ring->head + 1 ) % size;
}

 

As far as i understand this const in c is just read only so its not a compile time const right? How would you solve this problem?

 

My current solution is to replace the module operation with 

static inline uint32_t modulo( uint32_t value, uint32_t div)
{
	return value & ( div - 1 );
}

and just assume( document the definition ) that RING_BUFFER_SIZE1 is of power of 2. Is there a neat way assert/check that a #define something is the power of two?

This topic has a solution.
Last Edited: Mon. Jul 1, 2019 - 01:26 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

You don't mean % !!

 

The whole point of using a binary multiple is so you can & 

 

(The % operator means do a divide+remainder - never a great choice if it can be avoided).

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

clawson wrote:

You don't mean % !!

 

The whole point of using a binary multiple is so you can & 

 

(The % operator means do a divide+remainder - never a great choice if it can be avoided).

 

I wanted to use the % operator so the code is portable and can be used with sizes that are not of power of two. And if they are of power of two let the compiler optimize the code to do a binary and.

Also it would be nice do so something like this.

#if  isNotPowerOfTwo(RING_BUFFER_SIZE1)
#warning "May cause performance issues"
#endif

 

Last Edited: Mon. Jul 1, 2019 - 12:51 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

But then you can't get the optimzation?!? It relies on the & mask to avoid having to do anything like a modulo.

This reply has been marked as the solution. 
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Craftplorer wrote:
I wanted to use the % operator so the code is portable and can be used with sizes that are not of power of two. And if they are of power of two let the compiler optimize the code to do a binary and.

I think in C you only can create macro like this for verifying if the value is power of two during compile time:

#define isNotPowerOfTwo(x) (((x) != 1) && ((x) != 2) && ((x) != 4) ... ... ((x) != 32768u))

And note that size in your code sample, although const, is not compile time constant and even if you initialize it with power of 2 the compiler probably won't create code more optimized than for any other value.

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

MarekJ71 wrote:
And note that size in your code sample, although const, is not compile time constant and even if you initialize it with power of 2 the compiler probably won't create code more optimized than for any other value.

Yeah that was I noticed.

 

MarekJ71 wrote:
#define isNotPowerOfTwo(x) (((x) != 1) && ((x) != 2) && ((x) != 4) ... ... ((x) != 32768u))

Thanks i will try your macro.

 

EDIT:

I went with this macro:

#define isNotPowerOfTwo(x) ((x & (x -1)) != 0)

 

Last Edited: Mon. Jul 1, 2019 - 01:34 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Your version is much better.

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

Craftplorer wrote:

#define isNotPowerOfTwo(x) ((x & (x -1)) != 0)

You should have parenthesis around the argument, and you don't need the comparison:

 

#define isNotPowerOfTwo(x) ((x) & ((x) - 1))

 

"Experience is what enables you to recognise a mistake the second time you make it."

"Good judgement comes from experience.  Experience comes from bad judgement."

"Wisdom is always wont to arrive late, and to be a little approximate on first possession."

"When you hear hoofbeats, think horses, not unicorns."

"Fast.  Cheap.  Good.  Pick two."

"We see a lot of arses on handlebars around here." - [J Ekdahl]

 

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

joeymorin wrote:

You should have parenthesis around the argument, and you don't need the comparison

 

Thank you. Im not that used to c macro stuff.

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

I would skip the power of 2, not worth the trouble to gain a few bytes of code (you are apparently working with avr32, so the few bytes are meaningless). Just compare the value to a size, and zero it if >=.

 

if( ++head >= somesize ) head = 0;

 

Then you can get rid of a macro, no longer have to keep your buffers at powers of 2, is simpler to read and understand, and you can have any buffer size you wish and not have to ever think about it again. There are plenty of other problems to worry about, why add one more to the list.

 

Its easy to get fixated on some of these older 'clever techniques' that may at one time have been necessary, where saving bytes of code were required. We now have the luxury of writing code in a straight-forward manner that is readable/understandable, the compilers can sort it all out efficiently and we end up with more reliable code that one can (mostly) understand years later. Code littered with 'clever' can be quite difficult to understand later, even when you were the one that wrote it.

 

Just my opinion.

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

curtvm wrote:
We now have the luxury of writing code in a straight-forward manner that is readable/understandable
Sort of depends if you are programming for a volume application or not doesn't it? If just one trick brings you back across a binary boundary so now you can use the 2K model instead of the 4K model and save $0.10 then if you are making 5,000,000 you just saved $500,000. There's also a question of speed/efficiency. Sometimes ring buffers are being used on very fast data streams and the odd opcode saved could have a significant influence on things.