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/cp/ChangeLog: PR libstdc++/116140 * parser.cc (cp_parser_pragma_unroll): Implement hint. gcc/testsuite/ChangeLog: PR libstdc++/116140 * g++.dg/unroll-11.C: New test. * g++.dg/unroll-12.C: New test. * g++.dg/unroll-13.C: New test. --- diff --git a/gcc/cp/parser.cc b/gcc/cp/parser.cc index 1fb9e7fd87298e4539a5325c91086ff5b6ae5de7..98fb1c83eb76a6fa9fa37037b9d36496c978854d 100644 --- a/gcc/cp/parser.cc +++ b/gcc/cp/parser.cc @@ -53457,6 +53457,25 @@ cp_parser_pragma_unroll (cp_parser *parser, cp_token *pragma_tok) location_t location = cp_lexer_peek_token (parser->lexer)->location; tree unroll = cp_parser_constant_expression (parser); unroll = cp_check_pragma_unroll (location, fold_non_dependent_expr (unroll)); + cp_token *token = cp_lexer_peek_token (parser->lexer); + if (token->type != CPP_PRAGMA_EOL) + { + if (token->type != CPP_NAME) + cp_parser_error (parser, "expected identifier"); + + tree name = token->u.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 = NULL_TREE; + cp_lexer_consume_token (parser->lexer); + } cp_parser_skip_to_pragma_eol (parser, pragma_tok); return unroll; } diff --git a/gcc/testsuite/g++.dg/unroll-11.C b/gcc/testsuite/g++.dg/unroll-11.C new file mode 100644 index 0000000000000000000000000000000000000000..105f49eb4c3cb13f1af2ad5706f5203b954132d6 --- /dev/null +++ b/gcc/testsuite/g++.dg/unroll-11.C @@ -0,0 +1,12 @@ +/* { dg-do compile } */ +/* { dg-additional-options "-O1 -fdump-rtl-loop2_unroll-details -funroll-loops" } */ + +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/g++.dg/unroll-12.C b/gcc/testsuite/g++.dg/unroll-12.C new file mode 100644 index 0000000000000000000000000000000000000000..2af1e3824ba8ca5a05095db648be1ce4f114fe8e --- /dev/null +++ b/gcc/testsuite/g++.dg/unroll-12.C @@ -0,0 +1,12 @@ +/* { dg-do compile } */ +/* { dg-additional-options "-O1 -fdump-rtl-loop2_unroll-details -funroll-loops" } */ + +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/g++.dg/unroll-13.C b/gcc/testsuite/g++.dg/unroll-13.C new file mode 100644 index 0000000000000000000000000000000000000000..6958852ed1018db21ba25546b383c65823abdec1 --- /dev/null +++ b/gcc/testsuite/g++.dg/unroll-13.C @@ -0,0 +1,12 @@ +/* { dg-do compile } */ +/* { dg-additional-options "-O1 -fdump-rtl-loop2_unroll-details -funroll-loops" } */ + +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/cp/parser.cc b/gcc/cp/parser.cc index 1fb9e7fd87298e4539a5325c91086ff5b6ae5de7..98fb1c83eb76a6fa9fa37037b9d36496c978854d 100644 --- a/gcc/cp/parser.cc +++ b/gcc/cp/parser.cc @@ -53457,6 +53457,25 @@ cp_parser_pragma_unroll (cp_parser *parser, cp_token *pragma_tok) location_t location = cp_lexer_peek_token (parser->lexer)->location; tree unroll = cp_parser_constant_expression (parser); unroll = cp_check_pragma_unroll (location, fold_non_dependent_expr (unroll)); + cp_token *token = cp_lexer_peek_token (parser->lexer); + if (token->type != CPP_PRAGMA_EOL) + { + if (token->type != CPP_NAME) + cp_parser_error (parser, "expected identifier"); + + tree name = token->u.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 = NULL_TREE; + cp_lexer_consume_token (parser->lexer); + } cp_parser_skip_to_pragma_eol (parser, pragma_tok); return unroll; } diff --git a/gcc/testsuite/g++.dg/unroll-11.C b/gcc/testsuite/g++.dg/unroll-11.C new file mode 100644 index 0000000000000000000000000000000000000000..105f49eb4c3cb13f1af2ad5706f5203b954132d6 --- /dev/null +++ b/gcc/testsuite/g++.dg/unroll-11.C @@ -0,0 +1,12 @@ +/* { dg-do compile } */ +/* { dg-additional-options "-O1 -fdump-rtl-loop2_unroll-details -funroll-loops" } */ + +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/g++.dg/unroll-12.C b/gcc/testsuite/g++.dg/unroll-12.C new file mode 100644 index 0000000000000000000000000000000000000000..2af1e3824ba8ca5a05095db648be1ce4f114fe8e --- /dev/null +++ b/gcc/testsuite/g++.dg/unroll-12.C @@ -0,0 +1,12 @@ +/* { dg-do compile } */ +/* { dg-additional-options "-O1 -fdump-rtl-loop2_unroll-details -funroll-loops" } */ + +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/g++.dg/unroll-13.C b/gcc/testsuite/g++.dg/unroll-13.C new file mode 100644 index 0000000000000000000000000000000000000000..6958852ed1018db21ba25546b383c65823abdec1 --- /dev/null +++ b/gcc/testsuite/g++.dg/unroll-13.C @@ -0,0 +1,12 @@ +/* { dg-do compile } */ +/* { dg-additional-options "-O1 -fdump-rtl-loop2_unroll-details -funroll-loops" } */ + +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" } } */