On 15/02/21 23:22 +0000, Neven Sajko wrote:
There is a long-standing, but undocumented GCC inline assembly feature
that's part of the extended asm GCC extension to C and C++: extended
asm empty input constraints.

Although I don't really use extended asm much, and I never contributed
to GCC before; I tried to document the feature as far as I understand
it. I ran make html to check that the changed Texinfo is well formed.

FTR, empty input constraints have been mentioned on the GCC mailing
lists, e.g.:
https://gcc.gnu.org/pipermail/gcc-help/2015-June/124410.html

I release this contribution into the public domain.

Neven Sajko

gcc/ChangeLog:

       * doc/md.texi: Document extended asm empty input constraints

diff --git a/gcc/doc/md.texi b/gcc/doc/md.texi
index e3686dbfe..deccfd38a 100644
--- a/gcc/doc/md.texi
+++ b/gcc/doc/md.texi
@@ -1131,7 +1131,102 @@ the addressing register.
@subsection Simple Constraints
@cindex simple constraints

-The simplest kind of constraint is a string full of letters, each of
+An input constraint is allowed to be an empty string, in which case it is
+called an empty input constraint. (When an empty input constraint is used,
+the assembler template will most probably also be empty. I.e., the @code{asm}
+declaration need not contain actual assembly code.) An empty input

This parenthesis seems to be important to the next sentence, so should
it really be in parentheses?

Also, it's an asm statement, not asm declaration, isn't it?

And we don't seem to document that an empty assembler tempalte is
allowed, except in passing here.

+constraint can be used to create an artificial dependency on a C or C++

Is it redundant to say "C or C++ variable"? What other kind of
variable could it be talking about?

+variable (the variable that appears in the expression associated with the
+constraint) without incurring unnecessary costs to performance.

I think this whole paragraph (in fact all the new text) is quite
verbose and could be much more succint.

+An input constraint is allowed to be an empty string, in which case it is
+called an empty input constraint. (When an empty input constraint is used,
+the assembler template will most probably also be empty. I.e., the @code{asm}
+declaration need not contain actual assembly code.) An empty input
+constraint can be used to create an artificial dependency on a C or C++
+variable (the variable that appears in the expression associated with the
+constraint) without incurring unnecessary costs to performance.

Also, does the discussion of empty input constraints really belong
first? Isn't it a special case, and so should be documented after the
more common case? And do we really want to spend as long talking about
this special case as we do about all the other types of input
constraint combined?

+An example of where such behavior may be useful is for preventing compiler

"This can be useful to prevent compiler optimizations like dead store
elimination and hoisting code outside loops. Specific applications may
include ..."

+optimizations like dead store elimination or hoisting code outside a loop for
+certain pieces of C or C++ code. Specific applications may include direct
+interaction with hardware features; or things like testing, fuzzing and
+benchmarking.
+
+Here's a simple C++20 program that is not useful in practice but demonstrates
+relevant behavior; store it as a file called asm.cc:
+
+@verbatim
+#include <vector>
+
+int
+main() {
+    // Greater than or equal to zero.
+    constexpr int asmV = ASM_V;
+
+    // The exact content of v is irrelevant for
+    // this example.
+    std::vector<char> v{7, 6, 9, 3, 2, 0};

This is ill-formed because int -> char is a narrowing conversion.
Please use valid C++ for the example.


+
+    for (int i{0}; i < (1 << 28); i++) {
+        for (int j{0}; j < 6; j++) {

I don't think the brace initialization helps the example. Consider
that many readers of the GCC manual are C programmers. Why use a
feature specific to C++ when you could just say "int i = 0;" so
everybody understands it?

+            // The exact operation on the contents
+            // of v is not relevant for this
+            // example.
+            v[j]++;
+
+            if constexpr (1 <= asmV) {

I don't think the Yoda Conditions help the example.

+                asm volatile ("" :: ""(v.size()));
+                for (auto x: v) {
+                    asm volatile ("" :: ""(x));
+                }
+            }
+            if constexpr (2 <= asmV) {
+                asm volatile ("" :: ""(v.size()));
+                for (auto x: v) {
+                    asm volatile ("" :: ""(x));
+                }
+            }
+            if constexpr (3 <= asmV) {
+                asm volatile ("" :: ""(v.size()));
+                for (auto x: v) {
+                    asm volatile ("" :: ""(x));
+                }
+            }
+        }
+    }
+
+    return 0;

A return statement is not needed for main, so removing it keeps the
example shorter.

+}
+@end verbatim
+
+Compile with, e.g., the following command (with @code{XXX} equal to @code{0},
+@code{1}, @code{2}, and @code{3}).

XXX seems a bit ugly or scary, could you just use N as the
placeholder?

+@verbatim
+g++ -std=c++20 -O3 -flto -march=native -D ASM_V=XXX -o XXX asm.cc
+@end verbatim
+
+Firstly, for @code{XXX} equal to @code{0}; all of the @code{asm} declarations
+are dead code, thus formally the contents of @var{v} are not observable,
+thus the program consists almost entirely of code that may be eliminated by a
+(valid) compiler. While this usually aligns with what the programming user
+wants, sometimes we might want to, e.g., measure how long does it take for
+some piece of code to execute, even if we aren't interested in its results
+(or already know what its results must be). Such is the case in, e.g.,
+benchmarking.

This seems like a very long-winded way to explain what the
if-constexpr does, which seems unnecessary in this example. Why is it
here?

+Secondly, for @code{XXX} equal to @code{1}; only the first part with
+@code{asm} declarations (the body of the first @code{if} statement) is
+effective, and because of it the preceding code can not be eliminated,
+because the @code{asm} declarations depend on @var{v} and its contents as
+input operands. The same effect would exist with a nonempty input constraint
+in place of the empty input constraints, but probably with additional
+unnecessary code generation and diminished performance. The innermost loop
+should not cause any code to be generated, because the input constraint is
+empty.
+
+Thirdly, for @code{XXX} equal to @code{2} or @code{3}; assuming the

Why do you need the 3 <= asmV case at all? If the 2 case can be
optimized away, then obviously repeating exactly the same code can be
too.

required compiler
+optimizations are successful, the generated code should be the same as for
+@code{XXX} equal to @code{1}. This is again because of the empty
input constraint
+preventing unnecessary code generation (a nonempty input constraint would
+probably require that the compiler store values into either registers or
+memory, even though the assembler template is empty).

I don't think this needs to be explained here at all really. The
manual doesn't need to be a tutorial showing all this.

+The simplest kind of constraint, apart from the empty constraint,

How about "The simplest kind of non-empty constraint ..."

+is a string full of letters, each of
which describes one kind of operand that is permitted.  Here are
the letters that are allowed:

Maybe the whole thing could be just a couple of new paragraphs at the
end of the "Input Constraints" section, something like:

Using an empty string as an input constraint creates an artificial
dependency on the input operand, forcing it to be evaluated. An empty
input constraint is typically used with an empty assembler template, i.e. an
@code{asm} statement that contains no actual assembly code.

This can be useful to prevent compiler optimizations such as dead store
elimination and loop hoisting where those optimizations are unwanted.
For example, when accessing hardware directly or measuring performance
for testing or benchmarking purposes.

The simplest kind of non-empty constraint ...


Reply via email to