Hi All, In PR116140 it was brought up that adding pragma GCC unroll in std::find makes it so that you can't use a larger unroll factor if you wanted to. This is because the value can't be overriden by the other unrolling flags such as -funroll-loops.
To know whether this should be possible to do or not this proposes an extension to the pragma GCC unroll with an argument to indicate if we can override the value or not. The default is "requested" to match what it does today. Bootstrapped Regtested on aarch64-none-linux-gnu, arm-none-linux-gnueabihf, x86_64-pc-linux-gnu -m32, -m64 and no issues. Ok for master? Thanks, Tamar gcc/c/ChangeLog: PR libstdc++/116140 * c-parser.cc (c_parser_pragma_unroll): Implement hint. gcc/testsuite/ChangeLog: PR libstdc++/116140 * gcc.dg/unroll-11.c: New test. * gcc.dg/unroll-12.c: New test. * gcc.dg/unroll-13.c: New test. --- diff --git a/gcc/c/c-parser.cc b/gcc/c/c-parser.cc index 8a63dc54c795157345c71177f8335d56f755c021..2538b2aecd21da7d4992862b97e7740a8bbe0fbc 100644 --- a/gcc/c/c-parser.cc +++ b/gcc/c/c-parser.cc @@ -15602,6 +15602,25 @@ c_parser_pragma_unroll (c_parser *parser) unroll = 1; } + c_token *token = c_parser_peek_token (parser); + if (token->type != CPP_PRAGMA_EOL) + { + if (token->type != CPP_NAME) + c_parser_error (parser, "expected identifier"); + + tree name = token->value; + const char *token_name = IDENTIFIER_POINTER (name); + if (strcmp (token_name, "requested") != 0 + && strcmp (token_name, "preferred") != 0) + error_at (token->location, + "unexpected token in %<#pragma GCC unroll%>, expected " + "'requested' or 'preferred'"); + /* If preferred and -funroll-loops then ignore the unroll count. */ + if (flag_unroll_loops + && strcmp (token_name, "preferred") == 0) + unroll = 0; + c_parser_consume_token (parser); + } c_parser_skip_to_pragma_eol (parser); return unroll; } diff --git a/gcc/testsuite/gcc.dg/unroll-11.c b/gcc/testsuite/gcc.dg/unroll-11.c new file mode 100644 index 0000000000000000000000000000000000000000..0714b24be147e23a81078b26932b596198e63125 --- /dev/null +++ b/gcc/testsuite/gcc.dg/unroll-11.c @@ -0,0 +1,12 @@ +/* { dg-do compile } */ +/* { dg-additional-options "-O1 -fdump-rtl-loop2_unroll-details -funroll-loops -std=gnu99" } */ + +void f1 (int *restrict a, int n) +{ +#pragma GCC unroll 4 requested +#pragma GCC novector + for (int i = 0; i < n; i++) + a[i] *= 2; +} + +/* { dg-final { scan-rtl-dump "loop unrolled 3 times" "loop2_unroll" } } */ diff --git a/gcc/testsuite/gcc.dg/unroll-12.c b/gcc/testsuite/gcc.dg/unroll-12.c new file mode 100644 index 0000000000000000000000000000000000000000..4a4d9ec1451fe4babc264ef2b8b549b0b64fc98a --- /dev/null +++ b/gcc/testsuite/gcc.dg/unroll-12.c @@ -0,0 +1,12 @@ +/* { dg-do compile } */ +/* { dg-additional-options "-O1 -fdump-rtl-loop2_unroll-details -funroll-loops -std=gnu99" } */ + +void f2 (int *restrict a, int n) +{ +#pragma GCC unroll 4 +#pragma GCC novector + for (int i = 0; i < n; i++) + a[i] *= 2; +} + +/* { dg-final { scan-rtl-dump "loop unrolled 3 times" "loop2_unroll" } } */ diff --git a/gcc/testsuite/gcc.dg/unroll-13.c b/gcc/testsuite/gcc.dg/unroll-13.c new file mode 100644 index 0000000000000000000000000000000000000000..e5b92de2cd3292d2e23864aea3e83e4dc3368b12 --- /dev/null +++ b/gcc/testsuite/gcc.dg/unroll-13.c @@ -0,0 +1,12 @@ +/* { dg-do compile } */ +/* { dg-additional-options "-O1 -fdump-rtl-loop2_unroll-details -funroll-loops -std=gnu99" } */ + +void f3 (int *restrict a, int n) +{ +#pragma GCC unroll 4 preferred +#pragma GCC novector + for (int i = 0; i < n; i++) + a[i] *= 2; +} + +/* { dg-final { scan-rtl-dump "loop unrolled 7 times" "loop2_unroll" } } */ --
diff --git a/gcc/c/c-parser.cc b/gcc/c/c-parser.cc index 8a63dc54c795157345c71177f8335d56f755c021..2538b2aecd21da7d4992862b97e7740a8bbe0fbc 100644 --- a/gcc/c/c-parser.cc +++ b/gcc/c/c-parser.cc @@ -15602,6 +15602,25 @@ c_parser_pragma_unroll (c_parser *parser) unroll = 1; } + c_token *token = c_parser_peek_token (parser); + if (token->type != CPP_PRAGMA_EOL) + { + if (token->type != CPP_NAME) + c_parser_error (parser, "expected identifier"); + + tree name = token->value; + const char *token_name = IDENTIFIER_POINTER (name); + if (strcmp (token_name, "requested") != 0 + && strcmp (token_name, "preferred") != 0) + error_at (token->location, + "unexpected token in %<#pragma GCC unroll%>, expected " + "'requested' or 'preferred'"); + /* If preferred and -funroll-loops then ignore the unroll count. */ + if (flag_unroll_loops + && strcmp (token_name, "preferred") == 0) + unroll = 0; + c_parser_consume_token (parser); + } c_parser_skip_to_pragma_eol (parser); return unroll; } diff --git a/gcc/testsuite/gcc.dg/unroll-11.c b/gcc/testsuite/gcc.dg/unroll-11.c new file mode 100644 index 0000000000000000000000000000000000000000..0714b24be147e23a81078b26932b596198e63125 --- /dev/null +++ b/gcc/testsuite/gcc.dg/unroll-11.c @@ -0,0 +1,12 @@ +/* { dg-do compile } */ +/* { dg-additional-options "-O1 -fdump-rtl-loop2_unroll-details -funroll-loops -std=gnu99" } */ + +void f1 (int *restrict a, int n) +{ +#pragma GCC unroll 4 requested +#pragma GCC novector + for (int i = 0; i < n; i++) + a[i] *= 2; +} + +/* { dg-final { scan-rtl-dump "loop unrolled 3 times" "loop2_unroll" } } */ diff --git a/gcc/testsuite/gcc.dg/unroll-12.c b/gcc/testsuite/gcc.dg/unroll-12.c new file mode 100644 index 0000000000000000000000000000000000000000..4a4d9ec1451fe4babc264ef2b8b549b0b64fc98a --- /dev/null +++ b/gcc/testsuite/gcc.dg/unroll-12.c @@ -0,0 +1,12 @@ +/* { dg-do compile } */ +/* { dg-additional-options "-O1 -fdump-rtl-loop2_unroll-details -funroll-loops -std=gnu99" } */ + +void f2 (int *restrict a, int n) +{ +#pragma GCC unroll 4 +#pragma GCC novector + for (int i = 0; i < n; i++) + a[i] *= 2; +} + +/* { dg-final { scan-rtl-dump "loop unrolled 3 times" "loop2_unroll" } } */ diff --git a/gcc/testsuite/gcc.dg/unroll-13.c b/gcc/testsuite/gcc.dg/unroll-13.c new file mode 100644 index 0000000000000000000000000000000000000000..e5b92de2cd3292d2e23864aea3e83e4dc3368b12 --- /dev/null +++ b/gcc/testsuite/gcc.dg/unroll-13.c @@ -0,0 +1,12 @@ +/* { dg-do compile } */ +/* { dg-additional-options "-O1 -fdump-rtl-loop2_unroll-details -funroll-loops -std=gnu99" } */ + +void f3 (int *restrict a, int n) +{ +#pragma GCC unroll 4 preferred +#pragma GCC novector + for (int i = 0; i < n; i++) + a[i] *= 2; +} + +/* { dg-final { scan-rtl-dump "loop unrolled 7 times" "loop2_unroll" } } */