Sylvain Leroux schrieb:
Hi,
It seems to me that avr-gcc/avr-g++ is producing sub-optimal code for
the 'f' function in the following source code:
---------8<-----------------------------------
#include <avr/io.h>
void f(uint32_t i) {
i |= ((uint32_t)(0xFF) << 16);
/* DDRA is an 8 bit register */
DDRA = (uint32_t)(i);
DDRA = (uint32_t)(i>>8);
DDRA = (uint32_t)(i>>16);
DDRA = (uint32_t)(i>>24);
}
int main() {
volatile uint32_t n = 0x01020304;
f(n);
}
---------8<-----------------------------------
Having compiled with the following options:
avr-gcc c.c -mmcu=attiny2313
-Os -ffunction-sections -fdata-sections
-g -Wl,--gc-sections -Wl,--print-gc-sections
-fipa-cp -fcprop-registers -fweb
... here is the relevant fragment as displayed by avr-objdump. I marked
with a star (*) all the instruction that appears to be useless:
---------8<-----------------------------------
void f(uint32_t i) {
i |= ((uint32_t)(0xFF) << 16);
34: 8f 6f ori r24, 0xFF ; 255
DDRA = (uint32_t)(i);
36: 6a bb out 0x1a, r22 ; 26
DDRA = (uint32_t)(i>>8);
38: 27 2f mov r18, r23
* 3a: 38 2f mov r19, r24
* 3c: 49 2f mov r20, r25
* 3e: 55 27 eor r21, r21
40: 2a bb out 0x1a, r18 ; 26
DDRA = (uint32_t)(i>>16);
42: 9c 01 movw r18, r24
* 44: 44 27 eor r20, r20
* 46: 55 27 eor r21, r21
48: 2a bb out 0x1a, r18 ; 26
DDRA = (uint32_t)(i>>24);
4a: 69 2f mov r22, r25
* 4c: 77 27 eor r23, r23
* 4e: 88 27 eor r24, r24
* 50: 99 27 eor r25, r25
52: 6a bb out 0x1a, r22 ; 26
}
54: 08 95 ret
---------8<-----------------------------------
Both gcc and g++ produce the same code. And I get the same results both
with 4.3.5 and 4.7.1
Here is my question:
Is there any option(s) that will help gcc to not produce those extra
instructions in such case?
This is PR49807 which is not avr specific.
PR49807 is missed RTL optimization, but other targets like 32-bit
targets typically don't see it because their SFRs are 32 bits wide.
Just compile the following test case and the issue is gone.
If you remove the #define a, b, c, d you see PR49807 again.
Johann
--
typedef unsigned long uint32_t;
#define DDRA (*(volatile unsigned char*) 0x3A)
extern unsigned char a, b, c, d;
#define a DDRA
#define b DDRA
#define c DDRA
#define d DDRA
void f (uint32_t i)
{
i |= 0xFFul << 16;
/* DDRA is an 8 bit register */
a = i;
b = i >> 8;
c = i >> 16;
d = i >> 24;
}