[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
Re: [avr-gcc-list] [bug] cbi optimization error for 8-bit AVRs
From: |
Szikra István |
Subject: |
Re: [avr-gcc-list] [bug] cbi optimization error for 8-bit AVRs |
Date: |
Sat, 08 Nov 2014 21:42:34 +0100 |
User-agent: |
Mozilla/5.0 (Windows NT 6.1; WOW64; rv:31.0) Gecko/20100101 Thunderbird/31.2.0 |
On 2014.11.08. 13:48, David Brown wrote:
On 08/11/14 01:32, Szikra István wrote:
Hi everyone!
My problem in sort: I’m getting
in r24, 0x18
ldi r25, 0x00
andi r24, 0xEF
out 0x18, r24
instead of
cbi 0x18, 4
.
I’m trying to write efficient modern C/C++ code for multiple platforms
including AVR 8 bit controllers.
Unfortunately GCC support for AVR (among other things) is not always
flawless. And it changes from versions to version (and not always for
the better).
Since I’m a long time AVR developer I have a lot of compiler versions
installed (WinAVR 2006-2010, and Atmel Studio 6.2 with GCC 4.8.1), but I
could test my code with only one (the latest).
I run into some trouble with clearing port bits not translating from C
into cbi in assembler. It is caused by my bits template, but I do not
know why. It seems to me like a bug in GCC. Maybe someone here can shed
some light on the reason, or suggest a fix.
Here is the code:
#include <avr/io.h>
//#include <bits.hpp>
template<typename T>
constexpr unsigned int bits(T idx1)
{
return (1<<idx1);
}
template <typename T, typename... Rest>
constexpr unsigned int bits(T idx1, Rest... r)
{
return (1<<idx1) | bits(r...);
}
Just an idea that might be worth trying - try replacing the "unsigned
int" return type with "uint8_t" (/always/ use <stdint.h> types with
defined bit sizes!). AVR gcc has quite a number of optimisations and
special case patterns for dealing with 8-bit types, especially uint8_t,
and it often gives tighter code if you've used uint8_t even if uint16_t
gives the same actual values.
Thanks, I have already tried using unsigned char return type, and also
casting it. It did not help.
PORTB &=~ (uint8_t)bits(4);
28: 88 b3 in r24, 0x18 ; 24
2a: 90 e0 ldi r25, 0x00 ; 0
2c: 8f 7e andi r24, 0xEF ; 239
2e: 88 bb out 0x18, r24 ; 24
But, what helped was casting the result of ~:
PORTB &= (uint8_t)~bits(4);
28: c4 98 cbi 0x18, 4 ; 24
Secondly, consider making your templates based on the value of idx1
rather than the type - the type will always be an int (or promoted to an
int in the shift expression). Alternatively, drop the template entirely.
Yeah, I just replaced the bits(idx) with (1<<idx) in my code, till the
bug is fixed. Now I'm changing it to casting...
_port &= (unsigned char)~bits(_index);
What do you mean by basing the template on the value of idx1?
I'm still new to templates. Actually I don't need T at all.
constexpr unsigned int bits(int idx1)
{
return (1<<idx1);
}
template <typename... Rest>
constexpr unsigned int bits(int idx1, Rest... r)
{
return (1<<idx1) | bits(r...);
}
Regards,
Steven