This patch series provides "#pragma unroll N" and "#pragma unroll"
(without the "GCC" qualifier)
as aliases for the existing "#pragma GCC unroll N",
easing code portability with Clang, NVCC, and IBM XL C/C++:

* "#pragma unroll N" -> "#pragma GCC unroll N"
* "#pragma unroll" -> "#pragma GCC unroll <USHRT_MAX - 1>"

The no-argument form completely unrolls the loop to match Clang and NVCC,
which is a compatibility choice instead of a proposal for
how a GCC-native no-argument unroll should behave.

In particular, this series does not change "#pragma GCC unroll N",
and the no-argument form "#pragma GCC unroll" is deliberately left out,
reserving room for future work with different semantics.

All compilers listed above support "#pragma unroll N"
with the N being the unroll factor
applying to loops with compile-time constant trip counts, [1][3][4]
only with slightly different limitations:
* The upper limit of GCC is (USHRT_MAX - 1).
  This is decided in the implementation prior to these changes.
* Clang skips all limitation regarding size or trip counts. [2]
  The only limitation left is asserting
  (AllowRemainder || trip_count % N == 0) [2]
* The upper limit of NVCC is (INT_MAX). [3]
* The upper limit of IBM XL C/C++ is not documented publicly.

They also support "#pragma unroll", [1][3][4]
but with some notable behavioural differences:
* GCC, if this patch is applied,
  will only unroll loops completely if (trip_count <= USHRT_MAX - 1),
  and will otherwise decide on the unroll factor heuristically.
* Clang has upper limits guarding [2]
  * unrolled body size (PragmaUnrollThreshold)
  * trip counts (PragmaUnrollFullMaxIterations (default 1,000,000))
  When exceeded, the loop won't be completely unrolled.
* IBM XL C/C++ Compiler will decide on the unroll factor
  instead of unrolling completely when n is not specified. [5]

The compiler ICC mentioned in PR91840 has reached its EOL,
and is thus not discussed here.

Regarding the (USHRT_MAX - 1) limitation:
* It is a pre-existing implementation detail,
  which currently surfaces only in error messages and code comments.
* If applied, this series documents the limit only on the
  complete-unrolling "#pragma unroll",
  leaving `#pragma GCC unroll N` and `#pragma unroll N` without it.
* I am not certain which level of exposure would be the best balance
  between utility and maintainability.
  Guidance on how much to expose here would be appreciated.

Future work: "#pragma nounroll" is a natural companion,
but it is currently left out of this patch series
as not all of the compilers compared above (e.g., NVCC) support it, [3]
so its inter-compiler-compatibility rationale is weaker
and its semantics need separate consideration.
It can follow as a standalone patch.

Regtested on x86_64-pc-linux-gnu; no regressions.
New tests for the added pragmas pass under both C and C++.

[1]: 
https://clang.llvm.org/docs/AttributeReference.html#pragma-unroll-pragma-nounroll
[2]: 
https://github.com/llvm/llvm-project/blob/afb54cc942d5fccf63f5594a6808f21eb179db6f/llvm/lib/Transforms/Scalar/LoopUnrollPass.cpp
[3]: 
https://docs.nvidia.com/cuda/cuda-programming-guide/05-appendices/cpp-language-extensions.html#pragma-unroll
[4]: 
https://www.ibm.com/docs/en/ent-metalc-zos/3.1.0?topic=descriptions-pragma-unroll
[5]: https://www.ibm.com/docs/en/SSRZSMX_17.1.3/pdf/user.pdf

Yueh-Shun Li (3):
  testsuite: c-c++-common/unroll-8.c: new test
  c-family: support #pragma unroll (n) [PR91840]
  c-family: support complete unrolling with #pragma unroll

 gcc/c-family/c-pragma.cc                      |  4 ++
 gcc/c-family/c-pragma.h                       |  1 +
 gcc/c/c-parser.cc                             | 21 +++++++--
 gcc/cp/parser.cc                              | 20 +++++++-
 gcc/doc/extend.texi                           | 18 ++++++++
 .../unroll-1-unqualified-complete.c           | 24 ++++++++++
 .../unroll-1-unqualified-constant.c           | 46 +++++++++++++++++++
 .../unroll-4-unqualified-constant.c           | 31 +++++++++++++
 .../unroll-5-unqualified-constant.c           | 35 ++++++++++++++
 .../unroll-8-unqualified-complete.c           | 29 ++++++++++++
 gcc/testsuite/c-c++-common/unroll-8.c         | 37 +++++++++++++++
 .../pr126323-unroll-unqualified-complete.C    | 13 ++++++
 .../pr126323-unroll-unqualified-constant.C    | 12 +++++
 13 files changed, 285 insertions(+), 6 deletions(-)
 create mode 100644 gcc/testsuite/c-c++-common/unroll-1-unqualified-complete.c
 create mode 100644 gcc/testsuite/c-c++-common/unroll-1-unqualified-constant.c
 create mode 100644 gcc/testsuite/c-c++-common/unroll-4-unqualified-constant.c
 create mode 100644 gcc/testsuite/c-c++-common/unroll-5-unqualified-constant.c
 create mode 100644 gcc/testsuite/c-c++-common/unroll-8-unqualified-complete.c
 create mode 100644 gcc/testsuite/c-c++-common/unroll-8.c
 create mode 100644 
gcc/testsuite/g++.dg/parse/pr126323-unroll-unqualified-complete.C
 create mode 100644 
gcc/testsuite/g++.dg/parse/pr126323-unroll-unqualified-constant.C

-- 
2.54.0

Reply via email to