The load/store shouldn't go away (especially at -O0). regehr@home:~$ current-gcc -O0 vol.c -S -o - foo: pushl %ebp movl %esp, %ebp popl %ebp ret regehr@home:~$ cat small.c const volatile int g_2 = 1; int g_1 = 0; void func_1 (void) { g_1 = g_2; } int main (void) { g_1 = g_2; return 0; } regehr@home:~$ current-gcc -v Using built-in specs. COLLECT_GCC=current-gcc COLLECT_LTO_WRAPPER=/mnt/z/z/compiler-install/gcc-r169118-install/libexec/gcc/i686-pc-linux-gnu/4.6.0/lto-wrapper Target: i686-pc-linux-gnu Configured with: ../configure --with-libelf=/usr/local --enable-lto --prefix=/mnt/z/z/compiler-install/gcc-r169118-install --program-prefix=r169118- --enable-languages=c,c++ Thread model: posix gcc version 4.6.0 20110122 (experimental) (GCC)
Ack, sorry, wrong testcase! This is it: struct s2 { volatile int x; }; struct s2 s; void foo (void) { s = s; }
Not sure if this is a bug at all, structure assignment should be implementable using memcpy or memmove and thus the side effects that will happen on it are not very well defined.
(In reply to comment #2) > Not sure if this is a bug at all, structure assignment should be implementable > using memcpy or memmove and thus the side effects that will happen on it are > not very well defined. Hi Jakub- "volatile" isn't a very strong guarantee, but realistically people assume that if a volatile is on the RHS of an assignment, a load from that location occurs (and a store, if on the LHS). My guess is that violating this contract will confuse embedded systems developers and break previously working code. Also, if the rule for volatile becomes significantly different from what I said above, we won't be able to do volatile testing anymore since violations will be sort of meaningless.
This is related to PR45472 and is solely about volatile fields in aggregates.
I think we should respect volatile on fields, and not use memcpy/memmove for assignment of volatile structs or structs with volatile fields (at least not for the parts with those fields; it's probably OK, but not worthwhile, for the non-volatile bits of the structs).
We should at least make sure to use memcpy for the array part in struct { volatile int i; int a[100000]; } a, b; a = b; do we really want to blow up code-size (and compile-time) for struct { volatile int a[1000000]; } a, b; a = b; ? And what's the difference of the above to volatile struct { int a[1000000]; } a, b; a = b; ? What do other compilers do for the above? Is there a DR?
(In reply to comment #6) > struct { > volatile int a[1000000]; > } a, b; > a = b; > > ? And what's the difference of the above to > > volatile struct { > int a[1000000]; > } a, b; > a = b; There's no effective difference, I believe.
On Tue, 25 Jan 2011, rguenth at gcc dot gnu.org wrote: > do we really want to blow up code-size (and compile-time) for > > struct { > volatile int a[1000000]; > } a, b; > a = b; > > ? And what's the difference of the above to > > volatile struct { > int a[1000000]; > } a, b; > a = b; > > ? I think these are much the same - and of course an inline loop would be better than blowing up code size with separate instructions for each int. If in doubt, be conservative about the volatile values possibly being in some special kind of mapped memory that memcpy/memmove may not work with (and where certainly there should be exactly the correct number of reads and writes of each memory location).
Just wanted to ping about this one; it's still there in tonight's GCC. regehr@home:~$ cat vol.c struct s2 { volatile int x; }; struct s2 s; void foo (void) { s = s; } regehr@home:~$ gcc -O0 vol.c -c regehr@home:~$ objdump -d vol.o vol.o: file format elf64-x86-64 Disassembly of section .text: 0000000000000000 <foo>: 0: 55 push %rbp 1: 48 89 e5 mov %rsp,%rbp 4: 5d pop %rbp 5: c3 retq regehr@home:~$ gcc -v Using built-in specs. COLLECT_GCC=gcc COLLECT_LTO_WRAPPER=/home/regehr/z/compiler-install/gcc-r195565-install/libexec/gcc/x86_64-unknown-linux-gnu/4.8.0/lto-wrapper Target: x86_64-unknown-linux-gnu Configured with: /home/regehr/z/compiler-source/gcc/configure --with-libelf=/usr/local --enable-lto --prefix=/home/regehr/z/compiler-install/gcc-r195565-install --enable-languages=c,c++ Thread model: posix gcc version 4.8.0 20130129 (experimental) (GCC)
struct s2 { volatile int x; }; struct s2 s; void foo (void) { s = s; } As said previously I think that volatile struct members are ill-defined. The only way for the middle-end to see the volatileness in the above s = s copy is if the frontend would make 's' volatile. That is, effectively make it struct s2 { volatile int x; }; typedef volatile struct s2 S; S s; as there is otherwise no way to mark 's' in s = s with TREE_THIS_VOLATILE (it's the plain decl, which in the original testcase is not volatile).
Or the FE should expand the structure assignment in that case to some other stmts based on what the right semantics is (using loops for larger objects etc.) and only keep aggregate assignments in the IL for non-volatile (neither object itself, nor any of the fields) assignments.
(In reply to comment #10) > As said previously I think that volatile struct members are ill-defined. As far as the C standard goes, I believe the situation is clear: a volatile struct member is a volatile-qualified variable and the rules for volatile variables apply to it. Clang, for example, turns foo() into a load + store at all optimization levels. I believe the Intel compiler does as well but I don't have it available right now.
I guess we could e.g. handle this in c_gimplify_expr, but the question is what the exact semantics should it have. Testcase: struct S { int a; volatile int b; long c; volatile char d[10]; char e[10]; }; struct S a, b; volatile struct S c, d; union U { int a; volatile char b[10]; volatile long c[5]; }; union U e, f; volatile union U g, h; struct T { int a; volatile int b; union U c; volatile union U d; }; struct T i, j; volatile struct T k, l; struct V { int a : 5; volatile int b : 7; volatile int c : 1; int d; volatile long e : 5; long f : 6; volatile long g : 1; long h : 1; }; struct V m, n; volatile struct V o, p; void f1 () { a = b; } void f2 () { c = b; } void f3 () { a = d; } void f4 () { c = d; } void f5 () { e = f; } void f6 () { g = f; } void f7 () { e = h; } void f8 () { g = h; } void f9 () { i = j; } void f10 () { k = j; } void f11 () { i = l; } void f12 () { k = l; } void f13 () { m = n; } void f14 () { o = n; } void f15 () { m = p; } void f16 () { o = p; } I guess for struct S, it could gimplify it for f1 to: a.a = b.a; a.b = b.b; a.c = b.c; for (temp = 0; temp < 10; temp++) a.d[i] = b.d[i]; a.e = b.e; // aggregate assignment and for f2, f3 and f4 the same, except that instead of the aggregate assignment at the end it would emit a loop similar to d field. But, what to do about unions? The standard says that only one union member is active, but which one it is? I think the compiler generally can't know. So, do we just ignore unions and expand them always as we used to? Pick up the first union member (or randomly or preferrably one with volatile)? What about bitfields? Does it have to be per bitfield assignment, or can we e.g. assign the whole representative field at a time? What are other compilers doing here? I've tried clang 3.1, and don't see it would consider any of the volatile keywords here in any way.
(In reply to comment #13) > But, what to do about unions? The standard says that only one union member is > active, but which one it is? I think the compiler generally can't know. So, > do we just ignore unions and expand them always as we used to? Pick up the > first union member (or randomly or preferably one with volatile)? C++ defines copy of a (trivially copyable) union to copy the object representation, which is not volatile unless the whole union is volatile. I can't find anything relevant in C11. There is also C++ DR 496: http://www.open-std.org/JTC1/SC22/WG21/docs/cwg_toc.html#496 It seems the effect of this change will be to make assignment of a union with a volatile field ill-formed in C++ unless the union has a user-provided assignment operator. I think we just ignore unions, at least in the middle end. > What about bitfields? Does it have to be per bitfield assignment, or can we > e.g. assign the whole representative field at a time? I think we should follow the memory model data race rules here; volatile accesses are done per memory location, rather than per field.
I think the most obvious way to handle volatile and unions for C would be to follow the handling of const (set C_TYPE_FIELDS_VOLATILE in the same way as C_TYPE_FIELDS_READONLY - that is, checking for fields whose types have C_TYPE_FIELDS_VOLATILE rather than just fields that are directly volatile - and use it to determine whether the struct or union is at least in part volatile for assignment). Though for unions the best you can do might be a copying loop; without knowing the active union member you can hardly respect access sizes for individual members, even if you wanted to.
Dear all a possibly related issue. Consider struct S1 { long f; }; volatile struct S1 g; struct S1 func_1 () { return g; } void main () { func_1 (); } This program, if compiled with a recent gcc svn: $ gcc -v Target: x86_64-unknown-linux-gnu gcc version 4.9.0 20130625 (experimental) (GCC) correctly loads the long at g.f at -O0. However the assembly generated at -O2: func_1: movq g(%rip), %rax ret main: rep; ret does not perform the volatile load access, which, as far as I understand, is incorrect. -francesco
*** Bug 58409 has been marked as a duplicate of this bug. ***
(In reply to Francesco Zappa Nardelli from comment #16) > Dear all > > a possibly related issue. Consider > > struct S1 { > long f; > }; > volatile struct S1 g; > > struct S1 func_1 () { > return g; > } > > void main () { > func_1 (); > } > > This program, if compiled with a recent gcc svn: > > $ gcc -v > Target: x86_64-unknown-linux-gnu > gcc version 4.9.0 20130625 (experimental) (GCC) > > correctly loads the long at g.f at -O0. However the assembly generated at > -O2: > > func_1: > movq g(%rip), %rax > ret > main: > rep; ret > > does not perform the volatile load access, which, as far as I understand, is > incorrect. It does starting with GCC 4.8.2 and was a bug in older GCC versions. Richard. > -francesco
>> does not perform the volatile load access. > It does starting with GCC 4.8.2 and was a bug in older GCC versions. I just tested my example (comment 16) against yesterday trunk gcc version 4.9.0 20130912 (experimental) (GCC) and indeed the volatile load access is no longer removed. This is a good news. However the code I reported in bug 58409, which has been marked duplicate of this bug, still exhibits the incorrect reordering of volatile accesses. It thus seems to me that either bug 58409 is not a duplicate of this one, or the fix is incomplete. -francesco
(In reply to Francesco Zappa Nardelli from comment #19) > >> does not perform the volatile load access. > > > It does starting with GCC 4.8.2 and was a bug in older GCC versions. > > I just tested my example (comment 16) against yesterday trunk > > gcc version 4.9.0 20130912 (experimental) (GCC) > > and indeed the volatile load access is no longer removed. This is a good > news. > > However the code I reported in bug 58409, which has been marked duplicate of > this bug, still exhibits the incorrect reordering of volatile accesses. It > thus seems to me that either bug 58409 is not a duplicate of this one, or > the fix is incomplete. It is a duplicate of this one because it is about a volatile struct member in a not volatile object g_3[1][1][1]. And it is about the aggregate assignment to that struct. > -francesco
(In reply to Richard Biener from comment #20) > > However the code I reported in bug 58409, which has been marked duplicate of > > this bug, still exhibits the incorrect reordering of volatile accesses. It > > thus seems to me that either bug 58409 is not a duplicate of this one, or > > the fix is incomplete. > > It is a duplicate of this one because it is about a volatile struct member > in a not volatile object g_3[1][1][1]. And it is about the aggregate > assignment to that struct. Agreed. What I don't understand is the fact that the commits that led to the recent gcc svn trunk gcc version 4.9.0 20130912 (experimental) (GCC) solve the problem with the code in comment 16, but do not prevent the reordering of volatile writes described in bug 58409. As a consequence, it seems to me that gcc does not yet implement a correct semantics for accesses to volatile struct members in non volatile objects. Am I missing something or another fix is to be expected? Thanks. -francesco
*** Bug 260998 has been marked as a duplicate of this bug. *** Seen from the domain http://volichat.com Page where seen: http://volichat.com/adult-chat-rooms Marked for reference. Resolved as fixed @bugzilla.
The C++ bug for this is PR 69494.
*** Bug 106335 has been marked as a duplicate of this bug. ***