https://gcc.gnu.org/g:fbcafeec06a66175108be68c34aceafba7a453b9

commit r17-4947-gfbcafeec06a66175108be68c34aceafba7a453b9
Author: Tobias Burnus <[email protected]>
Date:   Wed Oct 7 06:36:24 2026 +0200

    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 otherwise 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.

Diff:
---
 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 | 46 ++++++++++++
 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, 454 insertions(+), 24 deletions(-)

diff --git a/gcc/attribs.cc b/gcc/attribs.cc
index cd4be1bd6c5f..ede120d5bcaf 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 927aff6d5b8e..7523f1ad8045 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 974568691011..2d0200858331 100644
--- a/gcc/c/c-typeck.cc
+++ b/gcc/c/c-typeck.cc
@@ -18440,6 +18440,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 23017857277a..b98792a5ad58 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 c7f5d55b14f8..fd60878ef2a6 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 f9f05eb09234..63be0e1f369e 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 f452e8b4cbd6..94d71d71fc27 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 564fe858cdd4..5d0bd02f3a3e 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 1d670d4f11f3..6ff3e583a124 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 000000000000..32632af23f60
--- /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 000000000000..8a355f2350b6
--- /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 000000000000..d1555fee7eca
--- /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 000000000000..01f00922d803
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/gomp/simdlen-scaled-4.c
@@ -0,0 +1,46 @@
+/* { 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 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 000000000000..9d826fa7cd86
--- /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 000000000000..a180402f6b86
--- /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 18330169d831..d3768befcd6f 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 f2718d03a4dc..3c27d65e9e75 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 3b7ad2b18180..27d30c39cbe6 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 3fb643ea0fb4..fb82b1750ddc 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)

Reply via email to