This is the mail archive of the
gcc-help@gcc.gnu.org
mailing list for the GCC project.
Missed optimization when using a structure
- From: Victor Stinner <victor dot stinner at gmail dot com>
- To: gcc-help at gcc dot gnu dot org
- Date: Tue, 23 Apr 2013 23:26:06 +0200
- Subject: Missed optimization when using a structure
Hi,
I'm trying to refactor some code to use a structure (struct { char*
ptr; }) instead of a pointer (char *). The problem is that GCC
produces less efficient code for loops when a structure is used. I
don't understand why GCC is unable to produce the same code.
Is it an aliasing issue? I added __restrict__ keyword, I tried
-fno-strict-aliasing and -fstrict-aliasing, but it does not change
anything.
The loop causing me headaches:
for(i=0; i<n; i++)
*writer.str++ = '?';
With a structure, the pointer value (old, writer.str) is loaded and
stored (new, writer.str++) at each iteration. Depending on the exact
code (and GCC version), the load is sometimes moved out of the loop
(done before the loop).
Using a pointer (char*), GCC always emit the best code: load the
pointer before the loop, and store the new value at the end of the
loop.
Full code:
---
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
typedef struct {
char* __restrict__ str;
char buffer[100];
} writer_t;
void writer_init(writer_t* __restrict__ writer)
{
writer->str = writer->buffer;
}
static char*
encode(int test, int n)
{
int i;
writer_t writer;
writer_init(&writer);
if (test) {
*writer.str++ = 'a';
}
else {
for(i=0; i<n; i++)
*writer.str++ = '?';
}
*writer.str = '\0';
return strdup(writer.buffer);
}
int main(int argc, char **argv)
{
char *str;
str = encode(0, argc);
printf("encode ascii: %s\n", str);
free(str);
return 0;
}
---
Example of assembler output on x86 with GCC 4.4.
# gcc (GCC) 4.4.1 20090725 (Red Hat 4.4.1-2)
$ gcc test.c -O3 -fno-inline -o- -S|grep 63 -B6 -A5
...
movl -112(%ebp), %eax
xorl %ecx, %ecx
.p2align 4,,7
.p2align 3
.L7:
addl $1, %ecx
movb $63, (%eax)
addl $1, %eax
cmpl %esi, %ecx
movl %eax, -112(%ebp)
jne .L7
...
To use a pointer instead of a structure, replace encode with the
following function:
---
static char*
encode(int test, int n)
{
int i;
writer_t writer;
char *str;
writer_init(&writer);
str = writer.str;
if (test) {
*str++ = 'a';
}
else {
for(i=0; i<n; i++)
*str++ = '?';
}
*str = '\0';
return strdup(writer.buffer);
}
---
Assembler output:
# gcc (GCC) 4.4.1 20090725 (Red Hat 4.4.1-2)
$ gcc -O3 -fno-inline -S -o- a.c|grep 63 -B5 -A5
...
.L10:
addl $1, %ecx
movb $63, (%eax)
addl $1, %eax
cmpl %ecx, %edi
ja .L10
...
Any idea?
Victor