Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]
Groups > comp.lang.c > #61986 > unrolled thread
| Started by | "James Harris" <james.harris.1@gmail.com> |
|---|---|
| First post | 2015-05-14 11:43 +0100 |
| Last post | 2015-05-24 08:11 -0700 |
| Articles | 20 on this page of 101 — 15 participants |
Back to article view | Back to comp.lang.c
Sequence points and commit to memory "James Harris" <james.harris.1@gmail.com> - 2015-05-14 11:43 +0100
Re: Sequence points and commit to memory Richard Heathfield <rjh@cpax.org.uk> - 2015-05-14 12:02 +0100
Re: Sequence points and commit to memory David Brown <david.brown@hesbynett.no> - 2015-05-14 13:39 +0200
Re: Sequence points and commit to memory Richard Heathfield <rjh@cpax.org.uk> - 2015-05-14 13:18 +0100
Re: Sequence points and commit to memory David Brown <david.brown@hesbynett.no> - 2015-05-14 23:11 +0200
Re: Sequence points and commit to memory Stephen Sprunk <stephen@sprunk.org> - 2015-05-14 09:06 -0500
Re: Sequence points and commit to memory Siri Cruz <chine.bleu@yahoo.com> - 2015-05-14 08:35 -0700
Re: Sequence points and commit to memory David Kleinecke <dkleinecke@gmail.com> - 2015-05-14 10:23 -0700
Re: Sequence points and commit to memory Siri Cruz <chine.bleu@yahoo.com> - 2015-05-14 10:44 -0700
Re: Sequence points and commit to memory David Kleinecke <dkleinecke@gmail.com> - 2015-05-14 11:09 -0700
Re: Sequence points and commit to memory Keith Thompson <kst-u@mib.org> - 2015-05-14 12:58 -0700
Re: Sequence points and commit to memory Morris Dovey <mrdovey@iedu.com> - 2015-05-14 16:31 -0500
Re: Sequence points and commit to memory Keith Thompson <kst-u@mib.org> - 2015-05-14 17:24 -0700
Re: Sequence points and commit to memory Morris Dovey <mrdovey@iedu.com> - 2015-05-14 20:18 -0500
Re: Sequence points and commit to memory David Brown <david.brown@hesbynett.no> - 2015-05-15 09:34 +0200
Re: Sequence points and commit to memory Morris Dovey <mrdovey@iedu.com> - 2015-05-15 10:18 -0500
Re: 'register' attribute (was: Sequence points and commit to memory) Morris Dovey <mrdovey@iedu.com> - 2015-05-16 01:26 -0500
Re: 'register' attribute David Brown <david.brown@hesbynett.no> - 2015-05-17 00:02 +0200
Re: 'register' attribute Morris Dovey <mrdovey@iedu.com> - 2015-05-16 19:29 -0500
Re: Sequence points and commit to memory David Kleinecke <dkleinecke@gmail.com> - 2015-05-15 09:52 -0700
Re: Sequence points and commit to memory James Kuyper <jameskuyper@verizon.net> - 2015-05-15 13:27 -0400
Re: Sequence points and commit to memory Keith Thompson <kst-u@mib.org> - 2015-05-15 10:50 -0700
Re: Sequence points and commit to memory Morris Dovey <mrdovey@iedu.com> - 2015-05-15 12:32 -0500
Re: Sequence points and commit to memory David Brown <david.brown@hesbynett.no> - 2015-05-14 23:23 +0200
Re: Sequence points and commit to memory David Kleinecke <dkleinecke@gmail.com> - 2015-05-15 09:42 -0700
Re: Sequence points and commit to memory James Kuyper <jameskuyper@verizon.net> - 2015-05-15 13:13 -0400
Re: Sequence points and commit to memory David Kleinecke <dkleinecke@gmail.com> - 2015-05-16 08:32 -0700
Re: Sequence points and commit to memory Keith Thompson <kst-u@mib.org> - 2015-05-15 10:35 -0700
Re: Sequence points and commit to memory Keith Thompson <kst-u@mib.org> - 2015-05-15 11:08 -0700
Re: Sequence points and commit to memory Robert Wessel <robertwessel2@yahoo.com> - 2015-05-15 16:40 -0500
Re: Sequence points and commit to memory David Kleinecke <dkleinecke@gmail.com> - 2015-05-16 08:48 -0700
Re: Sequence points and commit to memory "James Harris" <james.harris.1@gmail.com> - 2015-05-15 21:46 +0100
Re: Sequence points and commit to memory David Kleinecke <dkleinecke@gmail.com> - 2015-05-16 08:56 -0700
Re: Sequence points and commit to memory "James Harris" <james.harris.1@gmail.com> - 2015-05-16 19:35 +0100
Re: Sequence points and commit to memory David Kleinecke <dkleinecke@gmail.com> - 2015-05-18 09:49 -0700
Re: Sequence points and commit to memory "James Harris" <james.harris.1@gmail.com> - 2015-05-19 09:04 +0100
Re: Sequence points and commit to memory Keith Thompson <kst-u@mib.org> - 2015-05-19 08:42 -0700
Re: Sequence points and commit to memory "James Harris" <james.harris.1@gmail.com> - 2015-05-14 22:00 +0100
Re: Sequence points and commit to memory Siri Cruz <chine.bleu@yahoo.com> - 2015-05-14 14:26 -0700
Re: Sequence points and commit to memory "James Harris" <james.harris.1@gmail.com> - 2015-05-14 22:33 +0100
Re: Sequence points and commit to memory David Brown <david.brown@hesbynett.no> - 2015-05-14 23:38 +0200
Re: Sequence points and commit to memory "James Harris" <james.harris.1@gmail.com> - 2015-05-14 23:04 +0100
Re: Sequence points and commit to memory Stephen Sprunk <stephen@sprunk.org> - 2015-05-15 13:09 -0500
Re: Sequence points and commit to memory "James Harris" <james.harris.1@gmail.com> - 2015-05-15 21:56 +0100
Re: Sequence points and commit to memory James Kuyper <jameskuyper@verizon.net> - 2015-05-15 17:30 -0400
Re: Sequence points and commit to memory "James Harris" <james.harris.1@gmail.com> - 2015-05-16 07:51 +0100
Re: Sequence points and commit to memory James Kuyper <jameskuyper@verizon.net> - 2015-05-16 22:10 -0400
Re: Sequence points and commit to memory David Brown <david.brown@hesbynett.no> - 2015-05-19 00:25 +0200
Re: Sequence points and commit to memory James Kuyper <jameskuyper@verizon.net> - 2015-05-18 18:55 -0400
Re: Sequence points and commit to memory David Brown <david.brown@hesbynett.no> - 2015-05-19 09:10 +0200
Re: Sequence points and commit to memory James Kuyper <jameskuyper@verizon.net> - 2015-05-19 12:05 -0400
Re: Sequence points and commit to memory David Brown <david.brown@hesbynett.no> - 2015-05-19 18:42 +0200
Re: Sequence points and commit to memory Stephen Sprunk <stephen@sprunk.org> - 2015-05-16 16:33 -0500
Re: Sequence points and commit to memory David Brown <david.brown@hesbynett.no> - 2015-05-19 00:27 +0200
Re: Sequence points and commit to memory James Kuyper <jameskuyper@verizon.net> - 2015-05-18 19:05 -0400
Re: Sequence points and commit to memory glen herrmannsfeldt <gah@ugcs.caltech.edu> - 2015-05-19 00:09 +0000
Re: Sequence points and commit to memory Richard Heathfield <rjh@cpax.org.uk> - 2015-05-19 01:11 +0100
Re: Sequence points and commit to memory Tim Rentsch <txr@alumni.caltech.edu> - 2015-05-23 07:02 -0700
Re: Sequence points and commit to memory James Kuyper <jameskuyper@verizon.net> - 2015-05-18 23:21 -0400
Re: Sequence points and commit to memory glen herrmannsfeldt <gah@ugcs.caltech.edu> - 2015-05-19 06:25 +0000
Re: Sequence points and commit to memory David Brown <david.brown@hesbynett.no> - 2015-05-19 08:58 +0200
Re: Sequence points and commit to memory glen herrmannsfeldt <gah@ugcs.caltech.edu> - 2015-05-19 23:20 +0000
Re: Sequence points and commit to memory David Brown <david.brown@hesbynett.no> - 2015-05-20 12:31 +0200
Re: Sequence points and commit to memory James Kuyper <jameskuyper@verizon.net> - 2015-05-19 12:10 -0400
Re: Sequence points and commit to memory glen herrmannsfeldt <gah@ugcs.caltech.edu> - 2015-05-19 23:24 +0000
Re: Sequence points and commit to memory David Brown <david.brown@hesbynett.no> - 2015-05-19 09:05 +0200
Re: Sequence points and commit to memory Keith Thompson <kst-u@mib.org> - 2015-05-19 08:37 -0700
Re: Sequence points and commit to memory James Kuyper <jameskuyper@verizon.net> - 2015-05-19 12:14 -0400
Re: Sequence points and commit to memory David Brown <david.brown@hesbynett.no> - 2015-05-19 19:02 +0200
Re: Sequence points and commit to memory Robert Wessel <robertwessel2@yahoo.com> - 2015-05-15 16:46 -0500
Re: Sequence points and commit to memory David Brown <david.brown@hesbynett.no> - 2015-05-17 00:20 +0200
Re: Sequence points and commit to memory "James Harris" <james.harris.1@gmail.com> - 2015-05-17 18:19 +0100
Re: Sequence points and commit to memory Philip Lantz <prl@canterey.us> - 2015-05-17 16:11 -0700
Re: Sequence points and commit to memory "James Harris" <james.harris.1@gmail.com> - 2015-05-18 08:30 +0100
Re: Sequence points and commit to memory David Kleinecke <dkleinecke@gmail.com> - 2015-05-18 10:31 -0700
Re: Sequence points and commit to memory Keith Thompson <kst-u@mib.org> - 2015-05-18 11:11 -0700
Re: Sequence points and commit to memory David Kleinecke <dkleinecke@gmail.com> - 2015-05-19 09:37 -0700
Re: Sequence points and commit to memory Ian Collins <ian-news@hotmail.com> - 2015-05-19 17:40 +1200
Re: Sequence points and commit to memory Morris Dovey <mrdovey@iedu.com> - 2015-05-19 01:31 -0500
Re: Sequence points and commit to memory Ian Collins <ian-news@hotmail.com> - 2015-05-19 20:38 +1200
Re: Sequence points and commit to memory Morris Dovey <mrdovey@iedu.com> - 2015-05-19 10:50 -0500
Re: Sequence points and commit to memory David Brown <david.brown@hesbynett.no> - 2015-05-19 00:46 +0200
Re: Sequence points and commit to memory David Brown <david.brown@hesbynett.no> - 2015-05-19 00:35 +0200
Re: Sequence points and commit to memory Robert Wessel <robertwessel2@yahoo.com> - 2015-05-15 16:42 -0500
Re: Sequence points and commit to memory "James Harris" <james.harris.1@gmail.com> - 2015-05-16 07:58 +0100
Re: Sequence points and commit to memory Robert Wessel <robertwessel2@yahoo.com> - 2015-05-16 02:18 -0500
Re: Sequence points and commit to memory "James Harris" <james.harris.1@gmail.com> - 2015-05-16 08:36 +0100
Re: Sequence points and commit to memory Robert Wessel <robertwessel2@yahoo.com> - 2015-05-17 04:31 -0500
Re: Sequence points and commit to memory "James Harris" <james.harris.1@gmail.com> - 2015-05-17 18:24 +0100
Re: Sequence points and commit to memory David Brown <david.brown@hesbynett.no> - 2015-05-19 00:55 +0200
Re: Sequence points and commit to memory Keith Thompson <kst-u@mib.org> - 2015-05-14 11:26 -0700
Re: Sequence points and commit to memory "James Harris" <james.harris.1@gmail.com> - 2015-05-14 22:07 +0100
Re: Sequence points and commit to memory Keith Thompson <kst-u@mib.org> - 2015-05-14 14:22 -0700
Re: Sequence points and commit to memory "James Harris" <james.harris.1@gmail.com> - 2015-05-14 22:36 +0100
Re: Sequence points and commit to memory Tim Rentsch <txr@alumni.caltech.edu> - 2015-05-22 08:16 -0700
Re: Sequence points and commit to memory Keith Thompson <kst-u@mib.org> - 2015-05-22 11:31 -0700
Re: Sequence points and commit to memory James Kuyper <jameskuyper@verizon.net> - 2015-05-15 00:05 -0400
Re: Sequence points and commit to memory "James Harris" <james.harris.1@gmail.com> - 2015-05-15 22:25 +0100
Re: Sequence points and commit to memory James Kuyper <jameskuyper@verizon.net> - 2015-05-15 17:56 -0400
Re: Sequence points and commit to memory Nobody <nobody@nowhere.invalid> - 2015-05-17 10:04 +0100
Re: Sequence points and commit to memory Tim Rentsch <txr@alumni.caltech.edu> - 2015-05-24 08:11 -0700
Page 3 of 6 — ← Prev page 1 2 [3] 4 5 6 Next page →
| From | David Brown <david.brown@hesbynett.no> |
|---|---|
| Date | 2015-05-14 23:38 +0200 |
| Message-ID | <mj34ho$jll$1@dont-email.me> |
| In reply to | #62020 |
On 14/05/15 23:00, James Harris wrote:
> "Siri Cruz" <chine.bleu@yahoo.com> wrote in message
> news:chine.bleu-804F61.08350514052015@news.eternal-september.org...
>> In article <mj1u70$r5d$1@dont-email.me>,
>> "James Harris" <james.harris.1@gmail.com> wrote:
>>
>>> How about:
>>>
>>> u = 0;
>>> f();
>>>
>>> Is u guaranteed to have been written to memory before function f is
>>
>> No. There's nothing in the above that exposes the address of u to f,
>> so f has no
>> legitmate way to know about u.
>>
>> extern int *v; v = &u;
>> u = 0;
>> f();
>>
>> Now the f might have access to the address of u. The compiler would
>> need to have
>> the implementation of f at hand to see if uses any (extern int*), all
>> the places
>> those are used, etc, to safely determine that f still does not have
>> access to u.
>
> If u is a global or, as you point out, its address has been taken and
> stored elsewhere, then the compiler would have to spill u to memory
> before making the function call unless it could prove that f did not
> read or write u. Putting f in another translation unit should do the
> latter part. According to
>
> http://port70.net/~nsz/c/c89/c89-draft.html#2.1.2.3
>
> "Alternatively, an implementation might perform various optimizations
> within each translation unit, such that the actual semantics would agree
> with the abstract semantics only when making function calls across
> translation unit boundaries. In such an implementation, at the time of
> each function entry and function return where the calling function and
> the called function are in different translation units, the values of
> all externally linked objects and of all objects accessible via pointers
> therein would agree with the abstract semantics. "
>
>> MIPS used its loader as a compiler so that it had the entire program
>> text
>> available. It could then do this kind of global analysis.
>>
>>> called? Does f need to be in a different translation unit to force
>>> prior
>>> commits to memory (so that pointers to their values are valid)?
>>
>> If you never take the address of u, it does not need memory allocated;
>> equivalently if you declare register int u, it does not need memory
>> allocated.
>>
>>
>> volatile int u means that no assignment nor load can be redundant. The
>> compiler
>> must assume some unknown process can alter u asynchronously anywhere
>> even in the
>> execution of any instruction except an atomic load or store.
>
> In reality volatile is too strong a restriction. I don't need the values
> to be read from memory each time they are referenced. I only need to
> ensure that updates to them are written to memory.
>
> In the absence of being able to code a proper memory barrier (as per
> David's suggestion) volatile is a good choice.
>
> For the moment I have chosen to make some updates in a function in a
> separate translation unit with the idea that when the called function
> returns across the TU boundary its updates will *have* to have been
> written to memory.
/Bad/ idea. You are introducing additional pessimations in a hope of
making the code correct - and restricting yourself to using a compiler
(or compiler options) that don't allow cross-unit optimisations.
Making u volatile would be simpler, safer, and more efficient - even if
it leads to occasional extra accesses. You can always make a local copy
of it in a non-volatile variable if that helps.
Another option is to use a macro like this:
#define volatileAccess(v) *((volatile typeof((v)) *) &(v))
Then even if u is not volatile, you can write
volatileAccess(u) = 0;
to force that particular storage to be volatile.
(The macro uses the gcc "typeof" extension, which you may or may not like.)
> Example function below. In this case I had to make
> two updates atomic so have added interrupt disable and restore around it
> but the main point is that the updates *should* AFAICS be guaranteed to
> end up in memory before the function returns. After all, there's no way
> they can be kept in registers after the function ends if the compiler
> has no way to do inter-function optimisation.
>
> void dnode_delete(dnode_t *x) {
> unsigned state;
>
> /* Disable interrupts */
> state = irqrx_set(IRQRX_DISABLE);
>
> x->prev.next = x.next;
> x->next.prev = x.prev;
>
> /* Restore interrupt handling */
> irqrx_set(state);
> }
>
> The code is ostentibly simple but making it robust is not!
>
And it is still not correct. There is a good chance that the compiler
will generate the code you want, but it certainly does not have to - so
you are playing a very dangerous game.
The key issue is that while the irqrx_set function is presumably
volatile (or uses a volatile access to the irq flag), and thus the
compiler guarantees that the interrupts will be disabled and then
restored, the standards say nothing about the ordering of volatile
accesses with respect to non-volatile accesses. The compiler could move
the assignments to before the interrupt disable, or after the restore,
or in pretty much any other order it wants.
You have two options here. Make the accesses volatile (by using the
volatileAccess macro above, or declaring x as "volatile dnode_t *x"), or
use a memory barrier after the interrupt disable, and another one before
the re-enable.
You are correct that this stuff is not easy - it's part of why good
embedded developers are in high demand, and poor ones put comments at
the start of files saying "This module must be compiled with
optimisation disabled!".
[toc] | [prev] | [next] | [standalone]
| From | "James Harris" <james.harris.1@gmail.com> |
|---|---|
| Date | 2015-05-14 23:04 +0100 |
| Message-ID | <mj363p$tfs$1@dont-email.me> |
| In reply to | #62030 |
"David Brown" <david.brown@hesbynett.no> wrote in message
news:mj34ho$jll$1@dont-email.me...
> On 14/05/15 23:00, James Harris wrote:
...
>> In the absence of being able to code a proper memory barrier (as per
>> David's suggestion) volatile is a good choice.
>>
>> For the moment I have chosen to make some updates in a function in a
>> separate translation unit with the idea that when the called function
>> returns across the TU boundary its updates will *have* to have been
>> written to memory.
>
> /Bad/ idea. You are introducing additional pessimations in a hope of
> making the code correct - and restricting yourself to using a compiler
> (or compiler options) that don't allow cross-unit optimisations.
I have not heard the word "pessimations" before.
I think I am safe from cross-unit optimisations because I compile each
source file separately. There is no communication between them, even to
say which object files will work with which other object files, until
the linker is run.
> Making u volatile would be simpler, safer, and more efficient - even
> if it leads to occasional extra accesses. You can always make a local
> copy of it in a non-volatile variable if that helps.
Agreed.
...
>> Example function below. In this case I had to make
>> two updates atomic so have added interrupt disable and restore around
>> it
>> but the main point is that the updates *should* AFAICS be guaranteed
>> to
>> end up in memory before the function returns. After all, there's no
>> way
>> they can be kept in registers after the function ends if the compiler
>> has no way to do inter-function optimisation.
>>
>> void dnode_delete(dnode_t *x) {
>> unsigned state;
>>
>> /* Disable interrupts */
>> state = irqrx_set(IRQRX_DISABLE);
>>
>> x->prev.next = x.next;
>> x->next.prev = x.prev;
>>
>> /* Restore interrupt handling */
>> irqrx_set(state);
>> }
>>
>> The code is ostentibly simple but making it robust is not!
>>
>
> And it is still not correct. There is a good chance that the compiler
> will generate the code you want, but it certainly does not have to -
> so you are playing a very dangerous game.
>
> The key issue is that while the irqrx_set function is presumably
> volatile (or uses a volatile access to the irq flag), and thus the
> compiler guarantees that the interrupts will be disabled and then
> restored, the standards say nothing about the ordering of volatile
> accesses with respect to non-volatile accesses.
The irqrx_set function is not even in C. It is written in assembly.
But the main point is that I intended the above dnode_delete function to
commit all of its changes to memory before it returns to its caller.
> The compiler could move the assignments to before the interrupt
> disable, or after the restore, or in pretty much any other order it
> wants.
That is a big surprise - and a big problem. Are you sure that a compiler
could do that? If it did it would change the semantics of the program.
James
[toc] | [prev] | [next] | [standalone]
| From | Stephen Sprunk <stephen@sprunk.org> |
|---|---|
| Date | 2015-05-15 13:09 -0500 |
| Message-ID | <mj5clq$jj$1@dont-email.me> |
| In reply to | #62031 |
On 14-May-15 17:04, James Harris wrote: > "David Brown" <david.brown@hesbynett.no> wrote: >> /Bad/ idea. You are introducing additional pessimations in a hope >> of making the code correct - and restricting yourself to using a >> compiler (or compiler options) that don't allow cross-unit >> optimisations. > > I have not heard the word "pessimations" before. I think that should be "pessimisations". I've also seen "pessimal", to mirror "optimal". > I think I am safe from cross-unit optimisations because I compile > each source file separately. There is no communication between them, > even to say which object files will work with which other object > files, until the linker is run. Some implementations will "compile" source files to an intermediate language, then finish translation during the linking stage, making cross-unit (aka "whole program") optimizations possible. >> The compiler could move the assignments to before the interrupt >> disable, or after the restore, or in pretty much any other order it >> wants. > > That is a big surprise - and a big problem. Are you sure that a > compiler could do that? If it did it would change the semantics of > the program. "Interrupts" are outside the scope of the C Standard, so any use of them will put you outside the realm of defined behavior. "volatile" is often useful for such issues, but what it guarantees may not exactly match what you need. In particular, it often goes _far_ beyond your requirements, and it conflicts with many optimizations that may actually be safe, leading to suboptimal performance. S -- Stephen Sprunk "God does not play dice." --Albert Einstein CCIE #3723 "God is an inveterate gambler, and He throws the K5SSS dice at every possible opportunity." --Stephen Hawking
[toc] | [prev] | [next] | [standalone]
| From | "James Harris" <james.harris.1@gmail.com> |
|---|---|
| Date | 2015-05-15 21:56 +0100 |
| Message-ID | <mj5mf3$770$1@dont-email.me> |
| In reply to | #62059 |
"Stephen Sprunk" <stephen@sprunk.org> wrote in message news:mj5clq$jj$1@dont-email.me... > On 14-May-15 17:04, James Harris wrote: >> "David Brown" <david.brown@hesbynett.no> wrote: ... >>> The compiler could move the assignments to before the interrupt >>> disable, or after the restore, or in pretty much any other order it >>> wants. >> >> That is a big surprise - and a big problem. Are you sure that a >> compiler could do that? If it did it would change the semantics of >> the program. > > "Interrupts" are outside the scope of the C Standard, so any use of > them > will put you outside the realm of defined behavior. It is not interrupts which are the problem. If I understood him correctly David mentioned that in function_call() pointer_manipulations function_call() the compiler could move the pointer manipulations to before the initial function call or after the final function call. That would simply break the code. > "volatile" is often useful for such issues, but what it guarantees may > not exactly match what you need. In particular, it often goes _far_ > beyond your requirements, and it conflicts with many optimizations > that > may actually be safe, leading to suboptimal performance. Agreed. It is too heavyweight a tool but could be used. As someone said, I may be able to maniuplate values in a non-volatile variable and copy them to and from the volatile one when required. That use of a "cached copy" would help ameliorate some of the potential performance issues. James
[toc] | [prev] | [next] | [standalone]
| From | James Kuyper <jameskuyper@verizon.net> |
|---|---|
| Date | 2015-05-15 17:30 -0400 |
| Message-ID | <5556657B.5050609@verizon.net> |
| In reply to | #62069 |
On 05/15/2015 04:56 PM, James Harris wrote: > "Stephen Sprunk" <stephen@sprunk.org> wrote in message ... > It is not interrupts which are the problem. If I understood him > correctly David mentioned that in > > function_call() > pointer_manipulations > function_call() > > the compiler could move the pointer manipulations to before the initial > function call or after the final function call. That would simply break > the code. Are you sure he said that? I don't recall seeing him raise that issue. That can happen only if there's no sequence points separating those steps. Assuming that function_call() returns 'int', and that 'p' has the type "T*", then the expression T* final = function_call() + (p++) + function_call(); does leave it unspecified whether p++ occurs before or after either of the calls. However, if you need to be sure of the order, all that's required is to explicitly specify it: int temp1 = function_call(); T* final = temp1 + p++; final += function_call(); The first approach says "I don't care what order these sub-expressions are evaluated in". That's fine - if it's the truth. However, if you do care about the order, then the second approach is one way to tell the compiler what the order should be (there's several other functionally equivalent ways of doing it). And it's only the second approach that has the sequence points that are the "Subject:" of this thread.
[toc] | [prev] | [next] | [standalone]
| From | "James Harris" <james.harris.1@gmail.com> |
|---|---|
| Date | 2015-05-16 07:51 +0100 |
| Message-ID | <mj6pca$5ab$1@dont-email.me> |
| In reply to | #62074 |
"James Kuyper" <jameskuyper@verizon.net> wrote in message
news:5556657B.5050609@verizon.net...
> On 05/15/2015 04:56 PM, James Harris wrote:
>> "Stephen Sprunk" <stephen@sprunk.org> wrote in message
> ...
>> It is not interrupts which are the problem. If I understood him
>> correctly David mentioned that in
>>
>> function_call()
>> pointer_manipulations
>> function_call()
>>
>> the compiler could move the pointer manipulations to before the
>> initial
>> function call or after the final function call. That would simply
>> break
>> the code.
>
> Are you sure he said that? I don't recall seeing him raise that issue.
No, I am not sure. The paragraph in question was
DB> The key issue is that while the irqrx_set function is presumably
DB> volatile (or uses a volatile access to the irq flag), and thus the
DB> compiler guarantees that the interrupts will be disabled and then
DB> restored, the standards say nothing about the ordering of volatile
DB> accesses with respect to non-volatile accesses. The compiler could
move
DB> the assignments to before the interrupt disable, or after the
restore,
DB> or in pretty much any other order it wants.
It is in the post dated 14 May 2015 at 21:38 GMT. The code he was
commenting on was
void dnode_delete(dnode_t *x) {
unsigned state;
/* Disable interrupts */
state = irqrx_set(IRQRX_DISABLE);
x->prev.next = x.next;
x->next.prev = x.prev;
/* Restore interrupt handling */
irqrx_set(state);
}
> That can happen only if there's no sequence points separating those
> steps.
That should be OK then. IIUC there is a sequence point before a function
call after the operands have been evaluated.
Perhaps he meant that the reads of memory could be reordered to before
the first function call and the writes could take place after the last
function call unless the variables were marked as volatile.
My point (to which David was responding) was that wrapping the above
into a function in a separate translation unit and having no
inter-translation unit optimisation should ensure that the variables
x->prev.next and x->next.prev were updated in memory and not kept in
registers before the function returned.
James
[toc] | [prev] | [next] | [standalone]
| From | James Kuyper <jameskuyper@verizon.net> |
|---|---|
| Date | 2015-05-16 22:10 -0400 |
| Message-ID | <mj8t7s$2rm$1@dont-email.me> |
| In reply to | #62098 |
On 05/16/2015 02:51 AM, James Harris wrote:
> "James Kuyper" <jameskuyper@verizon.net> wrote in message
> news:5556657B.5050609@verizon.net...
>> On 05/15/2015 04:56 PM, James Harris wrote:
>>> "Stephen Sprunk" <stephen@sprunk.org> wrote in message
>> ...
>>> It is not interrupts which are the problem. If I understood him
>>> correctly David mentioned that in
>>>
>>> function_call()
>>> pointer_manipulations
>>> function_call()
>>>
>>> the compiler could move the pointer manipulations to before the
>>> initial
>>> function call or after the final function call. That would simply
>>> break
>>> the code.
>>
>> Are you sure he said that? I don't recall seeing him raise that issue.
>
> No, I am not sure. The paragraph in question was
>
> DB> The key issue is that while the irqrx_set function is presumably
> DB> volatile (or uses a volatile access to the irq flag), and thus the
> DB> compiler guarantees that the interrupts will be disabled and then
> DB> restored, the standards say nothing about the ordering of volatile
> DB> accesses with respect to non-volatile accesses. The compiler could
> move
> DB> the assignments to before the interrupt disable, or after the
> restore,
> DB> or in pretty much any other order it wants.
>
> It is in the post dated 14 May 2015 at 21:38 GMT. The code he was
> commenting on was
>
> void dnode_delete(dnode_t *x) {
> unsigned state;
>
> /* Disable interrupts */
> state = irqrx_set(IRQRX_DISABLE);
>
> x->prev.next = x.next;
> x->next.prev = x.prev;
>
> /* Restore interrupt handling */
> irqrx_set(state);
> }
>
>> That can happen only if there's no sequence points separating those
>> steps.
>
> That should be OK then. IIUC there is a sequence point before a function
> call after the operands have been evaluated.
More importantly, there's a sequence point at the end of every
statement. That would be, in itself, sufficient to render his concerns
irrelevant.
--
James Kuyper
[toc] | [prev] | [next] | [standalone]
| From | David Brown <david.brown@hesbynett.no> |
|---|---|
| Date | 2015-05-19 00:25 +0200 |
| Message-ID | <mjdoqe$gdj$1@dont-email.me> |
| In reply to | #62138 |
(Sorry for the delay in replying to the posts in this thread - I have
been mostly out of touch for the past few days.)
On 17/05/15 04:10, James Kuyper wrote:
> On 05/16/2015 02:51 AM, James Harris wrote:
>> "James Kuyper" <jameskuyper@verizon.net> wrote in message
>> news:5556657B.5050609@verizon.net...
>>> On 05/15/2015 04:56 PM, James Harris wrote:
>>>> "Stephen Sprunk" <stephen@sprunk.org> wrote in message
>>> ...
>>>> It is not interrupts which are the problem. If I understood him
>>>> correctly David mentioned that in
>>>>
>>>> function_call()
>>>> pointer_manipulations
>>>> function_call()
>>>>
>>>> the compiler could move the pointer manipulations to before the
>>>> initial
>>>> function call or after the final function call. That would simply
>>>> break
>>>> the code.
>>>
>>> Are you sure he said that? I don't recall seeing him raise that issue.
>>
It /is/ roughly what I said.
>> No, I am not sure. The paragraph in question was
>>
>> DB> The key issue is that while the irqrx_set function is presumably
>> DB> volatile (or uses a volatile access to the irq flag), and thus the
>> DB> compiler guarantees that the interrupts will be disabled and then
>> DB> restored, the standards say nothing about the ordering of volatile
>> DB> accesses with respect to non-volatile accesses. The compiler could
>> move
>> DB> the assignments to before the interrupt disable, or after the
>> restore,
>> DB> or in pretty much any other order it wants.
>>
>> It is in the post dated 14 May 2015 at 21:38 GMT. The code he was
>> commenting on was
>>
>> void dnode_delete(dnode_t *x) {
>> unsigned state;
>>
>> /* Disable interrupts */
>> state = irqrx_set(IRQRX_DISABLE);
>>
>> x->prev.next = x.next;
>> x->next.prev = x.prev;
>>
>> /* Restore interrupt handling */
>> irqrx_set(state);
>> }
>>
>>> That can happen only if there's no sequence points separating those
>>> steps.
>>
>> That should be OK then. IIUC there is a sequence point before a function
>> call after the operands have been evaluated.
>
> More importantly, there's a sequence point at the end of every
> statement. That would be, in itself, sufficient to render his concerns
> irrelevant.
>
You are missing the "as-if" rule. Yes, there are sequence points at the
end of every statement. But the compiler only has to honour them to the
extent that the externally visible effects of the code are "as if" it
had honoured them slavishly.
If the compiler knows that the irqrx_set function cannot affect, or be
affected by, x, x->prev, x->next, etc., and these are not volatile (and
therefore externally visible), then the compiler can re-order the
statements pretty much as it likes.
Of course, this only applies if the compiler /has/ such knowledge.
[toc] | [prev] | [next] | [standalone]
| From | James Kuyper <jameskuyper@verizon.net> |
|---|---|
| Date | 2015-05-18 18:55 -0400 |
| Message-ID | <555A6DE5.2010303@verizon.net> |
| In reply to | #62254 |
On 05/18/2015 06:25 PM, David Brown wrote: ... > You are missing the "as-if" rule. Yes, there are sequence points at the > end of every statement. But the compiler only has to honour them to the > extent that the externally visible effects of the code are "as if" it > had honoured them slavishly. So, why do you care? If you can write strictly conforming code whose behavior would otherwise depend upon whether or not the compiler performed a given optimization, then the as-if rule can not be used to justify the optimization.
[toc] | [prev] | [next] | [standalone]
| From | David Brown <david.brown@hesbynett.no> |
|---|---|
| Date | 2015-05-19 09:10 +0200 |
| Message-ID | <mjenju$353$1@dont-email.me> |
| In reply to | #62260 |
On 19/05/15 00:55, James Kuyper wrote: > On 05/18/2015 06:25 PM, David Brown wrote: > ... >> You are missing the "as-if" rule. Yes, there are sequence points at the >> end of every statement. But the compiler only has to honour them to the >> extent that the externally visible effects of the code are "as if" it >> had honoured them slavishly. > > So, why do you care? If you can write strictly conforming code whose > behavior would otherwise depend upon whether or not the compiler > performed a given optimization, then the as-if rule can not be used to > justify the optimization. > The problem is that James had written code where the correctness of the algorithm (i.e., the programmer's idea of correctness and order) depends on an ordering that is not guaranteed by the rules of C. Your comment about sequence points makes it look like sequence points fully determine ordering of statements in C, and that is simply wrong - they determine only the "as-if" ordering of the virtual machine, not the real-world ordering as run by the processor. And James' code requires certain ordering on the processor. To specify that, he needs something stronger than sequence points - and in C, that "something" is "volatile".
[toc] | [prev] | [next] | [standalone]
| From | James Kuyper <jameskuyper@verizon.net> |
|---|---|
| Date | 2015-05-19 12:05 -0400 |
| Message-ID | <555B5F39.1050807@verizon.net> |
| In reply to | #62276 |
On 05/19/2015 03:10 AM, David Brown wrote: > On 19/05/15 00:55, James Kuyper wrote: >> On 05/18/2015 06:25 PM, David Brown wrote: >> ... >>> You are missing the "as-if" rule. Yes, there are sequence points at the >>> end of every statement. But the compiler only has to honour them to the >>> extent that the externally visible effects of the code are "as if" it >>> had honoured them slavishly. >> >> So, why do you care? If you can write strictly conforming code whose >> behavior would otherwise depend upon whether or not the compiler >> performed a given optimization, then the as-if rule can not be used to >> justify the optimization. >> > > The problem is that James had written code where the correctness of the > algorithm (i.e., the programmer's idea of correctness and order) depends > on an ordering that is not guaranteed by the rules of C. Your comment > about sequence points makes it look like sequence points fully determine > ordering of statements in C, and that is simply wrong - they determine > only the "as-if" ordering of the virtual machine, not the real-world > ordering as run by the processor. And James' code requires certain > ordering on the processor. To specify that, he needs something stronger > than sequence points - and in C, that "something" is "volatile". Sequence points don't fully determine the ordering of statements in C, I never suggested otherwise. They don't even fully determine the "as-if" ordering, as you call it: in a()+b(), the two function calls can be evaluated in either order - a conforming implementation must produce results "as-if" one of those two orders were followed, but it's free to choose either one. Also, the standard has always allowed for signal handlers, and C2011 adds support for multi-threaded code, so a fully conforming implementation of C can choose from a large number of different "as-if" orders. However, the subject of this thread has, from the beginning, been the guarantees provided by the standard about two expressions separated by a sequence point where the standard does guarantee the order of the two sub-expressions. Using the new terms introduced in C2011, that means that one expression is "sequenced after" (5.1.2.3p3) the other. Now, you're right that it's only the as-if ordering that is guaranteed by the standard. But, when one expression is, per the standard, "sequenced after" another expression, the as-if ordering should be all that matters, as far as strictly-conforming code is concerned, because the "as-if" ordering is effectively the only ordering that can be seen by such code, even if the actual ordering is quite different. If you insert debugging fprintf()s in various locations in the code, and send them to an unbuffered stream, the data received by that stream must match the "as-if" order, even if the actual order in which the relevant expressions were executed is quite different.
[toc] | [prev] | [next] | [standalone]
| From | David Brown <david.brown@hesbynett.no> |
|---|---|
| Date | 2015-05-19 18:42 +0200 |
| Message-ID | <mjfp31$vgu$1@dont-email.me> |
| In reply to | #62294 |
On 19/05/15 18:05, James Kuyper wrote: > On 05/19/2015 03:10 AM, David Brown wrote: >> On 19/05/15 00:55, James Kuyper wrote: >>> On 05/18/2015 06:25 PM, David Brown wrote: >>> ... >>>> You are missing the "as-if" rule. Yes, there are sequence points at the >>>> end of every statement. But the compiler only has to honour them to the >>>> extent that the externally visible effects of the code are "as if" it >>>> had honoured them slavishly. >>> >>> So, why do you care? If you can write strictly conforming code whose >>> behavior would otherwise depend upon whether or not the compiler >>> performed a given optimization, then the as-if rule can not be used to >>> justify the optimization. >>> >> >> The problem is that James had written code where the correctness of the >> algorithm (i.e., the programmer's idea of correctness and order) depends >> on an ordering that is not guaranteed by the rules of C. Your comment >> about sequence points makes it look like sequence points fully determine >> ordering of statements in C, and that is simply wrong - they determine >> only the "as-if" ordering of the virtual machine, not the real-world >> ordering as run by the processor. And James' code requires certain >> ordering on the processor. To specify that, he needs something stronger >> than sequence points - and in C, that "something" is "volatile". > > Sequence points don't fully determine the ordering of statements in C, I > never suggested otherwise. They don't even fully determine the "as-if" > ordering, as you call it: in a()+b(), the two function calls can be > evaluated in either order - a conforming implementation must produce > results "as-if" one of those two orders were followed, but it's free to > choose either one. Also, the standard has always allowed for signal > handlers, and C2011 adds support for multi-threaded code, so a fully > conforming implementation of C can choose from a large number of > different "as-if" orders. > > However, the subject of this thread has, from the beginning, been the > guarantees provided by the standard about two expressions separated by a > sequence point where the standard does guarantee the order of the two > sub-expressions. Using the new terms introduced in C2011, that means > that one expression is "sequenced after" (5.1.2.3p3) the other. > > Now, you're right that it's only the as-if ordering that is guaranteed > by the standard. But, when one expression is, per the standard, > "sequenced after" another expression, the as-if ordering should be all > that matters, as far as strictly-conforming code is concerned, because > the "as-if" ordering is effectively the only ordering that can be seen > by such code, even if the actual ordering is quite different. If you > insert debugging fprintf()s in various locations in the code, and send > them to an unbuffered stream, the data received by that stream must > match the "as-if" order, even if the actual order in which the relevant > expressions were executed is quite different. > What you write here is entirely correct - but it is mostly beside the point. The thread has not been about the "as-if" ordering given by sequence points, but the /real/ ordering as seen by interrupt functions. In James' original point, he was wondering if sequence points give guarantees about when an assignment actually causes a value to be written to memory (since his interrupt routine will see the value in memory, but not a value waiting in a register). Sequence points are close to irrelevant here - they only matter in how they give an order to volatile accesses and other /visible/ effects (such as your fprintf's).
[toc] | [prev] | [next] | [standalone]
| From | Stephen Sprunk <stephen@sprunk.org> |
|---|---|
| Date | 2015-05-16 16:33 -0500 |
| Message-ID | <mj8d1g$qev$1@dont-email.me> |
| In reply to | #62069 |
On 15-May-15 15:56, James Harris wrote: > "Stephen Sprunk" <stephen@sprunk.org> wrote: >> "Interrupts" are outside the scope of the C Standard, so any use of >> them will put you outside the realm of defined behavior. > > It is not interrupts which are the problem. If I understood him > correctly David mentioned that in > > function_call() > pointer_manipulations > function_call() > > the compiler could move the pointer manipulations to before the > initial function call or after the final function call. That would > simply break the code. Only if function_call() accessed that pointer, of course, and the compiler _may_ be able to determine that it doesn't, depending on the specific code at hand. However, an interrupt routine may invalidate that determination. S -- Stephen Sprunk "God does not play dice." --Albert Einstein CCIE #3723 "God is an inveterate gambler, and He throws the K5SSS dice at every possible opportunity." --Stephen Hawking
[toc] | [prev] | [next] | [standalone]
| From | David Brown <david.brown@hesbynett.no> |
|---|---|
| Date | 2015-05-19 00:27 +0200 |
| Message-ID | <mjdouv$gdj$2@dont-email.me> |
| In reply to | #62128 |
On 16/05/15 23:33, Stephen Sprunk wrote: > On 15-May-15 15:56, James Harris wrote: >> "Stephen Sprunk" <stephen@sprunk.org> wrote: >>> "Interrupts" are outside the scope of the C Standard, so any use of >>> them will put you outside the realm of defined behavior. >> >> It is not interrupts which are the problem. If I understood him >> correctly David mentioned that in >> >> function_call() >> pointer_manipulations >> function_call() >> >> the compiler could move the pointer manipulations to before the >> initial function call or after the final function call. That would >> simply break the code. > > Only if function_call() accessed that pointer, of course, and the > compiler _may_ be able to determine that it doesn't, depending on the > specific code at hand. However, an interrupt routine may invalidate > that determination. > The compiler doesn't know about interrupts - only the programmer knows about them. So if the compiler can determine that function_call() is independent of pointer_manipulations, but the programmer knows that interrupt routines may introduce a dependency, then it is the programmer's responsibility to tell this to the compiler by forcing a dependency in some way. Valid methods include memory barriers and the use of "volatile".
[toc] | [prev] | [next] | [standalone]
| From | James Kuyper <jameskuyper@verizon.net> |
|---|---|
| Date | 2015-05-18 19:05 -0400 |
| Message-ID | <555A7049.6010405@verizon.net> |
| In reply to | #62255 |
On 05/18/2015 06:27 PM, David Brown wrote: ... > The compiler doesn't know about interrupts - only the programmer knows > about them. So if the compiler can determine that function_call() is > independent of pointer_manipulations, but the programmer knows that > interrupt routines may introduce a dependency, then it is the > programmer's responsibility to tell this to the compiler by forcing a > dependency in some way. Valid methods include memory barriers and the > use of "volatile". On a platform which supports interrupts, a conforming implementation of C must generate code that will still produce the behavior defined by the standard for the source code. If that means spilling registers to memory whenever a sequence point is crossed, even though an interrupt is the only possible reason why such spilling is needed - then those registers must be spilled - because the platform does permit such interruptions.
[toc] | [prev] | [next] | [standalone]
| From | glen herrmannsfeldt <gah@ugcs.caltech.edu> |
|---|---|
| Date | 2015-05-19 00:09 +0000 |
| Message-ID | <mjdv04$3k5$1@speranza.aioe.org> |
| In reply to | #62264 |
James Kuyper <jameskuyper@verizon.net> wrote: (snip) > On a platform which supports interrupts, a conforming implementation of > C must generate code that will still produce the behavior defined by the > standard for the source code. If that means spilling registers to memory > whenever a sequence point is crossed, even though an interrupt is the > only possible reason why such spilling is needed - then those registers > must be spilled - because the platform does permit such interruptions. How about on CPUs that support imprecise interrupts? -- glen
[toc] | [prev] | [next] | [standalone]
| From | Richard Heathfield <rjh@cpax.org.uk> |
|---|---|
| Date | 2015-05-19 01:11 +0100 |
| Message-ID | <mjdv21$2qu$2@dont-email.me> |
| In reply to | #62267 |
On 19/05/15 01:09, glen herrmannsfeldt wrote: > How about on CPUs that support imprecise interrupts? Excuse me, glen, but... um... never mind. Oh, actually... Er, no. Sorry. -- Richard Heathfield Email: rjh at cpax dot org dot uk "Usenet is a strange place" - dmr 29 July 1999 Sig line 4 vacant - apply within
[toc] | [prev] | [next] | [standalone]
| From | Tim Rentsch <txr@alumni.caltech.edu> |
|---|---|
| Date | 2015-05-23 07:02 -0700 |
| Message-ID | <kfnfv6n8k9y.fsf@x-alumni2.alumni.caltech.edu> |
| In reply to | #62268 |
Richard Heathfield <rjh@cpax.org.uk> writes: > On 19/05/15 01:09, glen herrmannsfeldt wrote: > >> How about on CPUs that support imprecise interrupts? > > Excuse me, glen, but... um... never mind. > > Oh, actually... > > Er, no. Sorry. Precisely.
[toc] | [prev] | [next] | [standalone]
| From | James Kuyper <jameskuyper@verizon.net> |
|---|---|
| Date | 2015-05-18 23:21 -0400 |
| Message-ID | <mjea5a$v64$1@dont-email.me> |
| In reply to | #62267 |
On 05/18/2015 08:09 PM, glen herrmannsfeldt wrote: > James Kuyper <jameskuyper@verizon.net> wrote: > > (snip) >> On a platform which supports interrupts, a conforming implementation of >> C must generate code that will still produce the behavior defined by the >> standard for the source code. If that means spilling registers to memory >> whenever a sequence point is crossed, even though an interrupt is the >> only possible reason why such spilling is needed - then those registers >> must be spilled - because the platform does permit such interruptions. > > How about on CPUs that support imprecise interrupts? I'm unfamiliar with that term. Is there any conceivable method to generate code that has the behavior defined by the standard, even if execution of that code is interrupted by imprecise interrupts? If so, whatever approach needs to be taken to achieve that result is mandatory for conforming implementations of C on those platforms. If not, conforming implementations of C are not possible on those platforms. -- James Kuyper
[toc] | [prev] | [next] | [standalone]
| From | glen herrmannsfeldt <gah@ugcs.caltech.edu> |
|---|---|
| Date | 2015-05-19 06:25 +0000 |
| Message-ID | <mjel16$ats$1@speranza.aioe.org> |
| In reply to | #62269 |
James Kuyper <jameskuyper@verizon.net> wrote: (snip) >>> On a platform which supports interrupts, a conforming implementation of >>> C must generate code that will still produce the behavior defined by the >>> standard for the source code. (snip, then I wrote) >> How about on CPUs that support imprecise interrupts? > I'm unfamiliar with that term. Is there any conceivable method to > generate code that has the behavior defined by the standard, even if > execution of that code is interrupted by imprecise interrupts? Imprecise interrupts occur on processors with out-of-order execution and, further, out-of-order retirement. (Many processors now have out-of-order execution, but manage to arrange things such that the effects happen in order.) > If so, > whatever approach needs to be taken to achieve that result is mandatory > for conforming implementations of C on those platforms. If not, > conforming implementations of C are not possible on those platforms. I suspect that the causes of imprecise interrupts already cause UB, such that it doesn't matter. They do make debugging harder, though. Some causes of imprecise interrupts are overflow, underflow, divide by zero, protection (accessing memory that doesn't belong to you), unaligned memory access. When one of those occurs, the CPU has to finish instructions that have already started, possibly generaring more interrupts. But debuggers might not be able to report the cause of a protection or alignment violation. Mostly, imprecise interrupts went away when vitual storage arrived. If you can't identify the instruction causing a page fault, it isn't possible to do the page-in and restart. Instructions can't change any permanent state until it is known that no page fault will occur. -- glen
[toc] | [prev] | [next] | [standalone]
Page 3 of 6 — ← Prev page 1 2 [3] 4 5 6 Next page →
Back to top | Article view | comp.lang.c
csiph-web