Tamar + Robbin: This was added to OpenMP 6.1 (release: Nov 2026) / TR14 (Nov
2025)
for aarch64 / RISC-V as they have many vector modes.
Please take care of the middle-end part + target hooks, including mangling,
once it landed
Also missing:
* Fortran
* When used with 'declare variant', I found a bug (C++-only): PR127734.
* It seems as if something should be done for the __simd__ attribute as
well (cf. far below).
PR127723 is the tracking issue for this. Tamar pointed me to PR114635
('OpenMP reductions fail dependency analysis') at the end of the
vectorizer BoF.
To the feature itself:
#pragma omp declare simd
and
#pragma omp [for] simd
<some loop>
now have a type-dependent scaling argument (>= 1) for simdlen, namely:
simdlen( [scaled(<type>[, divisor]) :] length )
where the scaling is MAX( 1, round-down( VL(type) / divisor ))
VL is permitted to be a runtime value and is target and type-dependent;
type is an arithmetic type - and the length + divisor are constant
integer >= 1.
[In 'omp declare variant', it can also be used with
'match(construct={simd(simdlen(scaled(...):len))})]
* * *
Any comments, remarks, or concerns before I commit it?
* * *
BTW: In GLIBC's /usr/include/bits/math-vector.h there is:
#if defined __x86_64__ && defined __FAST_MATH__
# if defined _OPENMP && _OPENMP >= 201307
/* OpenMP case. */
# define __DECL_SIMD_x86_64 _Pragma ("omp declare simd notinbranch")
# elif __GNUC_PREREQ (6,0)
/* W/o OpenMP use GCC 6.* __attribute__ ((__simd__)). */
# define __DECL_SIMD_x86_64 __attribute__ ((__simd__ ("notinbranch")))
# endif
I think it would be useful to have something for aarch64 and RISC-V
as well, I also recall some old idea by Tamar to expend the __simd__
attribute for SVE, which might now work with 'scaled'?
Having some __simd__ variant (with GCC >= 17 check) would be nice
as most codes does not use OpenMP - and even with -fopenmp-simd,
_OPENMP is not set.
When adding a 'scaled' version to GLIBC, it would require a
GCC >= 17 check - not only for __simd__ but also for OpenMP as
it will take many years until compilers claim sufficiently full
OpenMP 6.1 support (>= 202611) to report it as such via _OPENMP.
When modifying the __simd__, recall that GLIBC also has a Fortran
header: /usr/include/finclude/math-vector-fortran.h
This is currently used as:
!GCC$ builtin (cos) attributes simd (notinbranch) if('x86_64')
and should be then also updated.
Cheers,
Tobias
PS: For type being equal, I currently check whether the type tree
is identical (pointer comparison); that should work for any normal code,
but with typeof or some 'typedef' one might end up having trees which
differ, e.g. in the qualifier. I am not sure that's a real issue or not.
Thoughts about this?
OpenMP: Add the 'scaled' modifier to the 'simdlen' clause [PR127723]
This OpenMP 6.1 (TR14) feature was added to handle the fancier
simdlen variants of AArch64/RISC-V.
Namely, besides 'simdlen(length)' there is now also an optional scale
factor:
simdlen( scaled(arith-type [, divisor]) : length )
with the scaling factor defaulting to one when absent and other being
max(1, round_down(VL(type) / divisor))
and VL(type) is a target & type specific value, which might be only
known at runtime (divisor and length must be >= 1 and constant).
And 'type' is an arithmetic type (C/C++) or numeric intrinsic type
(Fortran).
The 'simdlen' with 'scaled' can be specified on 'declare simd', on
the 'simd' directive, and as context selector on 'declare variant'.
This commit adds support for C and C++, only, and currently fails with
a sorry in gimplify_scan_omp_clauses and simd_clone_clauses_extract.
PR middle-end/127723
gcc/ChangeLog:
* attribs.cc (omp_declare_simd_clauses_equal): Handle
simdlen's type and divisor of the scaled modifier.
* omp-general.cc (resolve_omp_target_device_matches,
omp_construct_simd_compare): Likewise.
* gimplify.cc (gimplify_scan_omp_clauses): Remove
simdlen clause with a sorry when it has a scaled modifier.
* omp-simd-clone.cc (simd_clone_clauses_extract): Likewise.
* tree-core.h (enum omp_clause_code): Update comment for
OMP_CLAUSE_SIMDLEN.
* tree-pretty-print.cc (dump_omp_clause): Handle scaled
modifier to simdlen.
(dump_omp_context_selector): Fix dumping of simd trait.
* tree.cc (omp_clause_num_ops): OMP_CLAUSE_SIMDLEN takes
now three operands.
* tree.h (OMP_CLAUSE_SIMDLEN_TYPE,
OMP_CLAUSE_SIMDLEN_DIVISOR): New defines.
gcc/c/ChangeLog:
* c-parser.cc (c_parser_omp_clause_simdlen): Handle
simdlen's type and divisor of the scaled modifier.
* c-typeck.cc (c_finish_omp_clauses): Add comment
about safelen vs. simdlen with scaled.
gcc/cp/ChangeLog:
* parser.cc (cp_parser_omp_clause_simdlen): Handle
simdlen's type and divisor of the scaled modifier.
* pt.cc (tsubst_omp_clauses): Likewise
* semantics.cc (finish_omp_clauses): Likewise;
add comment about safelen vs. simdlen with scaled.
gcc/testsuite/ChangeLog:
* c-c++-common/gomp/simdlen-scaled-1.c: New test.
* c-c++-common/gomp/simdlen-scaled-2.c: New test.
* c-c++-common/gomp/simdlen-scaled-3.c: New test.
* c-c++-common/gomp/simdlen-scaled-4.c: New test.
* g++.dg/gomp/simdlen-scaled-1.C: New test.
* g++.dg/gomp/simdlen-scaled-2.C: New test.
gcc/attribs.cc | 8 +++
gcc/c/c-parser.cc | 81 ++++++++++++++++++----
gcc/c/c-typeck.cc | 8 +++
gcc/cp/parser.cc | 42 ++++++++++-
gcc/cp/pt.cc | 11 ++-
gcc/cp/semantics.cc | 51 ++++++++++++++
gcc/gimplify.cc | 10 ++-
gcc/omp-general.cc | 20 +++++-
gcc/omp-simd-clone.cc | 4 ++
gcc/testsuite/c-c++-common/gomp/simdlen-scaled-1.c | 23 ++++++
gcc/testsuite/c-c++-common/gomp/simdlen-scaled-2.c | 21 ++++++
gcc/testsuite/c-c++-common/gomp/simdlen-scaled-3.c | 65 +++++++++++++++++
gcc/testsuite/c-c++-common/gomp/simdlen-scaled-4.c | 49 +++++++++++++
gcc/testsuite/g++.dg/gomp/simdlen-scaled-1.C | 29 ++++++++
gcc/testsuite/g++.dg/gomp/simdlen-scaled-2.C | 30 ++++++++
gcc/tree-core.h | 2 +
gcc/tree-pretty-print.cc | 19 ++++-
gcc/tree.cc | 2 +-
gcc/tree.h | 6 ++
19 files changed, 457 insertions(+), 24 deletions(-)
diff --git a/gcc/attribs.cc b/gcc/attribs.cc
index cd4be1bd6c5..ede120d5bca 100644
--- a/gcc/attribs.cc
+++ b/gcc/attribs.cc
@@ -1440,6 +1440,14 @@ omp_declare_simd_clauses_equal (tree clauses1, tree clauses2)
if (simple_cst_equal (OMP_CLAUSE_SIMDLEN_EXPR (cl1),
OMP_CLAUSE_SIMDLEN_EXPR (cl2)) != 1)
return false;
+ if (OMP_CLAUSE_SIMDLEN_TYPE (cl1) != OMP_CLAUSE_SIMDLEN_TYPE (cl2))
+ return false;
+ if ((OMP_CLAUSE_SIMDLEN_DIVISOR (cl1) == NULL_TREE)
+ != (OMP_CLAUSE_SIMDLEN_DIVISOR (cl2) == NULL_TREE)
+ || (OMP_CLAUSE_SIMDLEN_DIVISOR (cl1)
+ && simple_cst_equal (OMP_CLAUSE_SIMDLEN_DIVISOR (cl1),
+ OMP_CLAUSE_SIMDLEN_DIVISOR (cl2)) != 1))
+ return false;
default:
break;
}
diff --git a/gcc/c/c-parser.cc b/gcc/c/c-parser.cc
index 927aff6d5b8..7523f1ad804 100644
--- a/gcc/c/c-parser.cc
+++ b/gcc/c/c-parser.cc
@@ -20178,40 +20178,93 @@ c_parser_omp_clause_safelen (c_parser *parser, tree list)
}
/* OpenMP 4.0:
- simdlen ( constant-expression ) */
+ simdlen ( constant-expression )
+
+ OpenMP 6.1:
+ simdlen ([scaled(type[, constant-expression]):] constant-expression ) */
static tree
c_parser_omp_clause_simdlen (c_parser *parser, tree list)
{
location_t clause_loc = c_parser_peek_token (parser)->location;
- tree c, t;
+ tree c, t = NULL_TREE, type = NULL_TREE, divisor = NULL_TREE;
matching_parens parens;
if (!parens.require_open (parser))
return list;
- location_t expr_loc = c_parser_peek_token (parser)->location;
- c_expr expr = c_parser_expr_no_commas (parser, NULL);
- expr = convert_lvalue_to_rvalue (expr_loc, expr, false, true);
- t = expr.value;
- t = c_fully_fold (t, false, NULL);
- if (TREE_CODE (t) != INTEGER_CST
- || !INTEGRAL_TYPE_P (TREE_TYPE (t))
- || tree_int_cst_sgn (t) != 1)
+ unsigned pos = 3;
+ if (c_parser_next_token_is (parser, CPP_NAME)
+ && c_parser_peek_2nd_token (parser)->type == CPP_OPEN_PAREN
+ && strcmp (IDENTIFIER_POINTER (c_parser_peek_token (parser)->value),
+ "scaled") == 0
+ && c_parser_check_balanced_raw_token_sequence (parser, &pos)
+ && c_parser_peek_nth_token_raw (parser, ++pos)->type == CPP_COLON)
{
- error_at (clause_loc, "%<simdlen%> clause expression must "
- "be positive constant integer expression");
- t = NULL_TREE;
+ c_parser_consume_token (parser);
+ matching_parens parens2;
+ parens2.require_open (parser);
+
+ location_t loc = c_parser_peek_token (parser)->location;
+ struct c_type_name *ctype = c_parser_type_name (parser);
+ if (ctype == NULL
+ || (type = groktypename (ctype, NULL, NULL)) == NULL
+ || (!INTEGRAL_TYPE_P (type)
+ && !SCALAR_FLOAT_TYPE_P (type)
+ && TREE_CODE (type) != COMPLEX_TYPE))
+ {
+ error_at (loc, "expected arithmetic type name as argument to the "
+ "%<scaled%> modifier");
+ type = error_mark_node;
+ }
+ else if (c_parser_next_token_is (parser, CPP_COMMA))
+ {
+ c_parser_consume_token (parser);
+ loc = c_parser_peek_token (parser)->location;
+ c_expr expr = c_parser_expr_no_commas (parser, NULL);
+ expr = convert_lvalue_to_rvalue (loc, expr, false, true);
+ divisor = expr.value;
+ divisor = c_fully_fold (divisor, false, NULL);
+ if (TREE_CODE (divisor) != INTEGER_CST
+ || !INTEGRAL_TYPE_P (TREE_TYPE (divisor))
+ || tree_int_cst_sgn (divisor) != 1)
+ {
+ error_at (loc, "divisor expression of the %<scaled%> modifier "
+ "must a be positive constant integer expression");
+ type = error_mark_node;
+ }
+ }
+ parens2.skip_until_found_close (parser);
+ c_parser_require (parser, CPP_COLON, "expected %<:%>");
+ }
+
+ if (type != error_mark_node)
+ {
+ location_t expr_loc = c_parser_peek_token (parser)->location;
+ c_expr expr = c_parser_expr_no_commas (parser, NULL);
+ expr = convert_lvalue_to_rvalue (expr_loc, expr, false, true);
+ t = expr.value;
+ t = c_fully_fold (t, false, NULL);
+ if (TREE_CODE (t) != INTEGER_CST
+ || !INTEGRAL_TYPE_P (TREE_TYPE (t))
+ || tree_int_cst_sgn (t) != 1)
+ {
+ error_at (clause_loc, "%<simdlen%> clause expression must "
+ "be positive constant integer expression");
+ t = NULL_TREE;
+ }
}
parens.skip_until_found_close (parser);
- if (t == NULL_TREE || t == error_mark_node)
+ if (type == error_mark_node || t == NULL_TREE || t == error_mark_node)
return list;
check_no_duplicate_clause (list, OMP_CLAUSE_SIMDLEN, "simdlen");
c = build_omp_clause (clause_loc, OMP_CLAUSE_SIMDLEN);
OMP_CLAUSE_SIMDLEN_EXPR (c) = t;
+ OMP_CLAUSE_SIMDLEN_TYPE (c) = type;
+ OMP_CLAUSE_SIMDLEN_DIVISOR (c) = divisor;
OMP_CLAUSE_CHAIN (c) = list;
return c;
}
diff --git a/gcc/c/c-typeck.cc b/gcc/c/c-typeck.cc
index 9b01f3daec9..a1a4eaf349b 100644
--- a/gcc/c/c-typeck.cc
+++ b/gcc/c/c-typeck.cc
@@ -18439,6 +18439,14 @@ c_finish_omp_clauses (tree clauses, enum c_omp_region_type ort)
&& tree_int_cst_lt (OMP_CLAUSE_SAFELEN_EXPR (safelen),
OMP_CLAUSE_SIMDLEN_EXPR (simdlen)))
{
+ /* Note: How a scaling factor affects this, is underspecified in OpenMP;
+ cf. OpenMP spec issue #5160. Presumably, it means:
+ savelen >= simdlen * scale_factor
+ with
+ scale_factor = MAX (1, FLOOR_DIV_EXPR (VL(type), divisor))
+ and OpenMP states that VL(type) might be only known at runtime.
+ Hence scale_factor >= 1 and, conservatively, assume == 1 for this
+ error check. */
error_at (OMP_CLAUSE_LOCATION (simdlen),
"%<simdlen%> clause value is bigger than "
"%<safelen%> clause value");
diff --git a/gcc/cp/parser.cc b/gcc/cp/parser.cc
index 3c84f6e335f..9248793b890 100644
--- a/gcc/cp/parser.cc
+++ b/gcc/cp/parser.cc
@@ -44844,21 +44844,55 @@ cp_parser_omp_clause_safelen (cp_parser *parser, tree list,
}
/* OpenMP 4.0:
- simdlen ( constant-expression ) */
+ simdlen ( constant-expression )
+
+ OpenMP 6.1:
+ simdlen ([scaled(type[, constant-expression]):] constant-expression ) */
static tree
cp_parser_omp_clause_simdlen (cp_parser *parser, tree list,
location_t location)
{
- tree t, c;
+ tree c, t = NULL_TREE, type = NULL_TREE, divisor = NULL_TREE;
matching_parens parens;
if (!parens.require_open (parser))
return list;
+ unsigned pos = 2;
+ if (cp_lexer_next_token_is (parser->lexer, CPP_NAME)
+ && cp_lexer_nth_token_is (parser->lexer, 2, CPP_OPEN_PAREN)
+ && strcmp (
+ IDENTIFIER_POINTER (cp_lexer_peek_token (parser->lexer)->u.value),
+ "scaled") == 0
+ && (pos = cp_parser_skip_balanced_tokens (parser, pos))
+ && cp_lexer_nth_token_is (parser->lexer, pos, CPP_COLON))
+ {
+ cp_lexer_consume_token (parser->lexer);
+ matching_parens parens2;
+ parens2.require_open (parser);
+
+ type = cp_parser_type_id (parser);
+ if (type != error_mark_node
+ && cp_lexer_next_token_is (parser->lexer, CPP_COMMA))
+ {
+ cp_lexer_consume_token (parser->lexer);
+ divisor = cp_parser_constant_expression (parser);
+ }
+ if (type == error_mark_node || divisor == error_mark_node)
+ cp_parser_skip_to_closing_parenthesis (parser, /*recovering=*/true,
+ /*or_comma=*/false,
+ /*consume_paren=*/true);
+ else if (!parens2.require_close (parser))
+ type = error_mark_node;
+ if (!cp_parser_require (parser, CPP_COLON, RT_COLON))
+ type = error_mark_node;
+ }
+
t = cp_parser_constant_expression (parser);
- if (t == error_mark_node
+ if (type == error_mark_node
+ || t == error_mark_node
|| !parens.require_close (parser))
cp_parser_skip_to_closing_parenthesis (parser, /*recovering=*/true,
/*or_comma=*/false,
@@ -44868,6 +44902,8 @@ cp_parser_omp_clause_simdlen (cp_parser *parser, tree list,
c = build_omp_clause (location, OMP_CLAUSE_SIMDLEN);
OMP_CLAUSE_SIMDLEN_EXPR (c) = t;
+ OMP_CLAUSE_SIMDLEN_TYPE (c) = type;
+ OMP_CLAUSE_SIMDLEN_DIVISOR (c) = divisor;
OMP_CLAUSE_CHAIN (c) = list;
return c;
diff --git a/gcc/cp/pt.cc b/gcc/cp/pt.cc
index 2b68ceb0cd2..dbe874645be 100644
--- a/gcc/cp/pt.cc
+++ b/gcc/cp/pt.cc
@@ -18937,7 +18937,6 @@ tsubst_omp_clauses (tree clauses, enum c_omp_region_type ort,
case OMP_CLAUSE_DIST_SCHEDULE:
case OMP_CLAUSE_THREAD_LIMIT:
case OMP_CLAUSE_SAFELEN:
- case OMP_CLAUSE_SIMDLEN:
case OMP_CLAUSE_NUM_TASKS:
case OMP_CLAUSE_GRAINSIZE:
case OMP_CLAUSE_PRIORITY:
@@ -18976,6 +18975,16 @@ tsubst_omp_clauses (tree clauses, enum c_omp_region_type ort,
= tsubst_expr (OMP_CLAUSE_NOVARIANTS_EXPR (oc), args, complain,
in_decl);
break;
+ case OMP_CLAUSE_SIMDLEN:
+ OMP_CLAUSE_SIMDLEN_EXPR (nc)
+ = tsubst_stmt (OMP_CLAUSE_SIMDLEN_EXPR (oc),
+ args, complain, in_decl);
+ OMP_CLAUSE_SIMDLEN_TYPE (nc)
+ = tsubst (OMP_CLAUSE_SIMDLEN_TYPE (oc), args, complain, in_decl);
+ OMP_CLAUSE_SIMDLEN_DIVISOR (nc)
+ = tsubst_stmt (OMP_CLAUSE_SIMDLEN_DIVISOR (oc),
+ args, complain, in_decl);
+ break;
case OMP_CLAUSE_REDUCTION:
case OMP_CLAUSE_IN_REDUCTION:
case OMP_CLAUSE_TASK_REDUCTION:
diff --git a/gcc/cp/semantics.cc b/gcc/cp/semantics.cc
index f9f05eb0923..63be0e1f369 100644
--- a/gcc/cp/semantics.cc
+++ b/gcc/cp/semantics.cc
@@ -8768,6 +8768,49 @@ finish_omp_clauses (tree clauses, enum c_omp_region_type ort)
break;
case OMP_CLAUSE_SIMDLEN:
+ t = OMP_CLAUSE_SIMDLEN_TYPE (c);
+ if (t == error_mark_node)
+ remove = true;
+ else if (t && !dependent_type_p (t)
+ && !ARITHMETIC_TYPE_P (t))
+ {
+ error_at (OMP_CLAUSE_LOCATION (c),
+ "expected arithmetic type name as argument to the "
+ "%<scaled%> modifier");
+ remove = true;
+ }
+ t = OMP_CLAUSE_SIMDLEN_DIVISOR (c);
+ if (t == error_mark_node)
+ remove = true;
+ else if (t && !type_dependent_expression_p (t)
+ && !INTEGRAL_TYPE_P (TREE_TYPE (t)))
+ {
+ error_at (OMP_CLAUSE_LOCATION (c),
+ "%qs divisor expression of the %<scaled%> modifier "
+ "must be integral",
+ omp_clause_code_name[OMP_CLAUSE_CODE (c)]);
+ remove = true;
+ }
+ else if (t)
+ {
+ t = mark_rvalue_use (t);
+ if (!processing_template_decl)
+ {
+ t = maybe_constant_value (t);
+ if (TREE_CODE (t) != INTEGER_CST
+ || tree_int_cst_sgn (t) != 1)
+ {
+ error_at (OMP_CLAUSE_LOCATION (c),
+ "%qs divisor expression of the %<scaled%> "
+ "modifier must be a positive constant integer "
+ "expression",
+ omp_clause_code_name[OMP_CLAUSE_CODE (c)]);
+ remove = true;
+ }
+ }
+ OMP_CLAUSE_SIMDLEN_DIVISOR (c) = t;
+ }
+ /* FALLTHRU */
case OMP_CLAUSE_SAFELEN:
t = OMP_CLAUSE_OPERAND (c, 0);
if (t == error_mark_node)
@@ -10484,6 +10527,14 @@ finish_omp_clauses (tree clauses, enum c_omp_region_type ort)
&& tree_int_cst_lt (OMP_CLAUSE_SAFELEN_EXPR (safelen),
OMP_CLAUSE_SIMDLEN_EXPR (c)))
{
+ /* Note: How a scaling factor affects this, is underspecified in
+ OpenMP; cf. OpenMP spec issue #5160. Presumably, it means:
+ savelen >= simdlen * scale_factor
+ with
+ scale_factor = MAX (1, FLOOR_DIV_EXPR (VL(type), divisor))
+ and OpenMP states that VL(type) might be only known at runtime.
+ Hence scale_factor >= 1 and, conservatively, assume == 1 for
+ this error check. */
error_at (OMP_CLAUSE_LOCATION (c),
"%<simdlen%> clause value is bigger than "
"%<safelen%> clause value");
diff --git a/gcc/gimplify.cc b/gcc/gimplify.cc
index f452e8b4cbd..94d71d71fc2 100644
--- a/gcc/gimplify.cc
+++ b/gcc/gimplify.cc
@@ -14905,7 +14905,6 @@ gimplify_scan_omp_clauses (tree *list_p, gimple_seq *pre_p,
case OMP_CLAUSE_MESSAGE:
case OMP_CLAUSE_PROC_BIND:
case OMP_CLAUSE_SAFELEN:
- case OMP_CLAUSE_SIMDLEN:
case OMP_CLAUSE_NOGROUP:
case OMP_CLAUSE_THREADS:
case OMP_CLAUSE_SIMD:
@@ -14919,6 +14918,15 @@ gimplify_scan_omp_clauses (tree *list_p, gimple_seq *pre_p,
case OMP_CLAUSE_DEVICE_TYPE:
break;
+ case OMP_CLAUSE_SIMDLEN:
+ if (OMP_CLAUSE_SIMDLEN_TYPE (c))
+ {
+ remove = true;
+ sorry_at (OMP_CLAUSE_LOCATION (c),
+ "%<simdlen%> clause with %<scaled%> modifier");
+ }
+ break;
+
case OMP_CLAUSE_DYN_GROUPPRIVATE:
remove = true;
sorry_at (OMP_CLAUSE_LOCATION (c),"%<dyn_groupprivate%> clause");
diff --git a/gcc/omp-general.cc b/gcc/omp-general.cc
index 564fe858cdd..5d0bd02f3a3 100644
--- a/gcc/omp-general.cc
+++ b/gcc/omp-general.cc
@@ -2283,7 +2283,9 @@ resolve_omp_target_device_matches (tree node)
}
/* Compare construct={simd} CLAUSES1 with CLAUSES2, return 0/-1/1/2 as
- in omp_context_selector_set_compare. If MATCH_P is true, additionally
+ in omp_context_selector_set_compare: 0 if equal, -1 if clause1 is a
+ strict subset of clause2, 1 if clause2 is a strict subset of clause1,
+ and 2 if neither is a subset of the other. If MATCH_P is true, additionally
apply the special matching rules for the "simdlen" and "aligned" clauses
used to determine whether the selector CLAUSES1 is part of matches
the OpenMP context containing CLAUSES2. */
@@ -2299,11 +2301,12 @@ omp_construct_simd_compare (tree clauses1, tree clauses2, bool match_p)
int r = 0;
struct declare_variant_simd_data {
bool inbranch, notinbranch;
- tree simdlen;
+ tree simdlen, simdlen_divisor, simdlen_type;
auto_vec<tree,16> data_sharing;
auto_vec<tree,16> aligned;
declare_variant_simd_data ()
- : inbranch(false), notinbranch(false), simdlen(NULL_TREE) {}
+ : inbranch(false), notinbranch(false), simdlen(NULL_TREE),
+ simdlen_divisor(NULL_TREE), simdlen_type(NULL_TREE) {}
} data[2];
unsigned int i;
tree e0, e1;
@@ -2321,6 +2324,10 @@ omp_construct_simd_compare (tree clauses1, tree clauses2, bool match_p)
continue;
case OMP_CLAUSE_SIMDLEN:
data[i].simdlen = OMP_CLAUSE_SIMDLEN_EXPR (c);
+ data[i].simdlen_type = OMP_CLAUSE_SIMDLEN_TYPE (c);
+ data[i].simdlen_divisor = OMP_CLAUSE_SIMDLEN_DIVISOR (c);
+ if (!data[i].simdlen_divisor)
+ data[i].simdlen_divisor = integer_one_node;
continue;
case OMP_CLAUSE_UNIFORM:
case OMP_CLAUSE_LINEAR:
@@ -2345,6 +2352,13 @@ omp_construct_simd_compare (tree clauses1, tree clauses2, bool match_p)
r |= data[0].inbranch ? 2 : 1;
if (data[0].notinbranch != data[1].notinbranch)
r |= data[0].notinbranch ? 2 : 1;
+ /* FIXME: In OpenMP is underspecified how scaled-modifier should affect the
+ context matching; cf. OpenMP specification Issue 5160. We require here that
+ the type and divisor are identical. */
+ if (data[0].simdlen_type != data[1].simdlen_type)
+ return 2;
+ if (!simple_cst_equal (data[0].simdlen_divisor, data[1].simdlen_divisor))
+ return 2;
e0 = data[0].simdlen;
e1 = data[1].simdlen;
if (!simple_cst_equal (e0, e1))
diff --git a/gcc/omp-simd-clone.cc b/gcc/omp-simd-clone.cc
index 1d670d4f11f..6ff3e583a12 100644
--- a/gcc/omp-simd-clone.cc
+++ b/gcc/omp-simd-clone.cc
@@ -346,6 +346,10 @@ simd_clone_clauses_extract (struct cgraph_node *node, tree clauses,
case OMP_CLAUSE_SIMDLEN:
clone_info->simdlen
= TREE_INT_CST_LOW (OMP_CLAUSE_SIMDLEN_EXPR (t));
+ if (OMP_CLAUSE_SIMDLEN_TYPE (t))
+ sorry_at (DECL_SOURCE_LOCATION (node->decl),
+ "%<scaled%> modifier specified in %<simdlen%> clause on "
+ "%<declare simd%> directive for %qD", node->decl);
break;
case OMP_CLAUSE_LINEAR:
{
diff --git a/gcc/testsuite/c-c++-common/gomp/simdlen-scaled-1.c b/gcc/testsuite/c-c++-common/gomp/simdlen-scaled-1.c
new file mode 100644
index 00000000000..32632af23f6
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/gomp/simdlen-scaled-1.c
@@ -0,0 +1,23 @@
+/* { dg-do compile } */
+/* { dg-additional-options "-fdump-tree-gimple -w" } */
+
+// PR middle-end/127723
+
+#pragma omp declare simd simdlen(scaled(int, 1): 1)
+void g1(int a) { }
+// { dg-message "sorry, unimplemented: 'scaled' modifier specified in 'simdlen' clause on 'declare simd' directive for 'g1'" "" { target c } .-1 }
+// { dg-message "sorry, unimplemented: 'scaled' modifier specified in 'simdlen' clause on 'declare simd' directive for 'void g1\\(int\\)'" "" { target c++ } .-2 }
+
+#pragma omp declare simd simdlen(scaled(float, 2): 2)
+void g2(int a) { }
+// { dg-message "sorry, unimplemented: 'scaled' modifier specified in 'simdlen' clause on 'declare simd' directive for 'g2'" "" { target c } .-1 }
+// { dg-message "sorry, unimplemented: 'scaled' modifier specified in 'simdlen' clause on 'declare simd' directive for 'void g2\\(int\\)'" "" { target c++ } .-2 }
+
+#pragma omp declare simd simdlen(scaled(_Complex double): 4)
+void g3(int a) { }
+// { dg-message "sorry, unimplemented: 'scaled' modifier specified in 'simdlen' clause on 'declare simd' directive for 'g3'" "" { target c } .-1 }
+// { dg-message "sorry, unimplemented: 'scaled' modifier specified in 'simdlen' clause on 'declare simd' directive for 'void g3\\(int\\)'" "" { target c++ } .-2 }
+
+/* { dg-final { scan-tree-dump "__attribute__\\(\\(omp declare simd \\(simdlen\\(scaled\\(int,1\\):1\\)\\)\\)\\)" "gimple" } } */
+/* { dg-final { scan-tree-dump "__attribute__\\(\\(omp declare simd \\(simdlen\\(scaled\\(float,2\\):2\\)\\)\\)\\)" "gimple" } } */
+/* { dg-final { scan-tree-dump "__attribute__\\(\\(omp declare simd \\(simdlen\\(scaled\\(complex double\\):4\\)\\)\\)\\)" "gimple" } } */
diff --git a/gcc/testsuite/c-c++-common/gomp/simdlen-scaled-2.c b/gcc/testsuite/c-c++-common/gomp/simdlen-scaled-2.c
new file mode 100644
index 00000000000..8a355f2350b
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/gomp/simdlen-scaled-2.c
@@ -0,0 +1,21 @@
+/* { dg-do compile } */
+/* { dg-additional-options "-fdump-tree-original -w" } */
+
+// PR middle-end/127723
+
+void f(int n, int *a, double *d) {
+ #pragma omp simd simdlen(scaled(int,1): 1) // { dg-message "sorry, unimplemented: 'simdlen' clause with 'scaled' modifier" }
+ for (int i = 0; i < n; i++)
+ a[i] += 5;
+ #pragma omp simd simdlen(scaled(int): 2) // { dg-message "sorry, unimplemented: 'simdlen' clause with 'scaled' modifier" }
+ for (int i = 0; i < n; i++)
+ a[i] += 5;
+
+ #pragma omp simd simdlen(scaled(double, 4): 8) // { dg-message "sorry, unimplemented: 'simdlen' clause with 'scaled' modifier" }
+ for (int i = 0; i < n; i++)
+ d[i] = 0.0;
+}
+
+/* { dg-final { scan-tree-dump "#pragma omp simd simdlen\\(scaled\\(int,1\\):1\\)" "original" } } */
+/* { dg-final { scan-tree-dump "#pragma omp simd simdlen\\(scaled\\(int\\):2\\)" "original" } } */
+/* { dg-final { scan-tree-dump "#pragma omp simd simdlen\\(scaled\\(double,4\\):8\\)" "original" } } */
diff --git a/gcc/testsuite/c-c++-common/gomp/simdlen-scaled-3.c b/gcc/testsuite/c-c++-common/gomp/simdlen-scaled-3.c
new file mode 100644
index 00000000000..d1555fee7ec
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/gomp/simdlen-scaled-3.c
@@ -0,0 +1,65 @@
+/* { dg-do compile } */
+
+// PR middle-end/127723
+
+typedef struct S {} S;
+void f(int n, int *a, double *d) {
+ #pragma omp simd simdlen(scaled(int,1))
+ // { dg-error "implicit declaration of function 'scaled' \\\[-Wimplicit-function-declaration\\\]" "" { target c } .-1 }
+ // { dg-error "expected expression before 'int'" "" { target c } .-2 }
+ // { dg-error "'simdlen' clause expression must be positive constant integer expression" "" { target c } .-3 }
+ // { dg-error "expected primary-expression before 'int'" "" { target c++ } .-4 }
+ // { dg-error "'scaled' was not declared in this scope" "" { target c++11 } .-5 }
+ // { dg-error "a function call cannot appear in a constant-expression" "" { target c++98_only } .-6 }
+ for (int i = 0; i < n; i++)
+ a[i] += 5;
+ #pragma omp simd simdlen(scaled(int + 3): 2)
+ // { dg-error "expected '\\)' before '\\+' token" "" { target *-*-* } .-1 }
+ // { dg-message "sorry, unimplemented: 'simdlen' clause with 'scaled' modifier" "" { target c } .-2 }
+ // { dg-error "expected ':' before '\\+' token" "" { target c++ } .-3 }
+ // { dg-error "expected an OpenMP clause before ':' token" "" { target c++ } .-4 }
+ for (int i = 0; i < n; i++)
+ a[i] += 5;
+
+ #pragma omp simd simdlen(scaled(4): 8)
+ // { dg-error "expected specifier-qualifier-list before numeric constant" "" { target c } .-1 }
+ // { dg-error "expected arithmetic type name as argument to the 'scaled' modifier" "" { target c } .-2 }
+ // { dg-error "expected '\\)' before numeric constant" "" { target c } .-3 }
+ // { dg-error "expected type-specifier before numeric constant" "" { target c++ } .-4 }
+ for (int i = 0; i < n; i++)
+ d[i] = 0.0;
+
+ #pragma omp simd simdlen(scaled(S): 8)
+ // { dg-error "expected arithmetic type name as argument to the 'scaled' modifier" "" { target *-*-* } .-1 }
+ // { dg-error "expected '\\)' before numeric constant" "" { target c } .-2 }
+ for (int i = 0; i < n; i++)
+ d[i] = 0.0;
+
+ #pragma omp simd simdlen(scaled(float, n): 8)
+ // { dg-error "divisor expression of the 'scaled' modifier must a be positive constant integer expression" "" { target c } .-1 }
+ // { dg-error "expected '\\)' before numeric constant" "" { target c } .-2 }
+ // { dg-error "'n' is not a constant expression" "" { target c++11 } .-3 }
+ // { dg-error "'n' cannot appear in a constant-expression" "" { target c++98_only } .-4 }
+ // { dg-error "'simdlen' divisor expression of the 'scaled' modifier must be a positive constant integer expression" "" { target c++11 } .-5 }
+ for (int i = 0; i < n; i++)
+ d[i] = 0.0;
+
+ #pragma omp simd simdlen(scaled(bool, 0): 8)
+ // { dg-error "divisor expression of the 'scaled' modifier must a be positive constant integer expression" "" { target c } .-1 }
+ // { dg-error "expected '\\)' before numeric constant" "" { target c } .-2 }
+ // { dg-error "'simdlen' divisor expression of the 'scaled' modifier must be a positive constant integer expression" "" { target c++ } .-3 }
+ for (int i = 0; i < n; i++)
+ d[i] = 0.0;
+
+ #pragma omp simd simdlen(scaled(bool, 0, 2): 8)
+ // { dg-error "divisor expression of the 'scaled' modifier must a be positive constant integer expression" "" { target c } .-1 }
+ // { dg-error "expected '\\)' before ',' token" "" { target c } .-2 }
+ // { dg-error "expected '\\)' before numeric constant" "" { target c } .-3 }
+ // { dg-error "expected '\\)' before ',' token" "" { target c++ } .-4 }
+ // { dg-error "expected ':' before ',' token" "" { target c++ } .-5 }
+ // { dg-error "expected primary-expression before ',' token" "" { target c++ } .-6 }
+ // { dg-error "expected an OpenMP clause before ':' token" "" { target c++ } .-7 }
+ // { dg-error "'simdlen' divisor expression of the 'scaled' modifier must be a positive constant integer expression" "" { target c++ } .-8 }
+ for (int i = 0; i < n; i++)
+ d[i] = 0.0;
+}
diff --git a/gcc/testsuite/c-c++-common/gomp/simdlen-scaled-4.c b/gcc/testsuite/c-c++-common/gomp/simdlen-scaled-4.c
new file mode 100644
index 00000000000..838dc85b2ca
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/gomp/simdlen-scaled-4.c
@@ -0,0 +1,49 @@
+/* { dg-do compile } */
+/* { dg-additional-options "-fdump-tree-gimple -w" } */
+
+// PR middle-end/127723
+
+void fvarInt2(int);
+void fvarInt0(int);
+void fvar0(int);
+
+#pragma omp declare variant(fvarInt2) match(construct={simd(simdlen(scaled(int,2): 8))})
+#pragma omp declare variant(fvarInt0) match(construct={simd(simdlen(scaled(int): 8))})
+#pragma omp declare variant(fvar0) match(construct={simd(simdlen(4))})
+void fbase(int) { }
+
+void f() {
+#pragma omp parallel
+fbase(99);
+
+ #pragma omp simd simdlen(scaled(int,2): 8)
+ for (int i = 1; i < 0; i++)
+ fbase (1); // -> fvarInt2
+
+ #pragma omp simd simdlen(scaled(int): 8)
+ for (int i = 1; i < 0; i++)
+ fbase (2); // -> fvarInt0
+
+ #pragma omp simd simdlen(4)
+ for (int i = 1; i < 0; i++)
+ fbase (3); // -> fvar0
+
+ #pragma omp simd simdlen(8)
+ for (int i = 1; i < 0; i++)
+ fbase (4); // -> fbase
+}
+
+// Once implemented remove ...
+// { dg-message "sorry, unimplemented: 'simdlen' clause with 'scaled' modifier" "" { target *-*-* } 19 }
+// { dg-message "sorry, unimplemented: 'simdlen' clause with 'scaled' modifier" "" { target *-*-* } 23 }
+
+// ... and the following XFAIL should work ... (it fails because the clause is removed)
+// { dg-final { scan-tree-dump-times "fvarInt2 \\(1\\);" 1 "gimple" { xfail *-*-* } } }
+// { dg-final { scan-tree-dump-times "fvarInt0 \\(2\\);" 1 "gimple" { xfail *-*-* } } }
+
+// but the following three fail because of PR c++/127734:
+
+// { dg-final { scan-tree-dump-times "fvar0 \\(3\\);" 1 "gimple" { xfail c++ } } }
+// { dg-final { scan-tree-dump-times "fbase \\(4\\);" 1 "gimple" { target *-*-* } } }
+
+// { dg-final { scan-tree-dump "__attribute__\\(\\(omp declare variant base \\(fvar0 match construct = {simd \\(simdlen\\(4\\)\\)}\\), omp declare variant base \\(fvarInt0 match construct = {simd \\(simdlen\\(scaled\\(int\\):8\\)\\)}\\), omp declare variant base \\(fvarInt2 match construct = {simd \\(simdlen\\(scaled\\(int,2\\):8\\)\\)}\\)\\)\\)" "gimple" { xfail c++ } } }
diff --git a/gcc/testsuite/g++.dg/gomp/simdlen-scaled-1.C b/gcc/testsuite/g++.dg/gomp/simdlen-scaled-1.C
new file mode 100644
index 00000000000..9d826fa7cd8
--- /dev/null
+++ b/gcc/testsuite/g++.dg/gomp/simdlen-scaled-1.C
@@ -0,0 +1,29 @@
+/* { dg-do compile } */
+/* { dg-additional-options "-fdump-tree-gimple -w" } */
+
+// PR middle-end/127723
+
+template<typename T, int d, long l>
+[[omp::decl(declare simd,simdlen(scaled(T, d): l))]]
+void g1(int a) { }
+// { dg-message "sorry, unimplemented: 'scaled' modifier specified in 'simdlen' clause on 'declare simd' directive for 'void g1\\(int\\) \\\[with T = int; int d = 1; long int l = 1\\\]'" "" { target *-*-* } .-1 }
+
+template<typename T, int d, long l>
+[[omp::decl(declare simd,simdlen(scaled(T, d + l): sizeof (T)))]]
+void g2(int a) { }
+// { dg-message "sorry, unimplemented: 'scaled' modifier specified in 'simdlen' clause on 'declare simd' directive for 'void g2\\(int\\) \\\[with T = float; int d = 2; long int l = 0\\\]'" "" { target *-*-* } .-1 }
+
+template<typename T, int d, long l>
+[[omp::decl(declare simd,simdlen(scaled(T): l/d))]]
+void g3(int a) { }
+// { dg-message "sorry, unimplemented: 'scaled' modifier specified in 'simdlen' clause on 'declare simd' directive for 'void g3\\(int\\) \\\[with T = __complex__ double; int d = 2; long int l = 8\\\]'" "" { target *-*-* } .-1 }
+
+void f() {
+ g1<int, 1, 1>(1);
+ g2<float, 2, 0>(1);
+ g3<_Complex double, 2, 8>(1);
+}
+
+/* { dg-final { scan-tree-dump "__attribute__\\(\\(omp declare simd \\(simdlen\\(scaled\\(int,1\\):1\\)\\)\\)\\)" "gimple" } } */
+/* { dg-final { scan-tree-dump "__attribute__\\(\\(omp declare simd \\(simdlen\\(scaled\\(float,2\\):4\\)\\)\\)\\)" "gimple" } } */
+/* { dg-final { scan-tree-dump "__attribute__\\(\\(omp declare simd \\(simdlen\\(scaled\\(complex double\\):4\\)\\)\\)\\)" "gimple" } } */
diff --git a/gcc/testsuite/g++.dg/gomp/simdlen-scaled-2.C b/gcc/testsuite/g++.dg/gomp/simdlen-scaled-2.C
new file mode 100644
index 00000000000..a180402f6b8
--- /dev/null
+++ b/gcc/testsuite/g++.dg/gomp/simdlen-scaled-2.C
@@ -0,0 +1,30 @@
+/* { dg-do compile } */
+/* { dg-additional-options "-std=gnu++11 -fdump-tree-gimple -w" } */
+/* Variant which permits 'typeof' */
+
+// PR middle-end/127723
+
+template<typename T, int d, long l>
+[[omp::decl(declare simd,simdlen(scaled(T, d): l))]]
+void g1(int a) { }
+// { dg-message "sorry, unimplemented: 'scaled' modifier specified in 'simdlen' clause on 'declare simd' directive for 'void g1\\(int\\) \\\[with T = int; int d = 1; long int l = 1\\\]'" "" { target *-*-* } .-1 }
+
+template<typename T, int d, long l>
+[[omp::decl(declare simd,simdlen(scaled(typeof (a), d + l): sizeof (T)))]]
+void g2(T a) { }
+// { dg-message "sorry, unimplemented: 'scaled' modifier specified in 'simdlen' clause on 'declare simd' directive for 'void g2\\(T\\) \\\[with T = float; int d = 2; long int l = 0\\\]'" "" { target *-*-* } .-1 }
+
+template<typename T, int d, long l>
+[[omp::decl(declare simd,simdlen(scaled(T): l/d))]]
+void g3(int a) { }
+// { dg-message "sorry, unimplemented: 'scaled' modifier specified in 'simdlen' clause on 'declare simd' directive for 'void g3\\(int\\) \\\[with T = __complex__ double; int d = 2; long int l = 8\\\]'" "" { target *-*-* } .-1 }
+
+void f() {
+ g1<int, 1, 1>(1);
+ g2<float, 2, 0>(1.0f);
+ g3<_Complex double, 2, 8>(1);
+}
+
+/* { dg-final { scan-tree-dump "__attribute__\\(\\(omp declare simd \\(simdlen\\(scaled\\(int,1\\):1\\)\\)\\)\\)" "gimple" } } */
+/* { dg-final { scan-tree-dump "__attribute__\\(\\(omp declare simd \\(simdlen\\(scaled\\(float,2\\):4\\)\\)\\)\\)" "gimple" } } */
+/* { dg-final { scan-tree-dump "__attribute__\\(\\(omp declare simd \\(simdlen\\(scaled\\(complex double\\):4\\)\\)\\)\\)" "gimple" } } */
diff --git a/gcc/tree-core.h b/gcc/tree-core.h
index 18330169d83..d3768befcd6 100644
--- a/gcc/tree-core.h
+++ b/gcc/tree-core.h
@@ -495,6 +495,8 @@ enum omp_clause_code {
OMP_CLAUSE_SAFELEN,
/* OpenMP clause: simdlen (constant-integer-expression). */
+ /* OpenMP clause: simdlen ([scaled-mod:] constant-integer-expression)
+ with scaled-modifier: scaled(type [, const-integer-expression]). */
OMP_CLAUSE_SIMDLEN,
/* OpenMP clause: device_type ({host,nohost,any}). */
diff --git a/gcc/tree-pretty-print.cc b/gcc/tree-pretty-print.cc
index f2718d03a4d..3c27d65e9e7 100644
--- a/gcc/tree-pretty-print.cc
+++ b/gcc/tree-pretty-print.cc
@@ -1436,6 +1436,20 @@ dump_omp_clause (pretty_printer *pp, tree clause, int spc, dump_flags_t flags)
case OMP_CLAUSE_SIMDLEN:
pp_string (pp, "simdlen(");
+ if (OMP_CLAUSE_SIMDLEN_TYPE (clause))
+ {
+ pp_string (pp, "scaled(");
+ dump_generic_node (pp, OMP_CLAUSE_SIMDLEN_TYPE (clause),
+ spc, flags, false);
+ if (OMP_CLAUSE_SIMDLEN_DIVISOR (clause))
+ {
+ pp_comma (pp);
+ dump_generic_node (pp, OMP_CLAUSE_SIMDLEN_DIVISOR (clause),
+ spc, flags, false);
+ }
+ pp_right_paren (pp);
+ pp_colon (pp);
+ }
dump_generic_node (pp, OMP_CLAUSE_SIMDLEN_EXPR (clause),
spc, flags, false);
pp_right_paren (pp);
@@ -1786,6 +1800,7 @@ dump_omp_context_selector (pretty_printer *pp, tree ctx, int spc,
pp_string (pp, OMP_TS_NAME (sel));
tree score = OMP_TS_SCORE (sel);
tree props = OMP_TS_PROPERTIES (sel);
+ enum omp_tp_type tp_type = omp_ts_map[OMP_TS_CODE (sel)].tp_type;
if (props)
{
pp_string (pp, " (");
@@ -1797,7 +1812,9 @@ dump_omp_context_selector (pretty_printer *pp, tree ctx, int spc,
}
for (tree prop = props; prop; prop = TREE_CHAIN (prop))
{
- if (OMP_TP_NAME (prop) == OMP_TP_NAMELIST_NODE)
+ if (tp_type == OMP_TRAIT_PROPERTY_CLAUSE_LIST)
+ dump_omp_clause (pp, prop, spc + 4, flags);
+ else if (OMP_TP_NAME (prop) == OMP_TP_NAMELIST_NODE)
{
const char *str = omp_context_name_list_prop (prop);
pp_string (pp, "\"");
diff --git a/gcc/tree.cc b/gcc/tree.cc
index 3b7ad2b1818..27d30c39cbe 100644
--- a/gcc/tree.cc
+++ b/gcc/tree.cc
@@ -364,7 +364,7 @@ unsigned const char omp_clause_num_ops[] =
1, /* OMP_CLAUSE_THREAD_LIMIT */
0, /* OMP_CLAUSE_PROC_BIND */
1, /* OMP_CLAUSE_SAFELEN */
- 1, /* OMP_CLAUSE_SIMDLEN */
+ 3, /* OMP_CLAUSE_SIMDLEN */
0, /* OMP_CLAUSE_DEVICE_TYPE */
0, /* OMP_CLAUSE_FOR */
0, /* OMP_CLAUSE_PARALLEL */
diff --git a/gcc/tree.h b/gcc/tree.h
index 3fb643ea0fb..fb82b1750dd 100644
--- a/gcc/tree.h
+++ b/gcc/tree.h
@@ -2163,6 +2163,12 @@ class auto_suppress_location_wrappers
#define OMP_CLAUSE_SIMDLEN_EXPR(NODE) \
OMP_CLAUSE_OPERAND (OMP_CLAUSE_SUBCODE_CHECK (NODE, OMP_CLAUSE_SIMDLEN), 0)
+#define OMP_CLAUSE_SIMDLEN_TYPE(NODE) \
+ OMP_CLAUSE_OPERAND (OMP_CLAUSE_SUBCODE_CHECK (NODE, OMP_CLAUSE_SIMDLEN), 1)
+
+#define OMP_CLAUSE_SIMDLEN_DIVISOR(NODE) \
+ OMP_CLAUSE_OPERAND (OMP_CLAUSE_SUBCODE_CHECK (NODE, OMP_CLAUSE_SIMDLEN), 2)
+
#define OMP_CLAUSE__SIMDUID__DECL(NODE) \
OMP_CLAUSE_OPERAND (OMP_CLAUSE_SUBCODE_CHECK (NODE, OMP_CLAUSE__SIMDUID_), 0)