Hello Paul, On Mon, 20 Jan 2025 15:35:38 -0800, Paul Eggert wrote:
> On 2025-01-20 02:55, Jₑₙₛ Gustedt wrote: > > I have difficulties of understanding the usefullness of such an > > interface > > You're better off than I, as I'm still having difficulties knowing > even what unsequenced and reproducible mean, much less what they're > useful for. I am sorry to hear that. I hope you agree that the C23 and gcc attributes coincide if no pointers are involved. > For example, I don't understand why the 'abs' and > 'strcmp' functions are not declared to be [[unsequenced]], as they > seem to satisfy the intended criteria for unsequenced functions. Who said they wouldn't? WG14 didn't wanted to annotate any of the exisiting interfaces in the C library for C23, that's all. There is still some work there, and a proposal in that direction that does an extensive case analysis of C library interfaces would certainly be welcome. (And we did annotate some of the new functions that had not been in previous versions of the standard.) For the two functions this would possibly be something to consider but: - for `strcmp` the return value is only guaranteed to be the same sign and not the same value. If we'd put this attribute there, we would constrain implementations to always return the same `int` value for the same input. Probably this is not a big deal, but still a decision to make. - for `abs`, it has one input value for which the behavior is undefined. Again there would be a decision to take if we would like to put the attribute on such functions. On the other hand, in many cases it would be appropriate that C library implementations put these attributes on standard functions. In general, they have more information than WG14 and could easily make the necessary guarantees, for example for `strcmp`, of for `<math.h>` functions where they know that rounding mode doesn't matter for their implementation. > >> By "extension", I assume you mean that [[unsequenced]] is intended > >> to be looser than __attribute__((const)). That is, every const > >> function is unsequenced, but the reverse is not true. This is what > >> Bruno said in the above quote. > > > > Yes that's my idea. > > Then I'm more confused than ever, unfortunately. > > Here's another illustration of my confusion. 6.7.13.8.3 EXAMPLE 2 > says that given this definition: > > typedef struct toto toto; > toto const *toto_zero(void) [[unsequenced]]; > > "a single call can be executed during thread startup and the return > value p and the value of the object *p of type toto const can be > cached." This means a compiler can optimize code like this: > > toto const x = *toto_zero(); > change_state(); > toto y = *toto_zero(); > > as if it were this: > > toto const x = *toto_zero(); > change_state(); > toto y = x; > > That is, EXAMPLE 2 means an unsequenced function not only can examine > storage addressed by pointers passed to it: it also guarantees that > when it returns a pointer, storage addressed by that returned pointer > always has contents derivable from the function's arguments > (including the storage addressed by those arguments). In particular > tot_zero's [[unsequenced]] guarantees that change_state does not > modify the storage addressed by the pointer returned by toto_zero. > > But this means that, contrary to stated intent, > __attribute__((const)) does not imply [[unsequenced]]. For example: > > toto x; > toto const *toto1(void) { return &x; } > void change_state() { memset(x, 1, sizeof x); } > > toto1 is a const function, but it's not unsequenced because toto1 > returns a pointer to storage that change_state modifies. > > In other words, [[unsequenced]] allows some compiler optimizations > that __attribute__((const)) does not - contrary to stated intent. Ok, yes, that is a difference then that we should note. It would really have been helpful if we had known about that behavior of the gcc attributes when we tried to match this with standardeeze. > >> I don't understand why > >> the output of 'assert' doesn't count as a side effect, > > > > because the properties and applied optimizations at the call-site > > should not change if somebody includes `<assert.h>` with a different > > value for `NDEBUG` at a completely unrelated point in the code > > I don't see why not. Suppose the program looks like this > > [[unsequenced]] int foo(int); > int main(int argc, char **argv) > { > return argc == 1 ? 0 : foo (argc); > } > > #undef NDEBUG > #include <assert.h> > int foo(int n) > { > assert (n != 1); > return n; > } > > (foo could be defined in a separate compilation unit; that doesn't > change the analysis.) > > If a compiler were allowed to move the call foo(argc) to the start of > main (and why not? the function is unsequenced...), that would change > the meaning of the program. yes, but that is the responsibility of the person annotating the prototype in the interface. If this unsetting of `NDEBUG` is there to stay and not temporary just for debugging purposes, that annotation is a false promisse. But I note your veto for `assert`, this is valuable input for WG14 to consider. Nothing in this paper is written in stone this is just a first base for a discussion. We could e.g change this to something allows the attribute if there is `assert` *and* `NDEBUG` is set. On the other hand triggering an `assert` calls `abort` at the end. So for me this definitively is exceptional control flow that optimizers shouldn't need to consider. The given list in n3224 is an attempt to capture those library features that are considered exceptional control flow for which optimizers do not have to make provisions. > infloops are forbidden in const functions to allow those sorts of > optimizations. If infloops are also forbidden in unsequenced > functions, but 'assert's are allowed, a caller still can't do those > optimizations. Remember that all this is a promise in the interface. So if the interface says that, yes, the compiler can do the optimizations. If the function doesn't fulfill the requirements all bad is on the one who annotated the function. > This is another reason why it's important to state clearly the > *motivation* for [[unsequenced]] and and [[reproducible]]. The > standard doesn't do that, wow, you are quite categorical here, this is difficult to work with. Could you perhaps be a bit more constructive and indicate what we could add to 6.7.13.8.1 p3 or to the individual clauses of the two attributes? > and the proposed change doesn't help. > Without a clearer explanation of why these attributes are present I > fear we'll continue to have misunderstandings and glitches. That's what we are trying to do here, no? > >> Let's not underestimate the difficulty of making these concepts > >> clear. > > > > Oh, no, indeed, I don't think they are. The text that now is in C23 > > is probably one of the most delicate texts I ever wrote in my whole > > career. > > Oh, this means you weren't around when the sequence-point language > got added to the C standard in the 1980s. no, and I don't know why we would be discussing acient history here. > My comments this week are in the hope that things have gotten better > in the standardization process. I wouldn't know about that obviously, but I appreciate that you give us the benefit of the doubt ;-) All I can tell you that our attempt to standardize a scarcely documented but commonly used gcc feature seems to have failed, partially. That's a pity. Now n3424 is an attempt to make things better, I am all ear. Jₑₙₛ -- :: ICube :::::::::::::::::::::::::::::: deputy director :: :: Université de Strasbourg :::::::::::::::::::::: ICPS :: :: INRIA antenne de Strasbourg :::::::::::::::::: Camus :: :: INRIA PIQ program Strasbourg :::::::::: piq.inria.fr :: :: :::::::::::::::::::::::::::::::::::: ☎ +33 368854536 :: :: https://icube-icps.unistra.fr/index.php/Jens_Gustedt ::