Ok so I tried
This is absolutely the first draft of a draft, or what i like to call
the braindump edition. Formatting is horrible and wording could
probably also be improved.
Please let me know what you think and where it could be improved,
especially if there are things I have omitted.
Besides a paper number, it also needs your email address for people to send feedback.
The "Introduction" should be massively tersened:
C++20 deprecated many functionalities of `volatile`, due to JF Bastien's P1152R4 [Bastien, 2019]. The rationale was to prevent programmers misunderstanding the meaning of `volatile` in threading code [Bastien, 2018]. While this rationale is sound, the deprecation of the compound assignment operators for `volatile` caused some response from the embedded community [Ooijen, 2020]. We propose to restore the compound assignment operators.
(Even simple refactorings like replacing "It is the hope of the author that" with "It is the author's hope that" with "It is my hope that" with "I hope that" can lighten the load. But in this case, I don't even think it makes sense to say "I hope we can reach a compromise position" — compromise for the sake of compromise is never the goal! The goal is to get into whatever state satisfies your technical needs.)
---
> This is further amplified by the fact that vendors may supply macros for setting or clearing bits...
If vendors actually do use `|=` and `&=` for setting and clearing bits, then just say
> Vendors provide macros that use `|=` and `&=` on volatile objects. For example:
> - RabbitFrog RTOS has a macro `FOO_SET_FLAG(y) (mm_flags[y >> 4]) |= (1<<(y & 0xF))`
> - FrogRabbit RTOS has a macro `BAR_SET_MEM(x, y) *(volatile int*)y &= x`
You definitely need examples, because the null hypothesis here is that people don't do this.
---
> The argument against compound operations on volatile variables is that it leads
the programmer to believe that the operation itself becomes compounded and
therefore atomic. This is of course false (even though architectures where this
is the case could be imagined).
FWIW, my understanding is that the operation itself is frequently atomic, or at least divvied up differently from the non-volatile version.
For example, on x86-64 Clang:
Non-volatile &= produces a load, modify-in-register, and store.
Volatile &= produces a modify-in-memory, followed by a load (if the final value is needed by the expression).
Vice-versa, sometimes the compiler enforces that volatile reads/writes are always done at the size of the data type (e.g. it is forbidden to access the low-order byte of a `volatile int` via a byte-sized load instruction), which can lead to more codegen than the non-volatile version.
> Now since there must always be a read, modify, write cycle it is possible
that an interrupt would happen in between the read and the write, however
most code that uses this idiom needs to take care of this by being right by
construction i.e. not bit-twiddeling variables that are used in the interrupt
service routines (ISRs). While there is probably some code found in the wild
where this would indicate a problem, since this is so common in all these
cases the construct would only be replaced by the equivalent non-compound
statement, giving no benefit at all.
Your use of the passive voice in the last sentence hurts you. "Would only be replaced" by whom?— the compiler, or the human programmer? If the human programmer is supposed to replace `x &= y` with `x = x & y` in order to avoid ISR/multithreading bugs, then good, that's exactly what C++20 wants them to do. IOW, I don't understand the thrust of this paragraph.
----
> Table 1: Occurrences of compound operations on variables typically associated
with volatile
The caption of this table doesn't match the description in the English text. These aren't occurrences of compound assignments on typically volatile variables — they're literally just all the compound assignments in the entire program! Most of these assignments probably don't involve volatile variables at all.
> but the usage of this idiom also prevents
adopters of C++ to use the C libraries provided with their toolchains
I would like to see evidence of this. For example, you could provide a short "hello world"-style program (using some C library provided with your toolchain) and point to the line that would be deprecated in C++20.
----
> The simplest possible change that could possibly work would be to remove
the text added to paragraph [expr.ass] point 6 as this would allow compound
statements on volatile varaiables.
Nit: "varaiables".
IIUC, it's this:
A simple An assignment whose left operand is of a volatile-qualified type is deprecated ([depr.volatile.type]) unless the (possibly parenthesized) assignment is a discarded-value expression or an unevaluated operand.The behavior of an expression of the form
E1 op= E2 is equivalent to
E1 = E1 op E2 except that
E1 is evaluated only once
. For
+= and
-=,
E1 shall either have arithmetic type or be a pointer to a possibly cv-qualified completely-defined object type
. In all other cases,
E1 shall have arithmetic type
.
----
Personally, I'd like to see a separate section of the paper devoted to explaining
- What do we think the semantics of `x &= y` are, when `x` is volatile? Is it a load-modify-store? Is it an atomic modify-in-place? Is it allowed to be an atomic modify-in-place? Is it allowed to use special crazy flag-setting instructions? Basically what are programmers hoping to get when they write that line of code, and, what are they thinking they mustn't get?
- If the answer to the first question is "We don't know, it's implementation-defined or worse, but as embedded programmers we just need the syntax to keep compiling so that our code doesn't break," then that's an honest answer (I guess) but it needs to be really clearly stated in this separate section.
My goal with the separate section would be to try not to devolve the discussion into a flamewar about the (lack of) meaning of `volatile` in general, but to clearly indicate to the reader that you've thought about its (lack of) meaning.
----
Oh, and finally, consider the following workaround:
*(int*)myvolatilevar &= 255;
Compound assignments on non-volatile variables aren't deprecated; so if you really need the compound stuff more than any particular semantics provided by the volatile stuff, could you just add the cast?
–Arthur