public inbox for gcc-patches@gcc.gnu.org
 help / color / mirror / Atom feed
* [PATCH 0/3] OpenMP: Improve data abstractions for context selectors
@ 2023-11-19  9:21 Sandra Loosemore
  2023-11-19  9:21 ` [PATCH 1/3] OpenMP: Introduce accessor macros and constructors " Sandra Loosemore
                   ` (4 more replies)
  0 siblings, 5 replies; 9+ messages in thread
From: Sandra Loosemore @ 2023-11-19  9:21 UTC (permalink / raw)
  To: gcc-patches; +Cc: jakub, tobias

While trying to track down some bugs in the metadirective patches
(currently on the OG13 branch), I found that I was getting totally
lost in the undocumented data structures for context selectors; the
multiple levels of TREE_PURPOSE and TREE_VALUE that don't hint at what
kind of object is being accessed, generic variable names like "t1" and
"t2" likewise.  Similarly the inconsistent and undocumented
representation of different properties, switch statements over the
first character of the trait selector set name, etc added to my
confusion.  It's not surprising that adding new features made this
foundation pretty creaky and I think that adding the additional
selector features in OMP 5.2 and 6.* is going to cause it to fall over
completely.

This series of patches adds a layer of data abstraction, using at
least slightly more descriptive names, and then tries to address some
of the representation and coding issues.

Part 1 introduces some macros (e.g., OMP_TSS_ID instead of
TREE_PURPOSE to get the name of a selector) and renames a bunch of
variables (e.g., tss for a trait-set selector, ts for a trait
selector, tp for a trait property).  Those changes were relatively
mechanical.  I also added some abstraction for the trait-score so that
it need not be handled explicitly when processing property lists.

Part 2 changes the representation of name-list properties so that both
the string and identifier forms store the name in the same place.

Part 3 is a more radical change: it replaces the string names of
trait-set and trait selectors with enumerators, which allows clean-up
of those funky switch statements.  I also made things more
table-driven.  Alas, this part is still WIP; there's an ICE in one of
the test cases I haven't been able to track down yet.

I can continue to work on this patch set in the next couple of weeks
if the general direction is seen as a good thing.  I believe there is
a little more latitude re the end of stage 1 with OpenMP (as there is
with target-specific patches) since it is not enabled by default; in any
case I'd like to get feedback on the general direction before continuing too
much farther with this, and adapting the metadirective patches to match it.

-Sandra

Sandra Loosemore (3):
  OpenMP: Introduce accessor macros and constructors for context
    selectors.
  OpenMP: Unify representation of name-list properties.
  OpenMP: Use enumerators for names of trait-sets and traits

 gcc/c/c-parser.cc           | 212 ++++-------
 gcc/cp/decl.cc              |   8 +-
 gcc/cp/parser.cc            | 212 ++++-------
 gcc/cp/pt.cc                |  93 +++--
 gcc/fortran/trans-openmp.cc |  65 +++-
 gcc/gimplify.cc             |   4 +-
 gcc/omp-general.cc          | 713 ++++++++++++++++++++++--------------
 gcc/omp-general.h           | 132 ++++++-
 8 files changed, 811 insertions(+), 628 deletions(-)

-- 
2.31.1


^ permalink raw reply	[flat|nested] 9+ messages in thread

* [PATCH 1/3] OpenMP: Introduce accessor macros and constructors for context selectors.
  2023-11-19  9:21 [PATCH 0/3] OpenMP: Improve data abstractions for context selectors Sandra Loosemore
@ 2023-11-19  9:21 ` Sandra Loosemore
  2023-11-19  9:21 ` [PATCH 2/3] OpenMP: Unify representation of name-list properties Sandra Loosemore
                   ` (3 subsequent siblings)
  4 siblings, 0 replies; 9+ messages in thread
From: Sandra Loosemore @ 2023-11-19  9:21 UTC (permalink / raw)
  To: gcc-patches; +Cc: jakub, tobias

This patch hides the underlying nested TREE_LIST structure of context
selectors behind accessor macros that have more meaningful names than
the generic TREE_PURPOSE/TREE_VALUE accessors.  There is a slight
change to the representation in that the score expression in
trait-selectors has a distinguished tag and is separated from the
ordinary properties, although internally it is still represented as
the first item in the TREE_VALUE of the selector.  This patch also renames
some local variables with slightly more descriptive names so it is easier
to track whether something is a selector-set, selector, or property.

gcc/ChangeLog
	* omp-general.h (OMP_TS_SCORE_NODE): New.
	(OMP_TSS_ID, OMP_TSS_TRAIT_SELECTORS): New.
	(OMP_TS_ID, OMP_TS_SCORE, OMP_TS_PROPERTIES): New.
	(OMP_TP_NAME, OMP_TP_VALUE): New.
	(make_trait_set_selector): Declare.
	(make_trait_selector): Declare.
	(make_trait_property): Declare.
	(omp_constructor_traits_to_codes): Rename to
	omp_construct_traits_to_codes.
	* omp-general.cc (omp_constructor_traits_to_codes): Rename
	to omp_construct_traits_to_codes.  Use new accessors.
	(omp_check_context_selector): Use new accessors.
	(make_trait_set_selector): New.
	(make_trait_selector): New.
	(make_trait_property): New.
	(omp_context_name_list_prop): Use new accessors.
	(omp_context_selector_matches): Use new accessors.
	(omp_context_selector_props_compare): Use new accessors.
	(omp_context_selector_set_compare): Use new accessors.
	(omp_get_context_selector): Use new accessors.
	(omp_context_compute_score): Use new accessors.
	* gimplify.cc (omp_construct_selector_matches): Adjust for renaming
	of omp_constructor_traits_to_codes.

gcc/c/ChangeLog
	* c-parser.cc (c_parser_omp_context_selector): Use new constructors.

gcc/cp/ChangeLog
	* parser.cc (cp_parser_omp_context_selector): Use new constructors.
	* pt.cc: Include omp-general.h.
	(tsubst_attribute): Use new context selector accessors and
	 constructors.

gcc/fortran/ChangeLog
	* trans-openmp.cc (gfc_trans_omp_declare_variant): Use new
	constructors.
---
 gcc/c/c-parser.cc           |  27 ++--
 gcc/cp/parser.cc            |  30 ++--
 gcc/cp/pt.cc                |  82 ++++++----
 gcc/fortran/trans-openmp.cc |  27 ++--
 gcc/gimplify.cc             |   4 +-
 gcc/omp-general.cc          | 293 ++++++++++++++++++------------------
 gcc/omp-general.h           |  48 +++++-
 7 files changed, 297 insertions(+), 214 deletions(-)

diff --git a/gcc/c/c-parser.cc b/gcc/c/c-parser.cc
index 703f9570dbc..fcbacd461c7 100644
--- a/gcc/c/c-parser.cc
+++ b/gcc/c/c-parser.cc
@@ -24032,7 +24032,10 @@ static const char *const omp_user_selectors[] = {
      trait-selector-name[([trait-score:]trait-property[,trait-property[,...]])]
 
    trait-score:
-     score(score-expression)  */
+     score(score-expression)
+
+   Note that this function returns a list of trait selectors for the
+   trait-selector-set SET.  */
 
 static tree
 c_parser_omp_context_selector (c_parser *parser, tree set, tree parms)
@@ -24051,6 +24054,7 @@ c_parser_omp_context_selector (c_parser *parser, tree set, tree parms)
 	}
 
       tree properties = NULL_TREE;
+      tree scoreval = NULL_TREE;
       const char *const *selectors = NULL;
       bool allow_score = true;
       bool allow_user = false;
@@ -24157,8 +24161,7 @@ c_parser_omp_context_selector (c_parser *parser, tree set, tree parms)
 		    error_at (token->location, "score argument must be "
 			      "non-negative");
 		  else
-		    properties = tree_cons (get_identifier (" score"),
-					    score, properties);
+		    scoreval = score;
 		}
 	      token = c_parser_peek_token (parser);
 	    }
@@ -24171,7 +24174,8 @@ c_parser_omp_context_selector (c_parser *parser, tree set, tree parms)
 		{
 		  t = c_parser_expr_no_commas (parser, NULL).value;
 		  if (TREE_CODE (t) == STRING_CST)
-		    properties = tree_cons (NULL_TREE, t, properties);
+		    properties = make_trait_property (NULL_TREE, t,
+						      properties);
 		  else if (t != error_mark_node)
 		    {
 		      mark_exp_read (t);
@@ -24182,7 +24186,8 @@ c_parser_omp_context_selector (c_parser *parser, tree set, tree parms)
 				  "constant integer expression or string "
 				  "literal");
 		      else
-			properties = tree_cons (NULL_TREE, t, properties);
+			properties = make_trait_property (NULL_TREE, t,
+							  properties);
 		    }
 		  else
 		    return error_mark_node;
@@ -24200,7 +24205,8 @@ c_parser_omp_context_selector (c_parser *parser, tree set, tree parms)
 		{
 		  tree prop = c_parser_peek_token (parser)->value;
 		  c_parser_consume_token (parser);
-		  properties = tree_cons (prop, NULL_TREE, properties);
+		  properties = make_trait_property (prop, NULL_TREE,
+						    properties);
 		}
 	      else
 		{
@@ -24228,7 +24234,7 @@ c_parser_omp_context_selector (c_parser *parser, tree set, tree parms)
 		      return error_mark_node;
 		    }
 
-		  properties = tree_cons (prop, value, properties);
+		  properties = make_trait_property (prop, value, properties);
 
 		  if (c_parser_next_token_is (parser, CPP_COMMA))
 		    c_parser_consume_token (parser);
@@ -24248,7 +24254,8 @@ c_parser_omp_context_selector (c_parser *parser, tree set, tree parms)
 		    error_at (token->location, "property must be "
 			      "constant integer expression");
 		  else
-		    properties = tree_cons (NULL_TREE, t, properties);
+		    properties = make_trait_property (NULL_TREE, t,
+						      properties);
 		}
 	      else
 		return error_mark_node;
@@ -24286,7 +24293,7 @@ c_parser_omp_context_selector (c_parser *parser, tree set, tree parms)
 	  return error_mark_node;
 	}
 
-      ret = tree_cons (selector, properties, ret);
+      ret = make_trait_selector (selector, scoreval, properties, ret);
 
       if (c_parser_next_token_is (parser, CPP_COMMA))
 	c_parser_consume_token (parser);
@@ -24362,7 +24369,7 @@ c_parser_omp_context_selector_specification (c_parser *parser, tree parms)
       if (selectors == error_mark_node)
 	ret = error_mark_node;
       else if (ret != error_mark_node)
-	ret = tree_cons (set, selectors, ret);
+	ret = make_trait_set_selector (set, selectors, ret);
 
       braces.skip_until_found_close (parser);
 
diff --git a/gcc/cp/parser.cc b/gcc/cp/parser.cc
index d1104336215..dd773570981 100644
--- a/gcc/cp/parser.cc
+++ b/gcc/cp/parser.cc
@@ -47271,7 +47271,10 @@ static const char *const omp_user_selectors[] = {
      trait-selector-name[([trait-score:]trait-property[,trait-property[,...]])]
 
    trait-score:
-     score(score-expression)  */
+     score(score-expression)
+
+   Note that this function returns a list of trait selectors for the
+   trait-selector-set SET.  */
 
 static tree
 cp_parser_omp_context_selector (cp_parser *parser, tree set, bool has_parms_p)
@@ -47290,6 +47293,7 @@ cp_parser_omp_context_selector (cp_parser *parser, tree set, bool has_parms_p)
 	}
 
       tree properties = NULL_TREE;
+      tree scoreval = NULL_TREE;
       const char *const *selectors = NULL;
       bool allow_score = true;
       bool allow_user = false;
@@ -47396,8 +47400,7 @@ cp_parser_omp_context_selector (cp_parser *parser, tree set, bool has_parms_p)
 		    {
 		      score = fold_non_dependent_expr (score);
 		      if (value_dependent_expression_p (score))
-			properties = tree_cons (get_identifier (" score"),
-						score, properties);
+			scoreval = score;
 		      else if (!INTEGRAL_TYPE_P (TREE_TYPE (score))
 			       || TREE_CODE (score) != INTEGER_CST)
 			error_at (token->location, "score argument must be "
@@ -47406,8 +47409,7 @@ cp_parser_omp_context_selector (cp_parser *parser, tree set, bool has_parms_p)
 			error_at (token->location, "score argument must be "
 				  "non-negative");
 		      else
-			properties = tree_cons (get_identifier (" score"),
-						score, properties);
+			scoreval = score;
 		    }
 		}
 	      else
@@ -47427,7 +47429,8 @@ cp_parser_omp_context_selector (cp_parser *parser, tree set, bool has_parms_p)
 		    {
 		      t = fold_non_dependent_expr (t);
 		      if (TREE_CODE (t) == STRING_CST)
-			properties = tree_cons (NULL_TREE, t, properties);
+			properties = make_trait_property (NULL_TREE, t,
+							  properties);
 		      else if (!value_dependent_expression_p (t)
 			       && (!INTEGRAL_TYPE_P (TREE_TYPE (t))
 				   || !tree_fits_shwi_p (t)))
@@ -47435,7 +47438,8 @@ cp_parser_omp_context_selector (cp_parser *parser, tree set, bool has_parms_p)
 				  "constant integer expression or string "
 				  "literal");
 		      else
-			properties = tree_cons (NULL_TREE, t, properties);
+			properties = make_trait_property (NULL_TREE, t,
+							  properties);
 		    }
 		  else
 		    return error_mark_node;
@@ -47453,7 +47457,8 @@ cp_parser_omp_context_selector (cp_parser *parser, tree set, bool has_parms_p)
 		{
 		  tree prop = cp_lexer_peek_token (parser->lexer)->u.value;
 		  cp_lexer_consume_token (parser->lexer);
-		  properties = tree_cons (prop, NULL_TREE, properties);
+		  properties = make_trait_property (prop, NULL_TREE,
+						    properties);
 		}
 	      else
 		{
@@ -47482,7 +47487,7 @@ cp_parser_omp_context_selector (cp_parser *parser, tree set, bool has_parms_p)
 		      return error_mark_node;
 		    }
 
-		  properties = tree_cons (prop, value, properties);
+		  properties = make_trait_property (prop, value, properties);
 
 		  if (cp_lexer_next_token_is (parser->lexer, CPP_COMMA))
 		    cp_lexer_consume_token (parser->lexer);
@@ -47502,7 +47507,8 @@ cp_parser_omp_context_selector (cp_parser *parser, tree set, bool has_parms_p)
 		    error_at (token->location, "property must be "
 			      "constant integer expression");
 		  else
-		    properties = tree_cons (NULL_TREE, t, properties);
+		    properties = make_trait_property (NULL_TREE, t,
+						      properties);
 		}
 	      else
 		return error_mark_node;
@@ -47537,7 +47543,7 @@ cp_parser_omp_context_selector (cp_parser *parser, tree set, bool has_parms_p)
 	  return error_mark_node;
 	}
 
-      ret = tree_cons (selector, properties, ret);
+      ret = make_trait_selector (selector, scoreval, properties, ret);
 
       if (cp_lexer_next_token_is (parser->lexer, CPP_COMMA))
 	cp_lexer_consume_token (parser->lexer);
@@ -47619,7 +47625,7 @@ cp_parser_omp_context_selector_specification (cp_parser *parser,
 	  ret = error_mark_node;
 	}
       else if (ret != error_mark_node)
-	ret = tree_cons (set, selectors, ret);
+	ret = make_trait_set_selector (set, selectors, ret);
 
       braces.require_close (parser);
 
diff --git a/gcc/cp/pt.cc b/gcc/cp/pt.cc
index 324f6f01555..3af793dfe20 100644
--- a/gcc/cp/pt.cc
+++ b/gcc/cp/pt.cc
@@ -47,6 +47,7 @@ along with GCC; see the file COPYING3.  If not see
 #include "selftest.h"
 #include "target.h"
 #include "builtins.h"
+#include "omp-general.h"
 
 /* The type of functions taking a tree, and some additional data, and
    returning an int.  */
@@ -11841,50 +11842,72 @@ tsubst_attribute (tree t, tree *decl_p, tree args,
       location_t match_loc = cp_expr_loc_or_input_loc (TREE_PURPOSE (chain));
       tree ctx = copy_list (TREE_VALUE (val));
       tree simd = get_identifier ("simd");
-      tree score = get_identifier (" score");
       tree condition = get_identifier ("condition");
-      for (tree t1 = ctx; t1; t1 = TREE_CHAIN (t1))
+      for (tree tss = ctx; tss; tss = TREE_CHAIN (tss))
 	{
-	  const char *set = IDENTIFIER_POINTER (TREE_PURPOSE (t1));
-	  TREE_VALUE (t1) = copy_list (TREE_VALUE (t1));
-	  for (tree t2 = TREE_VALUE (t1); t2; t2 = TREE_CHAIN (t2))
+	  const char *set = IDENTIFIER_POINTER (OMP_TSS_ID (tss));
+	  tree selectors = NULL_TREE;
+	  for (tree ts = OMP_TSS_TRAIT_SELECTORS (tss); ts;
+	       ts = TREE_CHAIN (ts))
 	    {
-	      if (TREE_PURPOSE (t2) == simd && set[0] == 'c')
+	      tree properties = NULL_TREE;
+	      tree scoreval = NULL_TREE;
+	      if (OMP_TS_ID (ts) == simd && set[0] == 'c')
 		{
-		  tree clauses = TREE_VALUE (t2);
+		  tree clauses = OMP_TS_PROPERTIES (ts);
 		  clauses = tsubst_omp_clauses (clauses,
 						C_ORT_OMP_DECLARE_SIMD, args,
 						complain, in_decl);
 		  c_omp_declare_simd_clauses_to_decls (*decl_p, clauses);
 		  clauses = finish_omp_clauses (clauses, C_ORT_OMP_DECLARE_SIMD);
-		  TREE_VALUE (t2) = clauses;
+		  properties = clauses;
 		}
 	      else
 		{
-		  TREE_VALUE (t2) = copy_list (TREE_VALUE (t2));
-		  for (tree t3 = TREE_VALUE (t2); t3; t3 = TREE_CHAIN (t3))
-		    if (TREE_VALUE (t3))
+		  tree v = OMP_TS_SCORE (ts);
+		  if (v)
+		    {
+		      v = tsubst_expr (v, args, complain, in_decl);
+		      v = fold_non_dependent_expr (v);
+		      if (!INTEGRAL_TYPE_P (TREE_TYPE (v))
+			  || TREE_CODE (v) != INTEGER_CST)
+			{
+			  location_t loc
+			    = cp_expr_loc_or_loc (OMP_TS_SCORE (ts),
+						  match_loc);
+			  error_at (loc, "score argument must be "
+				    "constant integer expression");
+			  return NULL_TREE;
+			}
+		      else if (tree_int_cst_sgn (v) < 0)
+			{
+			  location_t loc
+			    = cp_expr_loc_or_loc (OMP_TS_SCORE (ts),
+						  match_loc);
+			  error_at (loc, "score argument must be "
+				    "non-negative");
+			  return NULL_TREE;
+			}
+		      scoreval = v;
+		    }
+		  properties = copy_list (OMP_TS_PROPERTIES (ts));
+		  for (tree p = properties; p; p = TREE_CHAIN (p))
+		    if (OMP_TP_VALUE (p))
 		      {
 			bool allow_string
-			  = ((TREE_PURPOSE (t2) != condition || set[0] != 'u')
-			     && TREE_PURPOSE (t3) != score);
-			tree v = TREE_VALUE (t3);
+			  = (OMP_TS_ID (ts) != condition || set[0] != 'u');
+			tree v = OMP_TP_VALUE (p);
 			if (TREE_CODE (v) == STRING_CST && allow_string)
 			  continue;
 			v = tsubst_expr (v, args, complain, in_decl);
 			v = fold_non_dependent_expr (v);
 			if (!INTEGRAL_TYPE_P (TREE_TYPE (v))
-			    || (TREE_PURPOSE (t3) == score
-				? TREE_CODE (v) != INTEGER_CST
-				: !tree_fits_shwi_p (v)))
+			    || !tree_fits_shwi_p (v))
 			  {
 			    location_t loc
-			      = cp_expr_loc_or_loc (TREE_VALUE (t3),
+			      = cp_expr_loc_or_loc (OMP_TP_VALUE (p),
 						    match_loc);
-			    if (TREE_PURPOSE (t3) == score)
-			      error_at (loc, "score argument must be "
-					     "constant integer expression");
-			    else if (allow_string)
+			    if (allow_string)
 			      error_at (loc, "property must be constant "
 					     "integer expression or string "
 					     "literal");
@@ -11893,20 +11916,13 @@ tsubst_attribute (tree t, tree *decl_p, tree args,
 					     "integer expression");
 			    return NULL_TREE;
 			  }
-			else if (TREE_PURPOSE (t3) == score
-				 && tree_int_cst_sgn (v) < 0)
-			  {
-			    location_t loc
-			      = cp_expr_loc_or_loc (TREE_VALUE (t3),
-						    match_loc);
-			    error_at (loc, "score argument must be "
-					   "non-negative");
-			    return NULL_TREE;
-			  }
-			TREE_VALUE (t3) = v;
+			OMP_TP_VALUE (p) = v;
 		      }
 		}
+	      selectors = make_trait_selector (OMP_TS_ID (ts), scoreval,
+					       properties, selectors);
 	    }
+	  OMP_TSS_TRAIT_SELECTORS (tss) = nreverse (selectors);
 	}
       val = tree_cons (varid, ctx, chain);
     }
diff --git a/gcc/fortran/trans-openmp.cc b/gcc/fortran/trans-openmp.cc
index 82bbc41b388..fe8044a57cd 100644
--- a/gcc/fortran/trans-openmp.cc
+++ b/gcc/fortran/trans-openmp.cc
@@ -8210,6 +8210,7 @@ gfc_trans_omp_declare_variant (gfc_namespace *ns)
 	  gfc_omp_selector *os;
 	  for (os = oss->trait_selectors; os; os = os->next)
 	    {
+	      tree scoreval = NULL_TREE;
 	      tree properties = NULL_TREE;
 	      gfc_omp_trait_property *otp;
 
@@ -8223,13 +8224,14 @@ gfc_trans_omp_declare_variant (gfc_namespace *ns)
 			gfc_se se;
 			gfc_init_se (&se, NULL);
 			gfc_conv_expr (&se, otp->expr);
-			properties = tree_cons (NULL_TREE, se.expr,
-						properties);
+			properties = make_trait_property (NULL_TREE, se.expr,
+							  properties);
 		      }
 		      break;
 		    case CTX_PROPERTY_ID:
-		      properties = tree_cons (get_identifier (otp->name),
-					      NULL_TREE, properties);
+		      properties
+			= make_trait_property (get_identifier (otp->name),
+					       NULL_TREE, properties);
 		      break;
 		    case CTX_PROPERTY_NAME_LIST:
 		      {
@@ -8239,7 +8241,8 @@ gfc_trans_omp_declare_variant (gfc_namespace *ns)
 			else
 			  value = gfc_conv_constant_to_tree (otp->expr);
 
-			properties = tree_cons (prop, value, properties);
+			properties = make_trait_property (prop, value,
+							  properties);
 		      }
 		      break;
 		    case CTX_PROPERTY_SIMD:
@@ -8256,17 +8259,17 @@ gfc_trans_omp_declare_variant (gfc_namespace *ns)
 		  gfc_se se;
 		  gfc_init_se (&se, NULL);
 		  gfc_conv_expr (&se, os->score);
-		  properties = tree_cons (get_identifier (" score"),
-					  se.expr, properties);
+		  scoreval = se.expr;
 		}
 
-	      selectors = tree_cons (get_identifier (os->trait_selector_name),
-				     properties, selectors);
+	      tree ts_name = get_identifier (os->trait_selector_name);
+	      selectors	= make_trait_selector (ts_name, scoreval,
+					       properties, selectors);
 	    }
 
-	  set_selectors
-	    = tree_cons (get_identifier (oss->trait_set_selector_name),
-			 selectors, set_selectors);
+	  tree tss_name = get_identifier (oss->trait_set_selector_name);
+	  set_selectors = make_trait_set_selector (tss_name, selectors,
+						   set_selectors);
 	}
 
       const char *variant_proc_name = odv->variant_proc_symtree->name;
diff --git a/gcc/gimplify.cc b/gcc/gimplify.cc
index 77f07af6ec5..757654d5434 100644
--- a/gcc/gimplify.cc
+++ b/gcc/gimplify.cc
@@ -13541,8 +13541,8 @@ omp_construct_selector_matches (enum tree_code *constructs, int nconstructs,
       int variant_nconstructs = 0;
       if (!target_seen)
 	variant_nconstructs
-	  = omp_constructor_traits_to_codes (TREE_VALUE (attr),
-					     variant_constructs);
+	  = omp_construct_traits_to_codes (TREE_VALUE (attr),
+					   variant_constructs);
       for (int i = 0; i < variant_nconstructs; i++)
 	{
 	  ++cnt;
diff --git a/gcc/omp-general.cc b/gcc/omp-general.cc
index b88d5930aab..4ea0d971273 100644
--- a/gcc/omp-general.cc
+++ b/gcc/omp-general.cc
@@ -1017,13 +1017,13 @@ omp_max_simt_vf (void)
    return their number.  */
 
 int
-omp_constructor_traits_to_codes (tree ctx, enum tree_code *constructs)
+omp_construct_traits_to_codes (tree ctx, enum tree_code *constructs)
 {
   int nconstructs = list_length (ctx);
   int i = nconstructs - 1;
-  for (tree t2 = ctx; t2; t2 = TREE_CHAIN (t2), i--)
+  for (tree ts = ctx; ts; ts = TREE_CHAIN (ts), i--)
     {
-      const char *sel = IDENTIFIER_POINTER (TREE_PURPOSE (t2));
+      const char *sel = IDENTIFIER_POINTER (OMP_TS_ID (ts));
       if (!strcmp (sel, "target"))
 	constructs[i] = OMP_TARGET;
       else if (!strcmp (sel, "teams"))
@@ -1125,38 +1125,40 @@ omp_check_context_selector (location_t loc, tree ctx)
      There are just 4 set names.  */
   for (tree t1 = ctx; t1; t1 = TREE_CHAIN (t1))
     for (tree t2 = TREE_CHAIN (t1); t2; t2 = TREE_CHAIN (t2))
-      if (TREE_PURPOSE (t1) == TREE_PURPOSE (t2))
+      if (OMP_TSS_ID (t1) == OMP_TSS_ID (t2))
 	{
 	  error_at (loc, "selector set %qs specified more than once",
-		    IDENTIFIER_POINTER (TREE_PURPOSE (t1)));
+		    IDENTIFIER_POINTER (OMP_TSS_ID (t1)));
 	  return error_mark_node;
 	}
-  for (tree t = ctx; t; t = TREE_CHAIN (t))
+  for (tree tss = ctx; tss; tss = TREE_CHAIN (tss))
     {
       /* Each trait-selector-name can only be specified once.  */
-      if (list_length (TREE_VALUE (t)) < 5)
+      if (list_length (OMP_TSS_TRAIT_SELECTORS (tss)) < 5)
 	{
-	  for (tree t1 = TREE_VALUE (t); t1; t1 = TREE_CHAIN (t1))
-	    for (tree t2 = TREE_CHAIN (t1); t2; t2 = TREE_CHAIN (t2))
-	      if (TREE_PURPOSE (t1) == TREE_PURPOSE (t2))
+	  for (tree ts1 = OMP_TSS_TRAIT_SELECTORS (tss); ts1;
+	       ts1 = TREE_CHAIN (ts1))
+	    for (tree ts2 = TREE_CHAIN (ts1); ts2; ts2 = TREE_CHAIN (ts2))
+	      if (OMP_TS_ID (ts1) == OMP_TS_ID (ts2))
 		{
 		  error_at (loc,
 			    "selector %qs specified more than once in set %qs",
-			    IDENTIFIER_POINTER (TREE_PURPOSE (t1)),
-			    IDENTIFIER_POINTER (TREE_PURPOSE (t)));
+			    IDENTIFIER_POINTER (OMP_TS_ID (ts1)),
+			    IDENTIFIER_POINTER (OMP_TSS_ID (tss)));
 		  return error_mark_node;
 		}
 	}
       else
 	{
 	  hash_set<tree> pset;
-	  for (tree t1 = TREE_VALUE (t); t1; t1 = TREE_CHAIN (t1))
-	    if (pset.add (TREE_PURPOSE (t1)))
+	  for (tree ts = OMP_TSS_TRAIT_SELECTORS (tss); ts;
+	       ts = TREE_CHAIN (ts))
+	    if (pset.add (OMP_TS_ID (ts)))
 	      {
 		error_at (loc,
 			  "selector %qs specified more than once in set %qs",
-			  IDENTIFIER_POINTER (TREE_PURPOSE (t1)),
-			  IDENTIFIER_POINTER (TREE_PURPOSE (t)));
+			  IDENTIFIER_POINTER (OMP_TS_ID (ts)),
+			  IDENTIFIER_POINTER (OMP_TSS_ID (tss)));
 		return error_mark_node;
 	      }
 	}
@@ -1177,49 +1179,45 @@ omp_check_context_selector (location_t loc, tree ctx)
 	{ "implementation", "extension", extension },
 	{ "implementation", "atomic_default_mem_order",
 	  atomic_default_mem_order } };
-      for (tree t1 = TREE_VALUE (t); t1; t1 = TREE_CHAIN (t1))
+      for (tree ts = OMP_TSS_TRAIT_SELECTORS (tss); ts; ts = TREE_CHAIN (ts))
 	for (unsigned i = 0; i < ARRAY_SIZE (props); i++)
-	  if (!strcmp (IDENTIFIER_POINTER (TREE_PURPOSE (t1)),
+	  if (!strcmp (IDENTIFIER_POINTER (OMP_TS_ID (ts)),
 					   props[i].selector)
-	      && !strcmp (IDENTIFIER_POINTER (TREE_PURPOSE (t)),
+	      && !strcmp (IDENTIFIER_POINTER (OMP_TSS_ID (tss)),
 					      props[i].set))
-	    for (tree t2 = TREE_VALUE (t1); t2; t2 = TREE_CHAIN (t2))
+	    for (tree p = OMP_TS_PROPERTIES (ts); p; p = TREE_CHAIN (p))
 	      for (unsigned j = 0; ; j++)
 		{
 		  if (props[i].props[j] == NULL)
 		    {
-		      if (TREE_PURPOSE (t2)
-			  && !strcmp (IDENTIFIER_POINTER (TREE_PURPOSE (t2)),
-				      " score"))
-			break;
 		      if (props[i].props == atomic_default_mem_order)
 			{
 			  error_at (loc,
 				    "incorrect property %qs of %qs selector",
-				    IDENTIFIER_POINTER (TREE_PURPOSE (t2)),
+				    IDENTIFIER_POINTER (TREE_PURPOSE (p)),
 				    "atomic_default_mem_order");
 			  return error_mark_node;
 			}
-		      else if (TREE_PURPOSE (t2))
+		      else if (OMP_TP_NAME (p))
 			warning_at (loc, 0,
 				    "unknown property %qs of %qs selector",
-				    IDENTIFIER_POINTER (TREE_PURPOSE (t2)),
+				    IDENTIFIER_POINTER (OMP_TP_NAME (p)),
 				    props[i].selector);
 		      else
 			warning_at (loc, 0,
 				    "unknown property %qE of %qs selector",
-				    TREE_VALUE (t2), props[i].selector);
+				    OMP_TP_VALUE (p), props[i].selector);
 		      break;
 		    }
-		  else if (TREE_PURPOSE (t2) == NULL_TREE)
+		  else if (OMP_TP_NAME (p) == NULL_TREE)
 		    {
-		      const char *str = TREE_STRING_POINTER (TREE_VALUE (t2));
+		      const char *str = TREE_STRING_POINTER (OMP_TP_VALUE (p));
 		      if (!strcmp (str, props[i].props[j])
-			  && ((size_t) TREE_STRING_LENGTH (TREE_VALUE (t2))
+			  && ((size_t) TREE_STRING_LENGTH (OMP_TP_VALUE (p))
 			      == strlen (str) + (lang_GNU_Fortran () ? 0 : 1)))
 			break;
 		    }
-		  else if (!strcmp (IDENTIFIER_POINTER (TREE_PURPOSE (t2)),
+		  else if (!strcmp (IDENTIFIER_POINTER (OMP_TP_NAME (p)),
 				    props[i].props[j]))
 		    break;
 		}
@@ -1254,18 +1252,43 @@ omp_mark_declare_variant (location_t loc, tree variant, tree construct)
 }
 
 
+/* Constructors for context selectors.  */
+
+tree
+make_trait_set_selector (tree name, tree selectors, tree chain)
+{
+  return tree_cons (name, selectors, chain);
+}
+
+tree
+make_trait_selector (tree name, tree score, tree properties, tree chain)
+{
+  if (score == NULL_TREE)
+    return tree_cons (name, properties, chain);
+  else
+    return tree_cons (name,
+		      tree_cons (OMP_TS_SCORE_NODE, score, properties),
+		      chain);
+}
+
+tree
+make_trait_property (tree name, tree value, tree chain)
+{
+  return tree_cons (name, value, chain);
+}
+
 /* Return a name from PROP, a property in selectors accepting
    name lists.  */
 
 static const char *
 omp_context_name_list_prop (tree prop)
 {
-  if (TREE_PURPOSE (prop))
-    return IDENTIFIER_POINTER (TREE_PURPOSE (prop));
+  if (OMP_TP_NAME (prop))
+    return IDENTIFIER_POINTER (OMP_TP_NAME (prop));
   else
     {
-      const char *ret = TREE_STRING_POINTER (TREE_VALUE (prop));
-      if ((size_t) TREE_STRING_LENGTH (TREE_VALUE (prop))
+      const char *ret = TREE_STRING_POINTER (OMP_TP_VALUE (prop));
+      if ((size_t) TREE_STRING_LENGTH (OMP_TP_VALUE (prop))
 	  == strlen (ret) + (lang_GNU_Fortran () ? 0 : 1))
 	return ret;
       return NULL;
@@ -1282,9 +1305,9 @@ int
 omp_context_selector_matches (tree ctx)
 {
   int ret = 1;
-  for (tree t1 = ctx; t1; t1 = TREE_CHAIN (t1))
+  for (tree tss = ctx; tss; tss = TREE_CHAIN (tss))
     {
-      char set = IDENTIFIER_POINTER (TREE_PURPOSE (t1))[0];
+      char set = IDENTIFIER_POINTER (OMP_TSS_ID (tss))[0];
       if (set == 'c')
 	{
 	  /* For now, ignore the construct set.  While something can be
@@ -1302,7 +1325,8 @@ omp_context_selector_matches (tree ctx)
 
 	  enum tree_code constructs[5];
 	  int nconstructs
-	    = omp_constructor_traits_to_codes (TREE_VALUE (t1), constructs);
+	    = omp_construct_traits_to_codes (OMP_TSS_TRAIT_SELECTORS (tss),
+					     constructs);
 
 	  if (cfun && (cfun->curr_properties & PROP_gimple_any) != 0)
 	    {
@@ -1333,20 +1357,19 @@ omp_context_selector_matches (tree ctx)
 	    ret = -1;
 	  continue;
 	}
-      for (tree t2 = TREE_VALUE (t1); t2; t2 = TREE_CHAIN (t2))
+      for (tree ts = OMP_TSS_TRAIT_SELECTORS (tss); ts; ts = TREE_CHAIN (ts))
 	{
-	  const char *sel = IDENTIFIER_POINTER (TREE_PURPOSE (t2));
+	  const char *sel = IDENTIFIER_POINTER (OMP_TS_ID (ts));
 	  switch (*sel)
 	    {
 	    case 'v':
 	      if (set == 'i' && !strcmp (sel, "vendor"))
-		for (tree t3 = TREE_VALUE (t2); t3; t3 = TREE_CHAIN (t3))
+		for (tree p = OMP_TS_PROPERTIES (ts); p; p = TREE_CHAIN (p))
 		  {
-		    const char *prop = omp_context_name_list_prop (t3);
+		    const char *prop = omp_context_name_list_prop (p);
 		    if (prop == NULL)
 		      return 0;
-		    if ((!strcmp (prop, " score") && TREE_PURPOSE (t3))
-			|| !strcmp (prop, "gnu"))
+		    if (!strcmp (prop, "gnu"))
 		      continue;
 		    return 0;
 		  }
@@ -1377,13 +1400,8 @@ omp_context_selector_matches (tree ctx)
 		      else
 			omo = OMP_MEMORY_ORDER_RELAXED;
 		    }
-		  tree t3 = TREE_VALUE (t2);
-		  const char *prop = IDENTIFIER_POINTER (TREE_PURPOSE (t3));
-		  if (!strcmp (prop, " score"))
-		    {
-		      t3 = TREE_CHAIN (t3);
-		      prop = IDENTIFIER_POINTER (TREE_PURPOSE (t3));
-		    }
+		  tree p = OMP_TS_PROPERTIES (ts);
+		  const char *prop = IDENTIFIER_POINTER (OMP_TP_NAME (p));
 		  if (!strcmp (prop, "relaxed")
 		      && omo != OMP_MEMORY_ORDER_RELAXED)
 		    return 0;
@@ -1395,9 +1413,9 @@ omp_context_selector_matches (tree ctx)
 		    return 0;
 		}
 	      if (set == 'd' && !strcmp (sel, "arch"))
-		for (tree t3 = TREE_VALUE (t2); t3; t3 = TREE_CHAIN (t3))
+		for (tree p = OMP_TS_PROPERTIES (ts); p; p = TREE_CHAIN (p))
 		  {
-		    const char *arch = omp_context_name_list_prop (t3);
+		    const char *arch = omp_context_name_list_prop (p);
 		    if (arch == NULL)
 		      return 0;
 		    int r = 0;
@@ -1497,9 +1515,9 @@ omp_context_selector_matches (tree ctx)
 	      break;
 	    case 'k':
 	      if (set == 'd' && !strcmp (sel, "kind"))
-		for (tree t3 = TREE_VALUE (t2); t3; t3 = TREE_CHAIN (t3))
+		for (tree p = OMP_TS_PROPERTIES (ts); p; p = TREE_CHAIN (p))
 		  {
-		    const char *prop = omp_context_name_list_prop (t3);
+		    const char *prop = omp_context_name_list_prop (p);
 		    if (prop == NULL)
 		      return 0;
 		    if (!strcmp (prop, "any"))
@@ -1558,9 +1576,9 @@ omp_context_selector_matches (tree ctx)
 	      break;
 	    case 'i':
 	      if (set == 'd' && !strcmp (sel, "isa"))
-		for (tree t3 = TREE_VALUE (t2); t3; t3 = TREE_CHAIN (t3))
+		for (tree p = OMP_TS_PROPERTIES (ts); p; p = TREE_CHAIN (p))
 		  {
-		    const char *isa = omp_context_name_list_prop (t3);
+		    const char *isa = omp_context_name_list_prop (p);
 		    if (isa == NULL)
 		      return 0;
 		    int r = 0;
@@ -1611,12 +1629,12 @@ omp_context_selector_matches (tree ctx)
 	      break;
 	    case 'c':
 	      if (set == 'u' && !strcmp (sel, "condition"))
-		for (tree t3 = TREE_VALUE (t2); t3; t3 = TREE_CHAIN (t3))
-		  if (TREE_PURPOSE (t3) == NULL_TREE)
+		for (tree p = OMP_TS_PROPERTIES (ts); p; p = TREE_CHAIN (p))
+		  if (OMP_TP_NAME (p) == NULL_TREE)
 		    {
-		      if (integer_zerop (TREE_VALUE (t3)))
+		      if (integer_zerop (OMP_TP_VALUE (p)))
 			return 0;
-		      if (integer_nonzerop (TREE_VALUE (t3)))
+		      if (integer_nonzerop (OMP_TP_VALUE (p)))
 			break;
 		      ret = -1;
 		    }
@@ -1747,6 +1765,7 @@ omp_construct_simd_compare (tree clauses1, tree clauses2)
 }
 
 /* Compare properties of selectors SEL from SET other than construct.
+   CTX1 and CTX2 are the lists of properties to compare.
    Return 0/-1/1/2 as in omp_context_selector_set_compare.
    Unlike set names or selector names, properties can have duplicates.  */
 
@@ -1756,57 +1775,37 @@ omp_context_selector_props_compare (const char *set, const char *sel,
 {
   int ret = 0;
   for (int pass = 0; pass < 2; pass++)
-    for (tree t1 = pass ? ctx2 : ctx1; t1; t1 = TREE_CHAIN (t1))
+    for (tree p1 = pass ? ctx2 : ctx1; p1; p1 = TREE_CHAIN (p1))
       {
-	tree t2;
-	for (t2 = pass ? ctx1 : ctx2; t2; t2 = TREE_CHAIN (t2))
-	  if (TREE_PURPOSE (t1) == TREE_PURPOSE (t2))
+	tree p2;
+	for (p2 = pass ? ctx1 : ctx2; p2; p2 = TREE_CHAIN (p2))
+	  if (OMP_TP_NAME (p1) == OMP_TP_NAME (p2))
 	    {
-	      if (TREE_PURPOSE (t1) == NULL_TREE)
+	      if (OMP_TP_NAME (p1) == NULL_TREE)
 		{
 		  if (set[0] == 'u' && strcmp (sel, "condition") == 0)
 		    {
-		      if (integer_zerop (TREE_VALUE (t1))
-			  != integer_zerop (TREE_VALUE (t2)))
+		      if (integer_zerop (OMP_TP_VALUE (p1))
+			  != integer_zerop (OMP_TP_VALUE (p2)))
 			return 2;
 		      break;
 		    }
-		  if (simple_cst_equal (TREE_VALUE (t1), TREE_VALUE (t2)))
+		  if (simple_cst_equal (OMP_TP_VALUE (p1), OMP_TP_VALUE (p2)))
 		    break;
 		}
-	      else if (strcmp (IDENTIFIER_POINTER (TREE_PURPOSE (t1)),
-			       " score") == 0)
-		{
-		  if (!simple_cst_equal (TREE_VALUE (t1), TREE_VALUE (t2)))
-		    return 2;
-		  break;
-		}
 	      else
 		break;
 	    }
-	  else if (TREE_PURPOSE (t1)
-		   && TREE_PURPOSE (t2) == NULL_TREE
-		   && TREE_CODE (TREE_VALUE (t2)) == STRING_CST)
-	    {
-	      const char *p1 = omp_context_name_list_prop (t1);
-	      const char *p2 = omp_context_name_list_prop (t2);
-	      if (p2
-		  && strcmp (p1, p2) == 0
-		  && strcmp (p1, " score"))
-		break;
-	    }
-	  else if (TREE_PURPOSE (t1) == NULL_TREE
-		   && TREE_PURPOSE (t2)
-		   && TREE_CODE (TREE_VALUE (t1)) == STRING_CST)
+	  else
 	    {
-	      const char *p1 = omp_context_name_list_prop (t1);
-	      const char *p2 = omp_context_name_list_prop (t2);
-	      if (p1
-		  && strcmp (p1, p2) == 0
-		  && strcmp (p1, " score"))
+	      /* Handle string constant vs identifier comparison for
+		 name-list properties.  */
+	      const char *n1 = omp_context_name_list_prop (p1);
+	      const char *n2 = omp_context_name_list_prop (p2);
+	      if (n1 && n2 && !strcmp (n1, n2))
 		break;
 	    }
-	if (t2 == NULL_TREE)
+	if (p2 == NULL_TREE)
 	  {
 	    int r = pass ? -1 : 1;
 	    if (ret && ret != r)
@@ -1824,6 +1823,7 @@ omp_context_selector_props_compare (const char *set, const char *sel,
 }
 
 /* Compare single context selector sets CTX1 and CTX2 with SET name.
+   CTX1 and CTX2 are lists of trait-selectors.
    Return 0 if CTX1 is equal to CTX2,
    -1 if CTX1 is a strict subset of CTX2,
    1 if CTX2 is a strict subset of CTX1, or
@@ -1845,26 +1845,26 @@ omp_context_selector_set_compare (const char *set, tree ctx1, tree ctx2)
     }
   if (set[0] == 'c')
     {
-      tree t1;
-      tree t2 = ctx2;
+      tree ts1;
+      tree ts2 = ctx2;
       tree simd = get_identifier ("simd");
       /* Handle construct set specially.  In this case the order
 	 of the selector matters too.  */
-      for (t1 = ctx1; t1; t1 = TREE_CHAIN (t1))
-	if (TREE_PURPOSE (t1) == TREE_PURPOSE (t2))
+      for (ts1 = ctx1; ts1; ts1 = TREE_CHAIN (ts1))
+	if (OMP_TS_ID (ts1) == OMP_TS_ID (ts2))
 	  {
 	    int r = 0;
-	    if (TREE_PURPOSE (t1) == simd)
-	      r = omp_construct_simd_compare (TREE_VALUE (t1),
-					      TREE_VALUE (t2));
+	    if (OMP_TS_ID (ts1) == simd)
+	      r = omp_construct_simd_compare (OMP_TS_PROPERTIES (ts1),
+					      OMP_TS_PROPERTIES (ts2));
 	    if (r == 2 || (ret && r && (ret < 0) != (r < 0)))
 	      return 2;
 	    if (ret == 0)
 	      ret = r;
-	    t2 = TREE_CHAIN (t2);
-	    if (t2 == NULL_TREE)
+	    ts2 = TREE_CHAIN (ts2);
+	    if (ts2 == NULL_TREE)
 	      {
-		t1 = TREE_CHAIN (t1);
+		ts1 = TREE_CHAIN (ts1);
 		break;
 	      }
 	  }
@@ -1872,9 +1872,9 @@ omp_context_selector_set_compare (const char *set, tree ctx1, tree ctx2)
 	  return 2;
 	else
 	  ret = 1;
-      if (t2 != NULL_TREE)
+      if (ts2 != NULL_TREE)
 	return 2;
-      if (t1 != NULL_TREE)
+      if (ts1 != NULL_TREE)
 	{
 	  if (ret < 0)
 	    return 2;
@@ -1884,16 +1884,21 @@ omp_context_selector_set_compare (const char *set, tree ctx1, tree ctx2)
 	return 0;
       return swapped ? -ret : ret;
     }
-  for (tree t1 = ctx1; t1; t1 = TREE_CHAIN (t1))
+  for (tree ts1 = ctx1; ts1; ts1 = TREE_CHAIN (ts1))
     {
-      tree t2;
-      for (t2 = ctx2; t2; t2 = TREE_CHAIN (t2))
-	if (TREE_PURPOSE (t1) == TREE_PURPOSE (t2))
+      tree ts2;
+      for (ts2 = ctx2; ts2; ts2 = TREE_CHAIN (ts2))
+	if (OMP_TS_ID (ts1) == OMP_TS_ID (ts2))
 	  {
-	    const char *sel = IDENTIFIER_POINTER (TREE_PURPOSE (t1));
+	    tree score1 = OMP_TS_SCORE (ts1);
+	    tree score2 = OMP_TS_SCORE (ts2);
+	    if (score1 && score2 && !simple_cst_equal (score1, score2))
+	      return 2;
+
+	    const char *sel = IDENTIFIER_POINTER (OMP_TS_ID (ts1));
 	    int r = omp_context_selector_props_compare (set, sel,
-							TREE_VALUE (t1),
-							TREE_VALUE (t2));
+							OMP_TS_PROPERTIES (ts1),
+							OMP_TS_PROPERTIES (ts2));
 	    if (r == 2 || (ret && r && (ret < 0) != (r < 0)))
 	      return 2;
 	    if (ret == 0)
@@ -1901,7 +1906,7 @@ omp_context_selector_set_compare (const char *set, tree ctx1, tree ctx2)
 	    cnt++;
 	    break;
 	  }
-      if (t2 == NULL_TREE)
+      if (ts2 == NULL_TREE)
 	{
 	  if (ret == -1)
 	    return 2;
@@ -1935,15 +1940,17 @@ omp_context_selector_compare (tree ctx1, tree ctx2)
       std::swap (ctx1, ctx2);
       std::swap (len1, len2);
     }
-  for (tree t1 = ctx1; t1; t1 = TREE_CHAIN (t1))
+  for (tree tss1 = ctx1; tss1; tss1 = TREE_CHAIN (tss1))
     {
-      tree t2;
-      for (t2 = ctx2; t2; t2 = TREE_CHAIN (t2))
-	if (TREE_PURPOSE (t1) == TREE_PURPOSE (t2))
+      tree tss2;
+      for (tss2 = ctx2; tss2; tss2 = TREE_CHAIN (tss2))
+	if (OMP_TSS_ID (tss1) == OMP_TSS_ID (tss2))
 	  {
-	    const char *set = IDENTIFIER_POINTER (TREE_PURPOSE (t1));
-	    int r = omp_context_selector_set_compare (set, TREE_VALUE (t1),
-						      TREE_VALUE (t2));
+	    const char *set = IDENTIFIER_POINTER (OMP_TSS_ID (tss1));
+	    int r
+	      = omp_context_selector_set_compare
+		  (set, OMP_TSS_TRAIT_SELECTORS (tss1),
+		   OMP_TSS_TRAIT_SELECTORS (tss2));
 	    if (r == 2 || (ret && r && (ret < 0) != (r < 0)))
 	      return 2;
 	    if (ret == 0)
@@ -1951,7 +1958,7 @@ omp_context_selector_compare (tree ctx1, tree ctx2)
 	    cnt++;
 	    break;
 	  }
-      if (t2 == NULL_TREE)
+      if (tss2 == NULL_TREE)
 	{
 	  if (ret == -1)
 	    return 2;
@@ -1974,14 +1981,14 @@ omp_get_context_selector (tree ctx, const char *set, const char *sel)
 {
   tree setid = get_identifier (set);
   tree selid = sel ? get_identifier (sel) : NULL_TREE;
-  for (tree t1 = ctx; t1; t1 = TREE_CHAIN (t1))
-    if (TREE_PURPOSE (t1) == setid)
+  for (tree tss = ctx; tss; tss = TREE_CHAIN (tss))
+    if (OMP_TSS_ID (tss) == setid)
       {
 	if (sel == NULL)
-	  return TREE_VALUE (t1);
-	for (tree t2 = TREE_VALUE (t1); t2; t2 = TREE_CHAIN (t2))
-	  if (TREE_PURPOSE (t2) == selid)
-	    return t2;
+	  return OMP_TSS_TRAIT_SELECTORS (tss);
+	for (tree ts = OMP_TSS_TRAIT_SELECTORS (tss); ts; ts = TREE_CHAIN (ts))
+	  if (OMP_TS_ID (ts) == selid)
+	    return ts;
       }
   return NULL_TREE;
 }
@@ -2004,25 +2011,23 @@ omp_context_compute_score (tree ctx, score_wide_int *score, bool declare_simd)
   bool has_isa = omp_get_context_selector (ctx, "device", "isa");
   bool ret = false;
   *score = 1;
-  for (tree t1 = ctx; t1; t1 = TREE_CHAIN (t1))
-    if (TREE_VALUE (t1) != construct)
-      for (tree t2 = TREE_VALUE (t1); t2; t2 = TREE_CHAIN (t2))
-	if (tree t3 = TREE_VALUE (t2))
-	  if (TREE_PURPOSE (t3)
-	      && strcmp (IDENTIFIER_POINTER (TREE_PURPOSE (t3)), " score") == 0
-	      && TREE_CODE (TREE_VALUE (t3)) == INTEGER_CST)
-	    {
-	      tree t4 = TREE_VALUE (t3);
-	      *score += score_wide_int::from (wi::to_wide (t4),
-					      TYPE_SIGN (TREE_TYPE (t4)));
-	    }
+  for (tree tss = ctx; tss; tss = TREE_CHAIN (tss))
+    if (OMP_TSS_TRAIT_SELECTORS (tss) != construct)
+      for (tree ts = OMP_TSS_TRAIT_SELECTORS (tss); ts; ts = TREE_CHAIN (ts))
+	{
+	  tree s = OMP_TS_SCORE (ts);
+	  if (s && TREE_CODE (s) == INTEGER_CST)
+	    *score += score_wide_int::from (wi::to_wide (s),
+					    TYPE_SIGN (TREE_TYPE (s)));
+	}
+
   if (construct || has_kind || has_arch || has_isa)
     {
       int scores[12];
       enum tree_code constructs[5];
       int nconstructs = 0;
       if (construct)
-	nconstructs = omp_constructor_traits_to_codes (construct, constructs);
+	nconstructs = omp_construct_traits_to_codes (construct, constructs);
       if (omp_construct_selector_matches (constructs, nconstructs, scores)
 	  == 2)
 	ret = true;
diff --git a/gcc/omp-general.h b/gcc/omp-general.h
index 1a52bfdb56b..28a9c0e6e17 100644
--- a/gcc/omp-general.h
+++ b/gcc/omp-general.h
@@ -92,6 +92,52 @@ struct omp_for_data
 
 #define OACC_FN_ATTRIB "oacc function"
 
+/* Accessors for OMP context selectors, used by variant directives.
+   These are represented internally by a multilevel TREE_LIST structure, but
+   these accessors should be used to avoid confusion.  The grammar is:
+
+   context-set-selector-specification:
+     trait-set-selector [, trait-set-selector [, ...]]
+   trait-set-selector:
+     trait-set-selector-name = { trait-selector [, trait-selector [, ... ]] }
+   trait-selector:
+     trait-selector-name [ ( [trait-score: ]
+			     trait-property [, trait-property  [, ...]] ) ]
+
+   trait-properties can variously be identifiers, strings, clauses, or
+   expressions.
+
+   All the lists are chained via TREE_CHAIN.  If a score is present, it is
+   internally tacked on to the properties with a TREE_PURPOSE of
+   OMP_TS_SCORE_NODE.  */
+
+#define OMP_TS_SCORE_NODE integer_minus_one_node
+
+#define OMP_TSS_ID(NODE) \
+  TREE_PURPOSE (NODE)
+#define OMP_TSS_TRAIT_SELECTORS(NODE) \
+  TREE_VALUE (NODE)
+#define OMP_TS_ID(NODE) \
+  TREE_PURPOSE (NODE)
+#define OMP_TS_SCORE(NODE) \
+  ((TREE_VALUE (NODE)					      \
+    && TREE_CODE (TREE_VALUE (NODE)) == TREE_LIST	      \
+    && TREE_PURPOSE (TREE_VALUE (NODE)) == OMP_TS_SCORE_NODE) \
+   ? TREE_VALUE (TREE_VALUE (NODE)) : NULL_TREE)
+#define OMP_TS_PROPERTIES(NODE) \
+  ((TREE_VALUE (NODE)					      \
+    && TREE_CODE (TREE_VALUE (NODE)) == TREE_LIST	      \
+    && TREE_PURPOSE (TREE_VALUE (NODE)) == OMP_TS_SCORE_NODE) \
+   ? TREE_CHAIN (TREE_VALUE (NODE)) : TREE_VALUE (NODE))
+#define OMP_TP_NAME(NODE) \
+  TREE_PURPOSE (NODE)
+#define OMP_TP_VALUE(NODE) \
+  TREE_VALUE (NODE)
+
+extern tree make_trait_set_selector (tree, tree, tree);
+extern tree make_trait_selector (tree, tree, tree, tree);
+extern tree make_trait_property (tree, tree, tree);
+
 extern tree omp_find_clause (tree clauses, enum omp_clause_code kind);
 extern bool omp_is_allocatable_or_ptr (tree decl);
 extern tree omp_check_optional_argument (tree decl, bool for_present_check);
@@ -106,7 +152,7 @@ extern gimple *omp_build_barrier (tree lhs);
 extern tree find_combined_omp_for (tree *, int *, void *);
 extern poly_uint64 omp_max_vf (void);
 extern int omp_max_simt_vf (void);
-extern int omp_constructor_traits_to_codes (tree, enum tree_code *);
+extern int omp_construct_traits_to_codes (tree, enum tree_code *);
 extern tree omp_check_context_selector (location_t loc, tree ctx);
 extern void omp_mark_declare_variant (location_t loc, tree variant,
 				      tree construct);
-- 
2.31.1


^ permalink raw reply	[flat|nested] 9+ messages in thread

* [PATCH 2/3] OpenMP: Unify representation of name-list properties.
  2023-11-19  9:21 [PATCH 0/3] OpenMP: Improve data abstractions for context selectors Sandra Loosemore
  2023-11-19  9:21 ` [PATCH 1/3] OpenMP: Introduce accessor macros and constructors " Sandra Loosemore
@ 2023-11-19  9:21 ` Sandra Loosemore
  2023-11-19  9:21 ` [PATCH 3/3] OpenMP: Use enumerators for names of trait-sets and traits Sandra Loosemore
                   ` (2 subsequent siblings)
  4 siblings, 0 replies; 9+ messages in thread
From: Sandra Loosemore @ 2023-11-19  9:21 UTC (permalink / raw)
  To: gcc-patches; +Cc: jakub, tobias

Previously, name-list properties specified as identifiers were stored
in the TREE_PURPOSE/OMP_TP_NAME slot, while those specified as strings
were stored in the TREE_VALUE/OMP_TP_VALUE slot.  This patch puts both
representations in OMP_TP_VALUE with a magic cookie in OMP_TP_NAME.

gcc/ChangeLog
	* omp-general.h (OMP_TP_NAMELIST_NODE): New.
	* omp-general.cc (omp_context_name_list_prop): Move earlier
	in the file, and adjust for new representation.
	(omp_check_context_selector): Adjust this too.
	(omp_context_selector_props_compare): Likewise.

gcc/c/ChangeLog
	* c-parser.cc (c_parser_omp_context_selector): Adjust for new
	namelist property representation.

gcc/cp/ChangeLog
	* parser.cc (cp_parser_omp_context_selector): Adjust for new
	namelist property representation.
	* pt.cc (tsubst_attribute): Likewise.

gcc/fortran/ChangeLog
	* trans-openmp.cc (gfc_trans_omp_declare_varaint): Adjust for
	new namelist property representation.
---
 gcc/c/c-parser.cc           |  5 ++-
 gcc/cp/parser.cc            |  5 ++-
 gcc/cp/pt.cc                |  4 +-
 gcc/fortran/trans-openmp.cc |  5 ++-
 gcc/omp-general.cc          | 84 +++++++++++++++++++++----------------
 gcc/omp-general.h           |  1 +
 6 files changed, 61 insertions(+), 43 deletions(-)

diff --git a/gcc/c/c-parser.cc b/gcc/c/c-parser.cc
index fcbacd461c7..a2ff381e0c1 100644
--- a/gcc/c/c-parser.cc
+++ b/gcc/c/c-parser.cc
@@ -24217,11 +24217,12 @@ c_parser_omp_context_selector (c_parser *parser, tree set, tree parms)
 	    case CTX_PROPERTY_NAME_LIST:
 	      do
 		{
-		  tree prop = NULL_TREE, value = NULL_TREE;
+		  tree prop = OMP_TP_NAMELIST_NODE;
+		  tree value = NULL_TREE;
 		  if (c_parser_next_token_is (parser, CPP_KEYWORD)
 		      || c_parser_next_token_is (parser, CPP_NAME))
 		    {
-		      prop = c_parser_peek_token (parser)->value;
+		      value = c_parser_peek_token (parser)->value;
 		      c_parser_consume_token (parser);
 		    }
 		  else if (c_parser_next_token_is (parser, CPP_STRING))
diff --git a/gcc/cp/parser.cc b/gcc/cp/parser.cc
index dd773570981..9030365644d 100644
--- a/gcc/cp/parser.cc
+++ b/gcc/cp/parser.cc
@@ -47469,11 +47469,12 @@ cp_parser_omp_context_selector (cp_parser *parser, tree set, bool has_parms_p)
 	    case CTX_PROPERTY_NAME_LIST:
 	      do
 		{
-		  tree prop = NULL_TREE, value = NULL_TREE;
+		  tree prop = OMP_TP_NAMELIST_NODE;
+		  tree value = NULL_TREE;
 		  if (cp_lexer_next_token_is (parser->lexer, CPP_KEYWORD)
 		      || cp_lexer_next_token_is (parser->lexer, CPP_NAME))
 		    {
-		      prop = cp_lexer_peek_token (parser->lexer)->u.value;
+		      value = cp_lexer_peek_token (parser->lexer)->u.value;
 		      cp_lexer_consume_token (parser->lexer);
 		    }
 		  else if (cp_lexer_next_token_is (parser->lexer, CPP_STRING))
diff --git a/gcc/cp/pt.cc b/gcc/cp/pt.cc
index 3af793dfe20..c3815733651 100644
--- a/gcc/cp/pt.cc
+++ b/gcc/cp/pt.cc
@@ -11892,7 +11892,9 @@ tsubst_attribute (tree t, tree *decl_p, tree args,
 		    }
 		  properties = copy_list (OMP_TS_PROPERTIES (ts));
 		  for (tree p = properties; p; p = TREE_CHAIN (p))
-		    if (OMP_TP_VALUE (p))
+		    if (OMP_TP_NAME (p) == OMP_TP_NAMELIST_NODE)
+		      continue;
+		    else if (OMP_TP_VALUE (p))
 		      {
 			bool allow_string
 			  = (OMP_TS_ID (ts) != condition || set[0] != 'u');
diff --git a/gcc/fortran/trans-openmp.cc b/gcc/fortran/trans-openmp.cc
index fe8044a57cd..60154ff3751 100644
--- a/gcc/fortran/trans-openmp.cc
+++ b/gcc/fortran/trans-openmp.cc
@@ -8235,9 +8235,10 @@ gfc_trans_omp_declare_variant (gfc_namespace *ns)
 		      break;
 		    case CTX_PROPERTY_NAME_LIST:
 		      {
-			tree prop = NULL_TREE, value = NULL_TREE;
+			tree prop = OMP_TP_NAMELIST_NODE;
+			tree value = NULL_TREE;
 			if (otp->is_name)
-			  prop = get_identifier (otp->name);
+			  value = get_identifier (otp->name);
 			else
 			  value = gfc_conv_constant_to_tree (otp->expr);
 
diff --git a/gcc/omp-general.cc b/gcc/omp-general.cc
index 4ea0d971273..e4e3890449e 100644
--- a/gcc/omp-general.cc
+++ b/gcc/omp-general.cc
@@ -1114,6 +1114,30 @@ omp_maybe_offloaded (void)
   return false;
 }
 
+/* Return a name from PROP, a property in selectors accepting
+   name lists.  */
+
+static const char *
+omp_context_name_list_prop (tree prop)
+{
+  gcc_assert (OMP_TP_NAME (prop) == OMP_TP_NAMELIST_NODE);
+  tree val = OMP_TP_VALUE (prop);
+  switch (TREE_CODE (val))
+    {
+    case IDENTIFIER_NODE:
+      return IDENTIFIER_POINTER (val);
+    case STRING_CST:
+      {
+	const char *ret = TREE_STRING_POINTER (val);
+	if ((size_t) TREE_STRING_LENGTH (val)
+	    == strlen (ret) + (lang_GNU_Fortran () ? 0 : 1))
+	  return ret;
+	return NULL;
+      }
+    default:
+      return NULL;
+    }
+}
 
 /* Diagnose errors in an OpenMP context selector, return CTX if
    it is correct or error_mark_node otherwise.  */
@@ -1198,23 +1222,29 @@ omp_check_context_selector (location_t loc, tree ctx)
 				    "atomic_default_mem_order");
 			  return error_mark_node;
 			}
+		      else if (OMP_TP_NAME (p) == OMP_TP_NAMELIST_NODE
+			       && (TREE_CODE (OMP_TP_VALUE (p)) == STRING_CST))
+			warning_at (loc, 0,
+				    "unknown property %qE of %qs selector",
+				    OMP_TP_VALUE (p),
+				    props[i].selector);
+		      else if (OMP_TP_NAME (p) == OMP_TP_NAMELIST_NODE)
+			warning_at (loc, 0,
+				    "unknown property %qs of %qs selector",
+				    omp_context_name_list_prop (p),
+				    props[i].selector);
 		      else if (OMP_TP_NAME (p))
 			warning_at (loc, 0,
 				    "unknown property %qs of %qs selector",
 				    IDENTIFIER_POINTER (OMP_TP_NAME (p)),
 				    props[i].selector);
-		      else
-			warning_at (loc, 0,
-				    "unknown property %qE of %qs selector",
-				    OMP_TP_VALUE (p), props[i].selector);
 		      break;
 		    }
-		  else if (OMP_TP_NAME (p) == NULL_TREE)
+		  else if (OMP_TP_NAME (p) == OMP_TP_NAMELIST_NODE)
+		    /* Property-list traits.  */
 		    {
-		      const char *str = TREE_STRING_POINTER (OMP_TP_VALUE (p));
-		      if (!strcmp (str, props[i].props[j])
-			  && ((size_t) TREE_STRING_LENGTH (OMP_TP_VALUE (p))
-			      == strlen (str) + (lang_GNU_Fortran () ? 0 : 1)))
+		      const char *str = omp_context_name_list_prop (p);
+		      if (str && !strcmp (str, props[i].props[j]))
 			break;
 		    }
 		  else if (!strcmp (IDENTIFIER_POINTER (OMP_TP_NAME (p)),
@@ -1277,24 +1307,6 @@ make_trait_property (tree name, tree value, tree chain)
   return tree_cons (name, value, chain);
 }
 
-/* Return a name from PROP, a property in selectors accepting
-   name lists.  */
-
-static const char *
-omp_context_name_list_prop (tree prop)
-{
-  if (OMP_TP_NAME (prop))
-    return IDENTIFIER_POINTER (OMP_TP_NAME (prop));
-  else
-    {
-      const char *ret = TREE_STRING_POINTER (OMP_TP_VALUE (prop));
-      if ((size_t) TREE_STRING_LENGTH (OMP_TP_VALUE (prop))
-	  == strlen (ret) + (lang_GNU_Fortran () ? 0 : 1))
-	return ret;
-      return NULL;
-    }
-}
-
 /* Return 1 if context selector matches the current OpenMP context, 0
    if it does not and -1 if it is unknown and need to be determined later.
    Some properties can be checked right away during parsing (this routine),
@@ -1793,18 +1805,18 @@ omp_context_selector_props_compare (const char *set, const char *sel,
 		  if (simple_cst_equal (OMP_TP_VALUE (p1), OMP_TP_VALUE (p2)))
 		    break;
 		}
+	      else if (OMP_TP_NAME (p1) == OMP_TP_NAMELIST_NODE)
+		{
+		  /* Handle string constant vs identifier comparison for
+		     name-list properties.  */
+		  const char *n1 = omp_context_name_list_prop (p1);
+		  const char *n2 = omp_context_name_list_prop (p2);
+		  if (n1 && n2 && !strcmp (n1, n2))
+		    break;
+		}
 	      else
 		break;
 	    }
-	  else
-	    {
-	      /* Handle string constant vs identifier comparison for
-		 name-list properties.  */
-	      const char *n1 = omp_context_name_list_prop (p1);
-	      const char *n2 = omp_context_name_list_prop (p2);
-	      if (n1 && n2 && !strcmp (n1, n2))
-		break;
-	    }
 	if (p2 == NULL_TREE)
 	  {
 	    int r = pass ? -1 : 1;
diff --git a/gcc/omp-general.h b/gcc/omp-general.h
index 28a9c0e6e17..dc5e5f6ba1f 100644
--- a/gcc/omp-general.h
+++ b/gcc/omp-general.h
@@ -112,6 +112,7 @@ struct omp_for_data
    OMP_TS_SCORE_NODE.  */
 
 #define OMP_TS_SCORE_NODE integer_minus_one_node
+#define OMP_TP_NAMELIST_NODE integer_one_node
 
 #define OMP_TSS_ID(NODE) \
   TREE_PURPOSE (NODE)
-- 
2.31.1


^ permalink raw reply	[flat|nested] 9+ messages in thread

* [PATCH 3/3] OpenMP: Use enumerators for names of trait-sets and traits
  2023-11-19  9:21 [PATCH 0/3] OpenMP: Improve data abstractions for context selectors Sandra Loosemore
  2023-11-19  9:21 ` [PATCH 1/3] OpenMP: Introduce accessor macros and constructors " Sandra Loosemore
  2023-11-19  9:21 ` [PATCH 2/3] OpenMP: Unify representation of name-list properties Sandra Loosemore
@ 2023-11-19  9:21 ` Sandra Loosemore
  2023-11-21 20:48   ` Sandra Loosemore
  2023-11-20 10:32 ` [PATCH 0/3] OpenMP: Improve data abstractions for context selectors Julian Brown
  2023-11-22 16:22 ` [PATCH V2 3/3] OpenMP: Use enumerators for names of trait-sets and traits Sandra Loosemore
  4 siblings, 1 reply; 9+ messages in thread
From: Sandra Loosemore @ 2023-11-19  9:21 UTC (permalink / raw)
  To: gcc-patches; +Cc: jakub, tobias

This patch introduces enumerators to represent trait-set names and
trait names, which makes it easier to use tables to control other
behavior and for switch statements to dispatch on the tags.  The tags
are stored in the same place in the TREE_LIST structure (OMP_TSS_ID or
OMP_TS_ID) and are encoded there as integer constants.

This patch has only been lightly tested and still has at least one bug
that causes an ICE.  :-(

gcc/ChangeLog
	* omp-general.h (enum omp_tss_code): New.
	(enum omp_ts_code): New.
	(enum omp_tp_type): New.
	(omp_tss_map): New.
	(struct omp_ts_info): New.
	(omp_ts_map): New.
	(OMP_TSS_CODE, OMP_TSS_NAME): New.
	(OMP_TS_CODE, OMP_TS_NAME): New.
	(make_trait_set_selector, make_trait_selector): Adjust declarations.
	(omp_context_selector_set_compare): Likewise.
	(omp_get_context_selector): Likewise.
	(omp_get_context_selector_list): New.
	(omp_lookup_tss_code): New.
	(omp_lookup_ts_code): New.
	* omp-general.cc (omp_construct_traits_to_codes): Make it
	table-driven.
	(omp_tss_map): New.
	(kind_properties, vendor_properties, extension_properties): New.
	(atomic_default_mem_order_properties): New.
	(omp_ts_map): New.
	(omp_check_context_selector): Simplify lookup and dispatch logic.
	(omp_mark_declare_variant): Adjust for new representation.
	(make_trait_set_selector, make_trait_selector): Adjust for new
	representations.
	(omp_context_selector_matches): Simplify dispatch logic, also
	avoid fix-sized buffers.
	(omp_context_selector_props_compare): Adjust for new representations
	and simplify dispatch logic.
	(omp_context_selector_set_compare): Likewise.
	(omp_context_selector_compare): Likewise.
	(omp_get_context_selector): Adjust for new representations, and split
	out...
	(omp_get_context_selector_list): New function.
	(omp_lookup_tss_code): New.
	(omp_lookup_ts_code): New.
	(omp_context_compute_score): Adjust for new representations.  Avoid
	fixed-sized buffers and magic numbers.

gcc/c/ChangeLog
	* c-parser.cc (omp_construct_selectors): Delete.
	(omp_device_selectors): Delete.
	(omp_implementation_selectors): Delete.
	(omp_user_selectors): Delete.
	(c_parser_omp_context_selector): Adjust for new representations
	and simplify dispatch logic.
	(c_parser_omp_context_selector_specification): Likewise.
	(c_finish_omp_declare_variant): Adjust for new representations.

gcc/cp/ChangeLog
	* decl.cc (omp_declare_variant_finalize_one): Adjust for new
	representations.
	* parser.cc (omp_construct_selectors): Delete.
	(omp_device_selectors): Delete.
	(omp_implementation_selectors): Delete.
	(omp_user_selectors): Delete.
	(cp_parser_omp_context_selector): Adjust for new representations
	and simplify dispatch logic.
	(cp_parser_omp_context_selector_specification): Likewise.
	* pt.cc (tsubst_attribute): Adjust for new representations.

gcc/fortran/ChangeLog
	* trans-openmp.cc (gfc_trans_omp_declare_variant): Adjust for
	new representations.
---
 gcc/c/c-parser.cc           | 192 ++++----------
 gcc/cp/decl.cc              |   8 +-
 gcc/cp/parser.cc            | 189 ++++----------
 gcc/cp/pt.cc                |  15 +-
 gcc/fortran/trans-openmp.cc |  41 ++-
 gcc/omp-general.cc          | 496 +++++++++++++++++++++++-------------
 gcc/omp-general.h           |  87 ++++++-
 7 files changed, 555 insertions(+), 473 deletions(-)

diff --git a/gcc/c/c-parser.cc b/gcc/c/c-parser.cc
index a2ff381e0c1..70c0e1828ca 100644
--- a/gcc/c/c-parser.cc
+++ b/gcc/c/c-parser.cc
@@ -24016,16 +24016,6 @@ c_parser_omp_declare_simd (c_parser *parser, enum pragma_context context)
     }
 }
 
-static const char *const omp_construct_selectors[] = {
-  "simd", "target", "teams", "parallel", "for", NULL };
-static const char *const omp_device_selectors[] = {
-  "kind", "isa", "arch", NULL };
-static const char *const omp_implementation_selectors[] = {
-  "vendor", "extension", "atomic_default_mem_order", "unified_address",
-  "unified_shared_memory", "dynamic_allocators", "reverse_offload", NULL };
-static const char *const omp_user_selectors[] = {
-  "condition", NULL };
-
 /* OpenMP 5.0:
 
    trait-selector:
@@ -24038,7 +24028,8 @@ static const char *const omp_user_selectors[] = {
    trait-selector-set SET.  */
 
 static tree
-c_parser_omp_context_selector (c_parser *parser, tree set, tree parms)
+c_parser_omp_context_selector (c_parser *parser, enum omp_tss_code set,
+			       tree parms)
 {
   tree ret = NULL_TREE;
   do
@@ -24052,80 +24043,52 @@ c_parser_omp_context_selector (c_parser *parser, tree set, tree parms)
 	  c_parser_error (parser, "expected trait selector name");
 	  return error_mark_node;
 	}
+      enum omp_ts_code sel
+	= omp_lookup_ts_code (set, IDENTIFIER_POINTER (selector));
 
-      tree properties = NULL_TREE;
-      tree scoreval = NULL_TREE;
-      const char *const *selectors = NULL;
-      bool allow_score = true;
-      bool allow_user = false;
-      int property_limit = 0;
-      enum { CTX_PROPERTY_NONE, CTX_PROPERTY_USER, CTX_PROPERTY_NAME_LIST,
-	     CTX_PROPERTY_ID, CTX_PROPERTY_EXPR,
-	     CTX_PROPERTY_SIMD } property_kind = CTX_PROPERTY_NONE;
-      switch (IDENTIFIER_POINTER (set)[0])
-	{
-	case 'c': /* construct */
-	  selectors = omp_construct_selectors;
-	  allow_score = false;
-	  property_limit = 1;
-	  property_kind = CTX_PROPERTY_SIMD;
-	  break;
-	case 'd': /* device */
-	  selectors = omp_device_selectors;
-	  allow_score = false;
-	  allow_user = true;
-	  property_limit = 3;
-	  property_kind = CTX_PROPERTY_NAME_LIST;
-	  break;
-	case 'i': /* implementation */
-	  selectors = omp_implementation_selectors;
-	  allow_user = true;
-	  property_limit = 3;
-	  property_kind = CTX_PROPERTY_NAME_LIST;
-	  break;
-	case 'u': /* user */
-	  selectors = omp_user_selectors;
-	  property_limit = 1;
-	  property_kind = CTX_PROPERTY_EXPR;
-	  break;
-	default:
-	  gcc_unreachable ();
-	}
-      for (int i = 0; ; i++)
+      if (sel == OMP_TRAIT_INVALID)
 	{
-	  if (selectors[i] == NULL)
+	  /* Some trait sets permit extension traits which are supposed
+	     to be ignored if the implementation doesn't support them.
+	     GCC does not support any extension traits, and if it did, they
+	     would have their own identifiers.  */
+	  if (set == OMP_TRAIT_SET_IMPLEMENTATION
+	      || set == OMP_TRAIT_SET_DEVICE
+	      || set == OMP_TRAIT_SET_TARGET_DEVICE)
 	    {
-	      if (allow_user)
-		{
-		  property_kind = CTX_PROPERTY_USER;
-		  break;
-		}
-	      else
+	      c_parser_consume_token (parser);
+	      if (c_parser_next_token_is (parser, CPP_OPEN_PAREN))
+		c_parser_balanced_token_sequence (parser);
+	      if (c_parser_next_token_is (parser, CPP_COMMA))
 		{
-		  error_at (c_parser_peek_token (parser)->location,
-			    "selector %qs not allowed for context selector "
-			    "set %qs", IDENTIFIER_POINTER (selector),
-			    IDENTIFIER_POINTER (set));
 		  c_parser_consume_token (parser);
-		  return error_mark_node;
+		  continue;
 		}
+	      else
+		break;
+	    }
+	  else
+	    {
+	      error_at (c_parser_peek_token (parser)->location,
+			"selector %qs not allowed for context selector "
+			"set %qs", IDENTIFIER_POINTER (selector),
+			omp_tss_map[set]);
+	      c_parser_consume_token (parser);
+	      return error_mark_node;
 	    }
-	  if (i == property_limit)
-	    property_kind = CTX_PROPERTY_NONE;
-	  if (strcmp (selectors[i], IDENTIFIER_POINTER (selector)) == 0)
-	    break;
 	}
-      if (property_kind == CTX_PROPERTY_NAME_LIST
-	  && IDENTIFIER_POINTER (set)[0] == 'i'
-	  && strcmp (IDENTIFIER_POINTER (selector),
-		     "atomic_default_mem_order") == 0)
-	property_kind = CTX_PROPERTY_ID;
 
       c_parser_consume_token (parser);
 
+      tree properties = NULL_TREE;
+      tree scoreval = NULL_TREE;
+      enum omp_tp_type property_kind = omp_ts_map[sel].tp_type;
+      bool allow_score = omp_ts_map[sel].allow_score;
+      tree t;
+
       if (c_parser_next_token_is (parser, CPP_OPEN_PAREN))
 	{
-	  if (property_kind == CTX_PROPERTY_NONE)
+	  if (property_kind == OMP_TRAIT_PROPERTY_NONE)
 	    {
 	      error_at (c_parser_peek_token (parser)->location,
 			"selector %qs does not accept any properties",
@@ -24168,38 +24131,7 @@ c_parser_omp_context_selector (c_parser *parser, tree set, tree parms)
 
 	  switch (property_kind)
 	    {
-	      tree t;
-	    case CTX_PROPERTY_USER:
-	      do
-		{
-		  t = c_parser_expr_no_commas (parser, NULL).value;
-		  if (TREE_CODE (t) == STRING_CST)
-		    properties = make_trait_property (NULL_TREE, t,
-						      properties);
-		  else if (t != error_mark_node)
-		    {
-		      mark_exp_read (t);
-		      t = c_fully_fold (t, false, NULL);
-		      if (!INTEGRAL_TYPE_P (TREE_TYPE (t))
-			  || !tree_fits_shwi_p (t))
-			error_at (token->location, "property must be "
-				  "constant integer expression or string "
-				  "literal");
-		      else
-			properties = make_trait_property (NULL_TREE, t,
-							  properties);
-		    }
-		  else
-		    return error_mark_node;
-
-		  if (c_parser_next_token_is (parser, CPP_COMMA))
-		    c_parser_consume_token (parser);
-		  else
-		    break;
-		}
-	      while (1);
-	      break;
-	    case CTX_PROPERTY_ID:
+	    case OMP_TRAIT_PROPERTY_ID:
 	      if (c_parser_next_token_is (parser, CPP_KEYWORD)
 		  || c_parser_next_token_is (parser, CPP_NAME))
 		{
@@ -24214,7 +24146,7 @@ c_parser_omp_context_selector (c_parser *parser, tree set, tree parms)
 		  return error_mark_node;
 		}
 	      break;
-	    case CTX_PROPERTY_NAME_LIST:
+	    case OMP_TRAIT_PROPERTY_NAME_LIST:
 	      do
 		{
 		  tree prop = OMP_TP_NAMELIST_NODE;
@@ -24244,12 +24176,14 @@ c_parser_omp_context_selector (c_parser *parser, tree set, tree parms)
 		}
 	      while (1);
 	      break;
-	    case CTX_PROPERTY_EXPR:
+	    case OMP_TRAIT_PROPERTY_EXPR:
 	      t = c_parser_expr_no_commas (parser, NULL).value;
 	      if (t != error_mark_node)
 		{
 		  mark_exp_read (t);
 		  t = c_fully_fold (t, false, NULL);
+		  /* FIXME: this is bogus, both device_num and
+		     condition selectors allow arbitrary expressions.  */
 		  if (!INTEGRAL_TYPE_P (TREE_TYPE (t))
 		      || !tree_fits_shwi_p (t))
 		    error_at (token->location, "property must be "
@@ -24261,7 +24195,9 @@ c_parser_omp_context_selector (c_parser *parser, tree set, tree parms)
 	      else
 		return error_mark_node;
 	      break;
-	    case CTX_PROPERTY_SIMD:
+	    case OMP_TRAIT_PROPERTY_CLAUSE_LIST:
+	      gcc_assert (sel == OMP_TRAIT_CONSTRUCT_SIMD);
+
 	      if (parms == NULL_TREE)
 		{
 		  error_at (token->location, "properties for %<simd%> "
@@ -24286,15 +24222,15 @@ c_parser_omp_context_selector (c_parser *parser, tree set, tree parms)
 	  parens.skip_until_found_close (parser);
 	  properties = nreverse (properties);
 	}
-      else if (property_kind == CTX_PROPERTY_NAME_LIST
-	       || property_kind == CTX_PROPERTY_ID
-	       || property_kind == CTX_PROPERTY_EXPR)
+      else if (property_kind != OMP_TRAIT_PROPERTY_NONE
+	       && property_kind != OMP_TRAIT_PROPERTY_CLAUSE_LIST
+	       && property_kind != OMP_TRAIT_PROPERTY_EXTENSION)
 	{
 	  c_parser_require (parser, CPP_OPEN_PAREN, "expected %<(%>");
 	  return error_mark_node;
 	}
 
-      ret = make_trait_selector (selector, scoreval, properties, ret);
+      ret = make_trait_selector (sel, scoreval, properties, ret);
 
       if (c_parser_next_token_is (parser, CPP_COMMA))
 	c_parser_consume_token (parser);
@@ -24328,35 +24264,17 @@ c_parser_omp_context_selector_specification (c_parser *parser, tree parms)
       const char *setp = "";
       if (c_parser_next_token_is (parser, CPP_NAME))
 	setp = IDENTIFIER_POINTER (c_parser_peek_token (parser)->value);
-      switch (setp[0])
-	{
-	case 'c':
-	  if (strcmp (setp, "construct") == 0)
-	    setp = NULL;
-	  break;
-	case 'd':
-	  if (strcmp (setp, "device") == 0)
-	    setp = NULL;
-	  break;
-	case 'i':
-	  if (strcmp (setp, "implementation") == 0)
-	    setp = NULL;
-	  break;
-	case 'u':
-	  if (strcmp (setp, "user") == 0)
-	    setp = NULL;
-	  break;
-	default:
-	  break;
-	}
-      if (setp)
+      enum omp_tss_code set = omp_lookup_tss_code (setp);
+
+      if (set == OMP_TRAIT_SET_INVALID)
 	{
+	  /* FIXME: hardwired list of names here is incomplete and
+	     liable to bit-rot.  */
 	  c_parser_error (parser, "expected %<construct%>, %<device%>, "
 				  "%<implementation%> or %<user%>");
 	  return error_mark_node;
 	}
 
-      tree set = c_parser_peek_token (parser)->value;
       c_parser_consume_token (parser);
 
       if (!c_parser_require (parser, CPP_EQ, "expected %<=%>"))
@@ -24453,7 +24371,8 @@ c_finish_omp_declare_variant (c_parser *parser, tree fndecl, tree parms)
 	  error_at (token->location, "variant %qD is not a function", variant);
 	  variant = error_mark_node;
 	}
-      else if (omp_get_context_selector (ctx, "construct", "simd") == NULL_TREE
+      else if (!omp_get_context_selector (ctx, OMP_TRAIT_SET_CONSTRUCT,
+					  OMP_TRAIT_CONSTRUCT_SIMD)
 	       && !comptypes (TREE_TYPE (fndecl), TREE_TYPE (variant)))
 	{
 	  error_at (token->location, "variant %qD and base %qD have "
@@ -24474,7 +24393,8 @@ c_finish_omp_declare_variant (c_parser *parser, tree fndecl, tree parms)
       if (variant != error_mark_node)
 	{
 	  C_DECL_USED (variant) = 1;
-	  tree construct = omp_get_context_selector (ctx, "construct", NULL);
+	  tree construct
+	    = omp_get_context_selector_list (ctx, OMP_TRAIT_SET_CONSTRUCT);
 	  omp_mark_declare_variant (match_loc, variant, construct);
 	  if (omp_context_selector_matches (ctx))
 	    {
diff --git a/gcc/cp/decl.cc b/gcc/cp/decl.cc
index b8e1098d482..70693af9cc8 100644
--- a/gcc/cp/decl.cc
+++ b/gcc/cp/decl.cc
@@ -8042,12 +8042,13 @@ omp_declare_variant_finalize_one (tree decl, tree attr)
     }
 
   tree ctx = TREE_VALUE (TREE_VALUE (attr));
-  tree simd = omp_get_context_selector (ctx, "construct", "simd");
+  tree simd = omp_get_context_selector (ctx, OMP_TRAIT_SET_CONSTRUCT,
+					OMP_TRAIT_CONSTRUCT_SIMD);
   if (simd)
     {
       TREE_VALUE (simd)
 	= c_omp_declare_simd_clauses_to_numbers (DECL_ARGUMENTS (decl),
-						 TREE_VALUE (simd));
+						 OMP_TS_PROPERTIES (simd));
       /* FIXME, adjusting simd args unimplemented.  */
       return true;
     }
@@ -8140,7 +8141,8 @@ omp_declare_variant_finalize_one (tree decl, tree attr)
 	}
       else
 	{
-	  tree construct = omp_get_context_selector (ctx, "construct", NULL);
+	  tree construct
+	    = omp_get_context_selector_list (ctx, OMP_TRAIT_SET_CONSTRUCT);
 	  omp_mark_declare_variant (match_loc, variant, construct);
 	  if (!omp_context_selector_matches (ctx))
 	    return true;
diff --git a/gcc/cp/parser.cc b/gcc/cp/parser.cc
index 9030365644d..6f5514d40c9 100644
--- a/gcc/cp/parser.cc
+++ b/gcc/cp/parser.cc
@@ -47255,16 +47255,6 @@ cp_parser_omp_declare_simd (cp_parser *parser, cp_token *pragma_tok,
     }
 }
 
-static const char *const omp_construct_selectors[] = {
-  "simd", "target", "teams", "parallel", "for", NULL };
-static const char *const omp_device_selectors[] = {
-  "kind", "isa", "arch", NULL };
-static const char *const omp_implementation_selectors[] = {
-  "vendor", "extension", "atomic_default_mem_order", "unified_address",
-  "unified_shared_memory", "dynamic_allocators", "reverse_offload", NULL };
-static const char *const omp_user_selectors[] = {
-  "condition", NULL };
-
 /* OpenMP 5.0:
 
    trait-selector:
@@ -47277,7 +47267,8 @@ static const char *const omp_user_selectors[] = {
    trait-selector-set SET.  */
 
 static tree
-cp_parser_omp_context_selector (cp_parser *parser, tree set, bool has_parms_p)
+cp_parser_omp_context_selector (cp_parser *parser, enum omp_tss_code set,
+				bool has_parms_p)
 {
   tree ret = NULL_TREE;
   do
@@ -47292,78 +47283,53 @@ cp_parser_omp_context_selector (cp_parser *parser, tree set, bool has_parms_p)
 	  return error_mark_node;
 	}
 
-      tree properties = NULL_TREE;
-      tree scoreval = NULL_TREE;
-      const char *const *selectors = NULL;
-      bool allow_score = true;
-      bool allow_user = false;
-      int property_limit = 0;
-      enum { CTX_PROPERTY_NONE, CTX_PROPERTY_USER, CTX_PROPERTY_NAME_LIST,
-	     CTX_PROPERTY_ID, CTX_PROPERTY_EXPR,
-	     CTX_PROPERTY_SIMD } property_kind = CTX_PROPERTY_NONE;
-      switch (IDENTIFIER_POINTER (set)[0])
-	{
-	case 'c': /* construct */
-	  selectors = omp_construct_selectors;
-	  allow_score = false;
-	  property_limit = 1;
-	  property_kind = CTX_PROPERTY_SIMD;
-	  break;
-	case 'd': /* device */
-	  selectors = omp_device_selectors;
-	  allow_score = false;
-	  allow_user = true;
-	  property_limit = 3;
-	  property_kind = CTX_PROPERTY_NAME_LIST;
-	  break;
-	case 'i': /* implementation */
-	  selectors = omp_implementation_selectors;
-	  allow_user = true;
-	  property_limit = 3;
-	  property_kind = CTX_PROPERTY_NAME_LIST;
-	  break;
-	case 'u': /* user */
-	  selectors = omp_user_selectors;
-	  property_limit = 1;
-	  property_kind = CTX_PROPERTY_EXPR;
-	  break;
-	default:
-	  gcc_unreachable ();
-	}
-      for (int i = 0; ; i++)
+      enum omp_ts_code sel
+	= omp_lookup_ts_code (set, IDENTIFIER_POINTER (selector));
+
+      if (sel == OMP_TRAIT_INVALID)
 	{
-	  if (selectors[i] == NULL)
+	  /* Some trait sets permit extension traits which are supposed
+	     to be ignored if the implementation doesn't support them.
+	     GCC does not support any extension traits, and if it did, they
+	     would have their own identifiers.  */
+	  if (set == OMP_TRAIT_SET_IMPLEMENTATION
+	      || set == OMP_TRAIT_SET_DEVICE
+	      || set == OMP_TRAIT_SET_TARGET_DEVICE)
 	    {
-	      if (allow_user)
-		{
-		  property_kind = CTX_PROPERTY_USER;
-		  break;
-		}
-	      else
+	      cp_lexer_consume_token (parser->lexer);
+	      if (cp_lexer_next_token_is (parser->lexer, CPP_OPEN_PAREN))
+		for (size_t n = cp_parser_skip_balanced_tokens (parser, 1) - 1;
+		     n; --n)
+		  cp_lexer_consume_token (parser->lexer);
+	      if (cp_lexer_next_token_is (parser->lexer, CPP_COMMA))
 		{
-		  error ("selector %qs not allowed for context selector "
-			 "set %qs", IDENTIFIER_POINTER (selector),
-			 IDENTIFIER_POINTER (set));
 		  cp_lexer_consume_token (parser->lexer);
-		  return error_mark_node;
+		  continue;
 		}
+	      else
+		break;
+	    }
+	  else
+	    {
+	      error_at (cp_lexer_peek_token (parser->lexer)->location,
+			"selector %qs not allowed for context selector "
+			"set %qs", IDENTIFIER_POINTER (selector),
+			omp_tss_map[set]);
+	      cp_lexer_consume_token (parser->lexer);
+	      return error_mark_node;
 	    }
-	  if (i == property_limit)
-	    property_kind = CTX_PROPERTY_NONE;
-	  if (strcmp (selectors[i], IDENTIFIER_POINTER (selector)) == 0)
-	    break;
 	}
-      if (property_kind == CTX_PROPERTY_NAME_LIST
-	  && IDENTIFIER_POINTER (set)[0] == 'i'
-	  && strcmp (IDENTIFIER_POINTER (selector),
-		     "atomic_default_mem_order") == 0)
-	property_kind = CTX_PROPERTY_ID;
-
       cp_lexer_consume_token (parser->lexer);
 
+      tree properties = NULL_TREE;
+      tree scoreval = NULL_TREE;
+      enum omp_tp_type property_kind = omp_ts_map[sel].tp_type;
+      bool allow_score = omp_ts_map[sel].allow_score;
+      tree t;
+
       if (cp_lexer_next_token_is (parser->lexer, CPP_OPEN_PAREN))
 	{
-	  if (property_kind == CTX_PROPERTY_NONE)
+	  if (property_kind == OMP_TRAIT_PROPERTY_NONE)
 	    {
 	      error ("selector %qs does not accept any properties",
 		     IDENTIFIER_POINTER (selector));
@@ -47420,38 +47386,7 @@ cp_parser_omp_context_selector (cp_parser *parser, tree set, bool has_parms_p)
 
 	  switch (property_kind)
 	    {
-	      tree t;
-	    case CTX_PROPERTY_USER:
-	      do
-		{
-		  t = cp_parser_constant_expression (parser);
-		  if (t != error_mark_node)
-		    {
-		      t = fold_non_dependent_expr (t);
-		      if (TREE_CODE (t) == STRING_CST)
-			properties = make_trait_property (NULL_TREE, t,
-							  properties);
-		      else if (!value_dependent_expression_p (t)
-			       && (!INTEGRAL_TYPE_P (TREE_TYPE (t))
-				   || !tree_fits_shwi_p (t)))
-			error_at (token->location, "property must be "
-				  "constant integer expression or string "
-				  "literal");
-		      else
-			properties = make_trait_property (NULL_TREE, t,
-							  properties);
-		    }
-		  else
-		    return error_mark_node;
-
-		  if (cp_lexer_next_token_is (parser->lexer, CPP_COMMA))
-		    cp_lexer_consume_token (parser->lexer);
-		  else
-		    break;
-		}
-	      while (1);
-	      break;
-	    case CTX_PROPERTY_ID:
+	    case OMP_TRAIT_PROPERTY_ID:
 	      if (cp_lexer_next_token_is (parser->lexer, CPP_KEYWORD)
 		  || cp_lexer_next_token_is (parser->lexer, CPP_NAME))
 		{
@@ -47466,7 +47401,7 @@ cp_parser_omp_context_selector (cp_parser *parser, tree set, bool has_parms_p)
 		  return error_mark_node;
 		}
 	      break;
-	    case CTX_PROPERTY_NAME_LIST:
+	    case OMP_TRAIT_PROPERTY_NAME_LIST:
 	      do
 		{
 		  tree prop = OMP_TP_NAMELIST_NODE;
@@ -47497,7 +47432,9 @@ cp_parser_omp_context_selector (cp_parser *parser, tree set, bool has_parms_p)
 		}
 	      while (1);
 	      break;
-	    case CTX_PROPERTY_EXPR:
+	    case OMP_TRAIT_PROPERTY_EXPR:
+	      /* FIXME: this is bogus, the expression need
+		 not be constant.  */
 	      t = cp_parser_constant_expression (parser);
 	      if (t != error_mark_node)
 		{
@@ -47514,7 +47451,9 @@ cp_parser_omp_context_selector (cp_parser *parser, tree set, bool has_parms_p)
 	      else
 		return error_mark_node;
 	      break;
-	    case CTX_PROPERTY_SIMD:
+	    case OMP_TRAIT_PROPERTY_CLAUSE_LIST:
+	      gcc_assert (sel == OMP_TRAIT_CONSTRUCT_SIMD);
+
 	      if (!has_parms_p)
 		{
 		  error_at (token->location, "properties for %<simd%> "
@@ -47536,15 +47475,15 @@ cp_parser_omp_context_selector (cp_parser *parser, tree set, bool has_parms_p)
 
 	  properties = nreverse (properties);
 	}
-      else if (property_kind == CTX_PROPERTY_NAME_LIST
-	       || property_kind == CTX_PROPERTY_ID
-	       || property_kind == CTX_PROPERTY_EXPR)
+      else if (property_kind != OMP_TRAIT_PROPERTY_NONE
+	       && property_kind != OMP_TRAIT_PROPERTY_CLAUSE_LIST
+	       && property_kind != OMP_TRAIT_PROPERTY_EXTENSION)
 	{
 	  cp_parser_require (parser, CPP_OPEN_PAREN, RT_OPEN_PAREN);
 	  return error_mark_node;
 	}
 
-      ret = make_trait_selector (selector, scoreval, properties, ret);
+      ret = make_trait_selector (sel, scoreval, properties, ret);
 
       if (cp_lexer_next_token_is (parser->lexer, CPP_COMMA))
 	cp_lexer_consume_token (parser->lexer);
@@ -47580,35 +47519,17 @@ cp_parser_omp_context_selector_specification (cp_parser *parser,
       if (cp_lexer_next_token_is (parser->lexer, CPP_NAME))
 	setp
 	  = IDENTIFIER_POINTER (cp_lexer_peek_token (parser->lexer)->u.value);
-      switch (setp[0])
-	{
-	case 'c':
-	  if (strcmp (setp, "construct") == 0)
-	    setp = NULL;
-	  break;
-	case 'd':
-	  if (strcmp (setp, "device") == 0)
-	    setp = NULL;
-	  break;
-	case 'i':
-	  if (strcmp (setp, "implementation") == 0)
-	    setp = NULL;
-	  break;
-	case 'u':
-	  if (strcmp (setp, "user") == 0)
-	    setp = NULL;
-	  break;
-	default:
-	  break;
-	}
-      if (setp)
+      enum omp_tss_code set = omp_lookup_tss_code (setp);
+
+      if (set == OMP_TRAIT_SET_INVALID)
 	{
+	  /* FIXME: hardwired list of names here is incomplete and
+	     liable to bit-rot.  */
 	  cp_parser_error (parser, "expected %<construct%>, %<device%>, "
 				   "%<implementation%> or %<user%>");
 	  return error_mark_node;
 	}
 
-      tree set = cp_lexer_peek_token (parser->lexer)->u.value;
       cp_lexer_consume_token (parser->lexer);
 
       if (!cp_parser_require (parser, CPP_EQ, RT_EQ))
diff --git a/gcc/cp/pt.cc b/gcc/cp/pt.cc
index c3815733651..ed51a838f12 100644
--- a/gcc/cp/pt.cc
+++ b/gcc/cp/pt.cc
@@ -11841,18 +11841,20 @@ tsubst_attribute (tree t, tree *decl_p, tree args,
       tree chain = TREE_CHAIN (val);
       location_t match_loc = cp_expr_loc_or_input_loc (TREE_PURPOSE (chain));
       tree ctx = copy_list (TREE_VALUE (val));
-      tree simd = get_identifier ("simd");
-      tree condition = get_identifier ("condition");
       for (tree tss = ctx; tss; tss = TREE_CHAIN (tss))
 	{
-	  const char *set = IDENTIFIER_POINTER (OMP_TSS_ID (tss));
+	  enum omp_tss_code set = OMP_TSS_CODE (tss);
 	  tree selectors = NULL_TREE;
 	  for (tree ts = OMP_TSS_TRAIT_SELECTORS (tss); ts;
 	       ts = TREE_CHAIN (ts))
 	    {
 	      tree properties = NULL_TREE;
 	      tree scoreval = NULL_TREE;
-	      if (OMP_TS_ID (ts) == simd && set[0] == 'c')
+	      /* FIXME: The body of this loop should really be dispatching
+		 according to omp_ts_map[OMP_TS_CODE (TS)].tp_type instead
+		 of having hard-wired knowledge of specific selectors.  */
+	      if (OMP_TS_CODE (ts) == OMP_TRAIT_CONSTRUCT_SIMD
+		  && set == OMP_TRAIT_SET_CONSTRUCT)
 		{
 		  tree clauses = OMP_TS_PROPERTIES (ts);
 		  clauses = tsubst_omp_clauses (clauses,
@@ -11897,7 +11899,8 @@ tsubst_attribute (tree t, tree *decl_p, tree args,
 		    else if (OMP_TP_VALUE (p))
 		      {
 			bool allow_string
-			  = (OMP_TS_ID (ts) != condition || set[0] != 'u');
+			  = (OMP_TS_CODE (ts) != OMP_TRAIT_USER_CONDITION
+			     || set != OMP_TRAIT_SET_USER);
 			tree v = OMP_TP_VALUE (p);
 			if (TREE_CODE (v) == STRING_CST && allow_string)
 			  continue;
@@ -11921,7 +11924,7 @@ tsubst_attribute (tree t, tree *decl_p, tree args,
 			OMP_TP_VALUE (p) = v;
 		      }
 		}
-	      selectors = make_trait_selector (OMP_TS_ID (ts), scoreval,
+	      selectors = make_trait_selector (OMP_TS_CODE (ts), scoreval,
 					       properties, selectors);
 	    }
 	  OMP_TSS_TRAIT_SELECTORS (tss) = nreverse (selectors);
diff --git a/gcc/fortran/trans-openmp.cc b/gcc/fortran/trans-openmp.cc
index 60154ff3751..08e32636c9f 100644
--- a/gcc/fortran/trans-openmp.cc
+++ b/gcc/fortran/trans-openmp.cc
@@ -8208,11 +8208,34 @@ gfc_trans_omp_declare_variant (gfc_namespace *ns)
 	{
 	  tree selectors = NULL_TREE;
 	  gfc_omp_selector *os;
+	  enum omp_tss_code set
+	    = omp_lookup_tss_code (oss->trait_set_selector_name);
+	  gcc_assert (set != OMP_TRAIT_SET_INVALID);
+
 	  for (os = oss->trait_selectors; os; os = os->next)
 	    {
 	      tree scoreval = NULL_TREE;
 	      tree properties = NULL_TREE;
 	      gfc_omp_trait_property *otp;
+	      enum omp_ts_code sel;
+
+	      if (set == OMP_TRAIT_SET_CONSTRUCT
+		  && !(strcmp (os->trait_selector_name, "do")))
+		sel = OMP_TRAIT_CONSTRUCT_FOR;
+	      else
+		sel = omp_lookup_ts_code (set, os->trait_selector_name);
+
+	      /* Some trait sets permit extension traits which are supposed
+		 to be ignored if the implementation doesn't support them.
+		 GCC does not support any extension traits, and if it did,
+		 they would have their own identifiers.  */
+	      if (sel == OMP_TRAIT_INVALID
+		  && (set == OMP_TRAIT_SET_IMPLEMENTATION
+		      || set == OMP_TRAIT_SET_DEVICE
+		      || set == OMP_TRAIT_SET_TARGET_DEVICE))
+		continue;
+
+	      gcc_assert (sel != OMP_TRAIT_INVALID);
 
 	      for (otp = os->properties; otp; otp = otp->next)
 		{
@@ -8263,13 +8286,10 @@ gfc_trans_omp_declare_variant (gfc_namespace *ns)
 		  scoreval = se.expr;
 		}
 
-	      tree ts_name = get_identifier (os->trait_selector_name);
-	      selectors	= make_trait_selector (ts_name, scoreval,
+	      selectors	= make_trait_selector (sel, scoreval,
 					       properties, selectors);
 	    }
-
-	  tree tss_name = get_identifier (oss->trait_set_selector_name);
-	  set_selectors = make_trait_set_selector (tss_name, selectors,
+	  set_selectors = make_trait_set_selector (set,  selectors,
 						   set_selectors);
 	}
 
@@ -8298,8 +8318,10 @@ gfc_trans_omp_declare_variant (gfc_namespace *ns)
 			 variant_proc_name, &odv->where);
 	      variant_proc_sym = NULL;
 	    }
-	  else if (omp_get_context_selector (set_selectors, "construct",
-					     "simd") == NULL_TREE)
+	  else if (omp_get_context_selector (set_selectors,
+					     OMP_TRAIT_SET_CONSTRUCT,
+					     OMP_TRAIT_CONSTRUCT_SIMD)
+		   == NULL_TREE)
 	    {
 	      char err[256];
 	      if (!gfc_compare_interfaces (ns->proc_name, variant_proc_sym,
@@ -8316,8 +8338,9 @@ gfc_trans_omp_declare_variant (gfc_namespace *ns)
 	  if (variant_proc_sym != NULL)
 	    {
 	      gfc_set_sym_referenced (variant_proc_sym);
-	      tree construct = omp_get_context_selector (set_selectors,
-							 "construct", NULL);
+	      tree construct
+		= omp_get_context_selector_list (set_selectors,
+						 OMP_TRAIT_SET_CONSTRUCT);
 	      omp_mark_declare_variant (gfc_get_location (&odv->where),
 					gfc_get_symbol_decl (variant_proc_sym),
 					construct);
diff --git a/gcc/omp-general.cc b/gcc/omp-general.cc
index e4e3890449e..7c99b73ceec 100644
--- a/gcc/omp-general.cc
+++ b/gcc/omp-general.cc
@@ -1014,28 +1014,26 @@ omp_max_simt_vf (void)
 }
 
 /* Store the construct selectors as tree codes from last to first,
-   return their number.  */
+   return their number.  CTX is a list of trait selectors and
+   CONSTRUCTS holds the output.  */
 
 int
 omp_construct_traits_to_codes (tree ctx, enum tree_code *constructs)
 {
   int nconstructs = list_length (ctx);
   int i = nconstructs - 1;
+
+  /* Order must match the OMP_TRAIT_CONSTRUCT_* enumerators in
+     enum omp_ts_code.  */
+  static enum tree_code code_map[]
+    = { OMP_TARGET, OMP_TEAMS, OMP_PARALLEL, OMP_FOR, OMP_SIMD };
+
   for (tree ts = ctx; ts; ts = TREE_CHAIN (ts), i--)
     {
-      const char *sel = IDENTIFIER_POINTER (OMP_TS_ID (ts));
-      if (!strcmp (sel, "target"))
-	constructs[i] = OMP_TARGET;
-      else if (!strcmp (sel, "teams"))
-	constructs[i] = OMP_TEAMS;
-      else if (!strcmp (sel, "parallel"))
-	constructs[i] = OMP_PARALLEL;
-      else if (!strcmp (sel, "for") || !strcmp (sel, "do"))
-	constructs[i] = OMP_FOR;
-      else if (!strcmp (sel, "simd"))
-	constructs[i] = OMP_SIMD;
-      else
-	gcc_unreachable ();
+      enum omp_ts_code sel = OMP_TS_CODE (ts);
+      int j = (int)sel - (int)OMP_TRAIT_CONSTRUCT_TARGET;
+      gcc_assert (j >= 0 && (unsigned int) j < ARRAY_SIZE (code_map));
+      constructs[i] = code_map[j];
     }
   gcc_assert (i == -1);
   return nconstructs;
@@ -1114,6 +1112,124 @@ omp_maybe_offloaded (void)
   return false;
 }
 
+/* Lookup tables for context selectors.  */
+const char *omp_tss_map[] =
+  {
+   "construct",
+   "device",
+   "target_device",
+   "implementation",
+   "user",
+   NULL
+};
+
+/* Arrays of property candidates must be null-terminated.  */
+static const char *const kind_properties[] =
+  { "host", "nohost", "cpu", "gpu", "fpga", "any", NULL };
+static const char *const vendor_properties[] =
+  { "amd", "arm", "bsc", "cray", "fujitsu", "gnu", "ibm", "intel",
+    "llvm", "nvidia", "pgi", "ti", "unknown", NULL };
+static const char *const extension_properties[] =
+  { NULL };
+static const char *const atomic_default_mem_order_properties[] =
+  { "seq_cst", "relaxed", "acq_rel", NULL };
+
+struct omp_ts_info omp_ts_map[] =
+  {
+   { "kind",
+     (1 << OMP_TRAIT_SET_DEVICE) | (1 << OMP_TRAIT_SET_TARGET_DEVICE),
+     OMP_TRAIT_PROPERTY_NAME_LIST, false,
+     kind_properties
+   },
+   { "isa",
+     (1 << OMP_TRAIT_SET_DEVICE) | (1 << OMP_TRAIT_SET_TARGET_DEVICE),
+     OMP_TRAIT_PROPERTY_NAME_LIST, false,
+     NULL
+   },
+   { "arch",
+     (1 << OMP_TRAIT_SET_DEVICE) | (1 << OMP_TRAIT_SET_TARGET_DEVICE),
+     OMP_TRAIT_PROPERTY_NAME_LIST, false,
+     NULL
+   },
+   { "device_num",
+     (1 << OMP_TRAIT_SET_TARGET_DEVICE),
+     OMP_TRAIT_PROPERTY_EXPR, false,
+     NULL
+   },
+   { "vendor",
+     (1 << OMP_TRAIT_SET_IMPLEMENTATION),
+     OMP_TRAIT_PROPERTY_NAME_LIST, true,
+     vendor_properties,
+   },
+   { "extension",
+     (1 << OMP_TRAIT_SET_IMPLEMENTATION),
+     OMP_TRAIT_PROPERTY_NAME_LIST, true,
+     extension_properties,
+   },
+   { "atomic_default_mem_order",
+     (1 << OMP_TRAIT_SET_IMPLEMENTATION),
+     OMP_TRAIT_PROPERTY_ID, true,
+     atomic_default_mem_order_properties,
+   },
+   { "requires",
+     (1 << OMP_TRAIT_SET_IMPLEMENTATION),
+     OMP_TRAIT_PROPERTY_CLAUSE_LIST, true,
+     NULL
+   },
+   { "unified_address",
+     (1 << OMP_TRAIT_SET_IMPLEMENTATION),
+     OMP_TRAIT_PROPERTY_NONE, true,
+     NULL
+   },
+   { "unified_shared_memory",
+     (1 << OMP_TRAIT_SET_IMPLEMENTATION),
+     OMP_TRAIT_PROPERTY_NONE, true,
+     NULL
+   },
+   { "dynamic_allocators",
+     (1 << OMP_TRAIT_SET_IMPLEMENTATION),
+     OMP_TRAIT_PROPERTY_NONE, true,
+     NULL
+   },
+   { "reverse_offload",
+     (1 << OMP_TRAIT_SET_IMPLEMENTATION),
+     OMP_TRAIT_PROPERTY_NONE, true,
+     NULL
+   },
+   { "condition",
+     (1 << OMP_TRAIT_SET_USER),
+     OMP_TRAIT_PROPERTY_EXPR, true,
+     NULL
+   },
+   { "target",
+     (1 << OMP_TRAIT_SET_CONSTRUCT),
+     OMP_TRAIT_PROPERTY_NONE, false,
+     NULL
+   },
+   { "teams",
+     (1 << OMP_TRAIT_SET_CONSTRUCT),
+     OMP_TRAIT_PROPERTY_NONE, false,
+     NULL
+   },
+   { "parallel",
+     (1 << OMP_TRAIT_SET_CONSTRUCT),
+     OMP_TRAIT_PROPERTY_NONE, false,
+     NULL
+   },
+   { "for",
+     (1 << OMP_TRAIT_SET_CONSTRUCT),
+     OMP_TRAIT_PROPERTY_NONE, false,
+     NULL
+   },
+   { "simd",
+     (1 << OMP_TRAIT_SET_CONSTRUCT),
+     OMP_TRAIT_PROPERTY_CLAUSE_LIST,  false,
+     NULL
+   },
+   { NULL, 0, OMP_TRAIT_PROPERTY_NONE, false, NULL }  /* OMP_TRAIT_LAST */
+  };
+
+
 /* Return a name from PROP, a property in selectors accepting
    name lists.  */
 
@@ -1145,112 +1261,92 @@ omp_context_name_list_prop (tree prop)
 tree
 omp_check_context_selector (location_t loc, tree ctx)
 {
-  /* Each trait-set-selector-name can only be specified once.
-     There are just 4 set names.  */
-  for (tree t1 = ctx; t1; t1 = TREE_CHAIN (t1))
-    for (tree t2 = TREE_CHAIN (t1); t2; t2 = TREE_CHAIN (t2))
-      if (OMP_TSS_ID (t1) == OMP_TSS_ID (t2))
-	{
-	  error_at (loc, "selector set %qs specified more than once",
-		    IDENTIFIER_POINTER (OMP_TSS_ID (t1)));
-	  return error_mark_node;
-	}
+  bool tss_seen[OMP_TRAIT_SET_LAST], ts_seen[OMP_TRAIT_LAST];
+
+  memset (tss_seen, 0, sizeof (tss_seen));
   for (tree tss = ctx; tss; tss = TREE_CHAIN (tss))
     {
-      /* Each trait-selector-name can only be specified once.  */
-      if (list_length (OMP_TSS_TRAIT_SELECTORS (tss)) < 5)
+      enum omp_tss_code tss_code = OMP_TSS_CODE (tss);
+
+      /* Each trait-set-selector-name can only be specified once.  */
+      if (tss_seen[tss_code])
 	{
-	  for (tree ts1 = OMP_TSS_TRAIT_SELECTORS (tss); ts1;
-	       ts1 = TREE_CHAIN (ts1))
-	    for (tree ts2 = TREE_CHAIN (ts1); ts2; ts2 = TREE_CHAIN (ts2))
-	      if (OMP_TS_ID (ts1) == OMP_TS_ID (ts2))
-		{
-		  error_at (loc,
-			    "selector %qs specified more than once in set %qs",
-			    IDENTIFIER_POINTER (OMP_TS_ID (ts1)),
-			    IDENTIFIER_POINTER (OMP_TSS_ID (tss)));
-		  return error_mark_node;
-		}
+	  error_at (loc, "selector set %qs specified more than once",
+		    OMP_TSS_NAME (tss));
+	  return error_mark_node;
 	}
       else
+	tss_seen[tss_code] = true;
+
+      memset (ts_seen, 0, sizeof (ts_seen));
+      for (tree ts = OMP_TSS_TRAIT_SELECTORS (tss); ts; ts = TREE_CHAIN (ts))
 	{
-	  hash_set<tree> pset;
-	  for (tree ts = OMP_TSS_TRAIT_SELECTORS (tss); ts;
-	       ts = TREE_CHAIN (ts))
-	    if (pset.add (OMP_TS_ID (ts)))
+	  enum omp_ts_code ts_code = OMP_TS_CODE (ts);
+
+	  /* Each trait-selector-name can only be specified once.  */
+	  if (ts_seen[ts_code])
+	    {
+	      error_at (loc,
+			"selector %qs specified more than once in set %qs",
+			OMP_TS_NAME (ts),
+			OMP_TSS_NAME (tss));
+	      return error_mark_node;
+	    }
+	  else
+	    ts_seen[ts_code] = true;
+
+	  if (omp_ts_map[ts_code].valid_properties == NULL)
+	    continue;
+
+	  for (tree p = OMP_TS_PROPERTIES (ts); p; p = TREE_CHAIN (p))
+	    for (unsigned j = 0; ; j++)
 	      {
-		error_at (loc,
-			  "selector %qs specified more than once in set %qs",
-			  IDENTIFIER_POINTER (OMP_TS_ID (ts)),
-			  IDENTIFIER_POINTER (OMP_TSS_ID (tss)));
-		return error_mark_node;
+		const char *candidate
+		  = omp_ts_map[ts_code].valid_properties[j];
+		if (candidate == NULL)
+		  {
+		    /* We've reached the end of the candidate array.  */
+		    if (ts_code == OMP_TRAIT_IMPLEMENTATION_ADMO)
+		      /* FIXME: not sure why this is an error vs warnings
+			 for the others, + incorrect/unknown wording?  */
+		      {
+			error_at (loc,
+				  "incorrect property %qs of %qs selector",
+				  IDENTIFIER_POINTER (OMP_TP_NAME (p)),
+				  "atomic_default_mem_order");
+			return error_mark_node;
+		      }
+		    if (OMP_TP_NAME (p) == OMP_TP_NAMELIST_NODE
+			&& (TREE_CODE (OMP_TP_VALUE (p)) == STRING_CST))
+		      warning_at (loc, 0,
+				  "unknown property %qE of %qs selector",
+				  OMP_TP_VALUE (p),
+				  OMP_TS_NAME (ts));
+		    else if (OMP_TP_NAME (p) == OMP_TP_NAMELIST_NODE)
+		      warning_at (loc, 0,
+				  "unknown property %qs of %qs selector",
+				  omp_context_name_list_prop (p),
+				  OMP_TS_NAME (ts));
+		    else if (OMP_TP_NAME (p))
+		      warning_at (loc, 0,
+				  "unknown property %qs of %qs selector",
+				  IDENTIFIER_POINTER (OMP_TP_NAME (p)),
+				  OMP_TS_NAME (ts));
+		    break;
+		  }
+		else if (OMP_TP_NAME (p) == OMP_TP_NAMELIST_NODE)
+		  /* Property-list traits.  */
+		  {
+		    const char *str = omp_context_name_list_prop (p);
+		    if (str && !strcmp (str, candidate))
+		      break;
+		  }
+		else if (!strcmp (IDENTIFIER_POINTER (OMP_TP_NAME (p)),
+				  candidate))
+		  /* Identifier traits.  */
+		  break;
 	      }
 	}
-
-      static const char *const kind[] = {
-	"host", "nohost", "cpu", "gpu", "fpga", "any", NULL };
-      static const char *const vendor[] = {
-	"amd", "arm", "bsc", "cray", "fujitsu", "gnu", "ibm", "intel",
-	"llvm", "nvidia", "pgi", "ti", "unknown", NULL };
-      static const char *const extension[] = { NULL };
-      static const char *const atomic_default_mem_order[] = {
-	"seq_cst", "relaxed", "acq_rel", NULL };
-      struct known_properties { const char *set; const char *selector;
-				const char *const *props; };
-      known_properties props[] = {
-	{ "device", "kind", kind },
-	{ "implementation", "vendor", vendor },
-	{ "implementation", "extension", extension },
-	{ "implementation", "atomic_default_mem_order",
-	  atomic_default_mem_order } };
-      for (tree ts = OMP_TSS_TRAIT_SELECTORS (tss); ts; ts = TREE_CHAIN (ts))
-	for (unsigned i = 0; i < ARRAY_SIZE (props); i++)
-	  if (!strcmp (IDENTIFIER_POINTER (OMP_TS_ID (ts)),
-					   props[i].selector)
-	      && !strcmp (IDENTIFIER_POINTER (OMP_TSS_ID (tss)),
-					      props[i].set))
-	    for (tree p = OMP_TS_PROPERTIES (ts); p; p = TREE_CHAIN (p))
-	      for (unsigned j = 0; ; j++)
-		{
-		  if (props[i].props[j] == NULL)
-		    {
-		      if (props[i].props == atomic_default_mem_order)
-			{
-			  error_at (loc,
-				    "incorrect property %qs of %qs selector",
-				    IDENTIFIER_POINTER (TREE_PURPOSE (p)),
-				    "atomic_default_mem_order");
-			  return error_mark_node;
-			}
-		      else if (OMP_TP_NAME (p) == OMP_TP_NAMELIST_NODE
-			       && (TREE_CODE (OMP_TP_VALUE (p)) == STRING_CST))
-			warning_at (loc, 0,
-				    "unknown property %qE of %qs selector",
-				    OMP_TP_VALUE (p),
-				    props[i].selector);
-		      else if (OMP_TP_NAME (p) == OMP_TP_NAMELIST_NODE)
-			warning_at (loc, 0,
-				    "unknown property %qs of %qs selector",
-				    omp_context_name_list_prop (p),
-				    props[i].selector);
-		      else if (OMP_TP_NAME (p))
-			warning_at (loc, 0,
-				    "unknown property %qs of %qs selector",
-				    IDENTIFIER_POINTER (OMP_TP_NAME (p)),
-				    props[i].selector);
-		      break;
-		    }
-		  else if (OMP_TP_NAME (p) == OMP_TP_NAMELIST_NODE)
-		    /* Property-list traits.  */
-		    {
-		      const char *str = omp_context_name_list_prop (p);
-		      if (str && !strcmp (str, props[i].props[j]))
-			break;
-		    }
-		  else if (!strcmp (IDENTIFIER_POINTER (OMP_TP_NAME (p)),
-				    props[i].props[j]))
-		    break;
-		}
     }
   return ctx;
 }
@@ -1275,7 +1371,8 @@ omp_mark_declare_variant (location_t loc, tree variant, tree construct)
     }
   if ((TREE_VALUE (attr) != NULL_TREE) != (construct != NULL_TREE)
       || (construct != NULL_TREE
-	  && omp_context_selector_set_compare ("construct", TREE_VALUE (attr),
+	  && omp_context_selector_set_compare (OMP_TRAIT_SET_CONSTRUCT,
+					       TREE_VALUE (attr),
 					       construct)))
     error_at (loc, "%qD used as a variant with incompatible %<construct%> "
 		   "selector sets", variant);
@@ -1285,18 +1382,21 @@ omp_mark_declare_variant (location_t loc, tree variant, tree construct)
 /* Constructors for context selectors.  */
 
 tree
-make_trait_set_selector (tree name, tree selectors, tree chain)
+make_trait_set_selector (enum omp_tss_code code, tree selectors, tree chain)
 {
-  return tree_cons (name, selectors, chain);
+  return tree_cons (build_int_cst (integer_type_node, code),
+		    selectors, chain);
 }
 
 tree
-make_trait_selector (tree name, tree score, tree properties, tree chain)
+make_trait_selector (enum omp_ts_code code, tree score, tree properties,
+		     tree chain)
 {
   if (score == NULL_TREE)
-    return tree_cons (name, properties, chain);
+    return tree_cons (build_int_cst (integer_type_node, code),
+		      properties, chain);
   else
-    return tree_cons (name,
+    return tree_cons (build_int_cst (integer_type_node, code),
 		      tree_cons (OMP_TS_SCORE_NODE, score, properties),
 		      chain);
 }
@@ -1319,8 +1419,8 @@ omp_context_selector_matches (tree ctx)
   int ret = 1;
   for (tree tss = ctx; tss; tss = TREE_CHAIN (tss))
     {
-      char set = IDENTIFIER_POINTER (OMP_TSS_ID (tss))[0];
-      if (set == 'c')
+      enum omp_tss_code set = OMP_TSS_CODE (tss);
+      if (set == OMP_TRAIT_SET_CONSTRUCT)
 	{
 	  /* For now, ignore the construct set.  While something can be
 	     determined already during parsing, we don't know until end of TU
@@ -1335,10 +1435,12 @@ omp_context_selector_matches (tree ctx)
 	      continue;
 	    }
 
-	  enum tree_code constructs[5];
+	  tree selectors = OMP_TSS_TRAIT_SELECTORS (tss);
+	  enum tree_code *constructs
+	    = (enum tree_code *) alloca (list_length (selectors)
+					 * sizeof (enum tree_code));
 	  int nconstructs
-	    = omp_construct_traits_to_codes (OMP_TSS_TRAIT_SELECTORS (tss),
-					     constructs);
+	    = omp_construct_traits_to_codes (selectors, constructs);
 
 	  if (cfun && (cfun->curr_properties & PROP_gimple_any) != 0)
 	    {
@@ -1371,11 +1473,11 @@ omp_context_selector_matches (tree ctx)
 	}
       for (tree ts = OMP_TSS_TRAIT_SELECTORS (tss); ts; ts = TREE_CHAIN (ts))
 	{
-	  const char *sel = IDENTIFIER_POINTER (OMP_TS_ID (ts));
-	  switch (*sel)
+	  enum omp_ts_code sel = OMP_TS_CODE (ts);
+	  switch (sel)
 	    {
-	    case 'v':
-	      if (set == 'i' && !strcmp (sel, "vendor"))
+	    case OMP_TRAIT_IMPLEMENTATION_VENDOR:
+	      if (set == OMP_TRAIT_SET_IMPLEMENTATION)
 		for (tree p = OMP_TS_PROPERTIES (ts); p; p = TREE_CHAIN (p))
 		  {
 		    const char *prop = omp_context_name_list_prop (p);
@@ -1386,13 +1488,13 @@ omp_context_selector_matches (tree ctx)
 		    return 0;
 		  }
 	      break;
-	    case 'e':
-	      if (set == 'i' && !strcmp (sel, "extension"))
+	    case OMP_TRAIT_IMPLEMENTATION_EXTENSION:
+	      if (set == OMP_TRAIT_SET_IMPLEMENTATION)
 		/* We don't support any extensions right now.  */
 		return 0;
 	      break;
-	    case 'a':
-	      if (set == 'i' && !strcmp (sel, "atomic_default_mem_order"))
+	    case OMP_TRAIT_IMPLEMENTATION_ADMO:
+	      if (set == OMP_TRAIT_SET_IMPLEMENTATION)
 		{
 		  if (cfun && (cfun->curr_properties & PROP_gimple_any) != 0)
 		    break;
@@ -1424,7 +1526,9 @@ omp_context_selector_matches (tree ctx)
 			   && omo != OMP_MEMORY_ORDER_ACQ_REL)
 		    return 0;
 		}
-	      if (set == 'd' && !strcmp (sel, "arch"))
+	      break;
+	    case OMP_TRAIT_DEVICE_ARCH:
+	      if (set == OMP_TRAIT_SET_DEVICE)
 		for (tree p = OMP_TS_PROPERTIES (ts); p; p = TREE_CHAIN (p))
 		  {
 		    const char *arch = omp_context_name_list_prop (p);
@@ -1461,8 +1565,8 @@ omp_context_selector_matches (tree ctx)
 		      ret = -1;
 		  }
 	      break;
-	    case 'u':
-	      if (set == 'i' && !strcmp (sel, "unified_address"))
+	    case OMP_TRAIT_IMPLEMENTATION_UNIFIED_ADDRESS:
+	      if (set == OMP_TRAIT_SET_IMPLEMENTATION)
 		{
 		  if (cfun && (cfun->curr_properties & PROP_gimple_any) != 0)
 		    break;
@@ -1474,9 +1578,10 @@ omp_context_selector_matches (tree ctx)
 		      else
 			return 0;
 		    }
-		  break;
 		}
-	      if (set == 'i' && !strcmp (sel, "unified_shared_memory"))
+	      break;
+	    case OMP_TRAIT_IMPLEMENTATION_UNIFIED_SHARED_MEMORY:
+	      if (set == OMP_TRAIT_SET_IMPLEMENTATION)
 		{
 		  if (cfun && (cfun->curr_properties & PROP_gimple_any) != 0)
 		    break;
@@ -1489,11 +1594,10 @@ omp_context_selector_matches (tree ctx)
 		      else
 			return 0;
 		    }
-		  break;
 		}
 	      break;
-	    case 'd':
-	      if (set == 'i' && !strcmp (sel, "dynamic_allocators"))
+	    case OMP_TRAIT_IMPLEMENTATION_DYNAMIC_ALLOCATORS:
+	      if (set == OMP_TRAIT_SET_IMPLEMENTATION)
 		{
 		  if (cfun && (cfun->curr_properties & PROP_gimple_any) != 0)
 		    break;
@@ -1506,11 +1610,10 @@ omp_context_selector_matches (tree ctx)
 		      else
 			return 0;
 		    }
-		  break;
 		}
 	      break;
-	    case 'r':
-	      if (set == 'i' && !strcmp (sel, "reverse_offload"))
+	    case OMP_TRAIT_IMPLEMENTATION_REVERSE_OFFLOAD:
+	      if (set == OMP_TRAIT_SET_IMPLEMENTATION)
 		{
 		  if (cfun && (cfun->curr_properties & PROP_gimple_any) != 0)
 		    break;
@@ -1522,11 +1625,10 @@ omp_context_selector_matches (tree ctx)
 		      else
 			return 0;
 		    }
-		  break;
 		}
 	      break;
-	    case 'k':
-	      if (set == 'd' && !strcmp (sel, "kind"))
+	    case OMP_TRAIT_DEVICE_KIND:
+	      if (set == OMP_TRAIT_SET_DEVICE)
 		for (tree p = OMP_TS_PROPERTIES (ts); p; p = TREE_CHAIN (p))
 		  {
 		    const char *prop = omp_context_name_list_prop (p);
@@ -1586,8 +1688,8 @@ omp_context_selector_matches (tree ctx)
 		      ret = -1;
 		  }
 	      break;
-	    case 'i':
-	      if (set == 'd' && !strcmp (sel, "isa"))
+	    case OMP_TRAIT_DEVICE_ISA:
+	      if (set == OMP_TRAIT_SET_DEVICE)
 		for (tree p = OMP_TS_PROPERTIES (ts); p; p = TREE_CHAIN (p))
 		  {
 		    const char *isa = omp_context_name_list_prop (p);
@@ -1639,8 +1741,8 @@ omp_context_selector_matches (tree ctx)
 		      ret = -1;
 		  }
 	      break;
-	    case 'c':
-	      if (set == 'u' && !strcmp (sel, "condition"))
+	    case OMP_TRAIT_USER_CONDITION:
+	      if (set == OMP_TRAIT_SET_USER)
 		for (tree p = OMP_TS_PROPERTIES (ts); p; p = TREE_CHAIN (p))
 		  if (OMP_TP_NAME (p) == NULL_TREE)
 		    {
@@ -1782,7 +1884,8 @@ omp_construct_simd_compare (tree clauses1, tree clauses2)
    Unlike set names or selector names, properties can have duplicates.  */
 
 static int
-omp_context_selector_props_compare (const char *set, const char *sel,
+omp_context_selector_props_compare (enum omp_tss_code set,
+				    enum omp_ts_code sel,
 				    tree ctx1, tree ctx2)
 {
   int ret = 0;
@@ -1795,7 +1898,8 @@ omp_context_selector_props_compare (const char *set, const char *sel,
 	    {
 	      if (OMP_TP_NAME (p1) == NULL_TREE)
 		{
-		  if (set[0] == 'u' && strcmp (sel, "condition") == 0)
+		  if (set == OMP_TRAIT_SET_USER
+		      && sel == OMP_TRAIT_USER_CONDITION)
 		    {
 		      if (integer_zerop (OMP_TP_VALUE (p1))
 			  != integer_zerop (OMP_TP_VALUE (p2)))
@@ -1842,7 +1946,7 @@ omp_context_selector_props_compare (const char *set, const char *sel,
    2 if neither context is a subset of another one.  */
 
 int
-omp_context_selector_set_compare (const char *set, tree ctx1, tree ctx2)
+omp_context_selector_set_compare (enum omp_tss_code set, tree ctx1, tree ctx2)
 {
   bool swapped = false;
   int ret = 0;
@@ -1855,18 +1959,17 @@ omp_context_selector_set_compare (const char *set, tree ctx1, tree ctx2)
       std::swap (ctx1, ctx2);
       std::swap (len1, len2);
     }
-  if (set[0] == 'c')
+  if (set == OMP_TRAIT_SET_CONSTRUCT)
     {
       tree ts1;
       tree ts2 = ctx2;
-      tree simd = get_identifier ("simd");
       /* Handle construct set specially.  In this case the order
 	 of the selector matters too.  */
       for (ts1 = ctx1; ts1; ts1 = TREE_CHAIN (ts1))
-	if (OMP_TS_ID (ts1) == OMP_TS_ID (ts2))
+	if (OMP_TS_CODE (ts1) == OMP_TS_CODE (ts2))
 	  {
 	    int r = 0;
-	    if (OMP_TS_ID (ts1) == simd)
+	    if (OMP_TS_CODE (ts1) == OMP_TRAIT_CONSTRUCT_SIMD)
 	      r = omp_construct_simd_compare (OMP_TS_PROPERTIES (ts1),
 					      OMP_TS_PROPERTIES (ts2));
 	    if (r == 2 || (ret && r && (ret < 0) != (r < 0)))
@@ -1898,17 +2001,17 @@ omp_context_selector_set_compare (const char *set, tree ctx1, tree ctx2)
     }
   for (tree ts1 = ctx1; ts1; ts1 = TREE_CHAIN (ts1))
     {
+      enum omp_ts_code sel = OMP_TS_CODE (ts1);
       tree ts2;
       for (ts2 = ctx2; ts2; ts2 = TREE_CHAIN (ts2))
-	if (OMP_TS_ID (ts1) == OMP_TS_ID (ts2))
+	if (sel == OMP_TS_CODE (ts2))
 	  {
 	    tree score1 = OMP_TS_SCORE (ts1);
 	    tree score2 = OMP_TS_SCORE (ts2);
 	    if (score1 && score2 && !simple_cst_equal (score1, score2))
 	      return 2;
 
-	    const char *sel = IDENTIFIER_POINTER (OMP_TS_ID (ts1));
-	    int r = omp_context_selector_props_compare (set, sel,
+	    int r = omp_context_selector_props_compare (set, OMP_TS_CODE (ts1),
 							OMP_TS_PROPERTIES (ts1),
 							OMP_TS_PROPERTIES (ts2));
 	    if (r == 2 || (ret && r && (ret < 0) != (r < 0)))
@@ -1954,11 +2057,11 @@ omp_context_selector_compare (tree ctx1, tree ctx2)
     }
   for (tree tss1 = ctx1; tss1; tss1 = TREE_CHAIN (tss1))
     {
+      enum omp_tss_code set = OMP_TSS_CODE (tss1);
       tree tss2;
       for (tss2 = ctx2; tss2; tss2 = TREE_CHAIN (tss2))
-	if (OMP_TSS_ID (tss1) == OMP_TSS_ID (tss2))
+	if (set == OMP_TSS_CODE (tss2))
 	  {
-	    const char *set = IDENTIFIER_POINTER (OMP_TSS_ID (tss1));
 	    int r
 	      = omp_context_selector_set_compare
 		  (set, OMP_TSS_TRAIT_SELECTORS (tss1),
@@ -1985,26 +2088,51 @@ omp_context_selector_compare (tree ctx1, tree ctx2)
 }
 
 /* From context selector CTX, return trait-selector with name SEL in
-   trait-selector-set with name SET if any, or NULL_TREE if not found.
-   If SEL is NULL, return the list of trait-selectors in SET.  */
+   trait-selector-set with name SET if any, or NULL_TREE if not found.  */
+tree
+omp_get_context_selector (tree ctx, enum omp_tss_code set,
+			  enum omp_ts_code sel)
+{
+  for (tree tss = ctx; tss; tss = TREE_CHAIN (tss))
+    if (OMP_TSS_CODE (tss) == set)
+      for (tree ts = OMP_TSS_TRAIT_SELECTORS (tss); ts; ts = TREE_CHAIN (ts))
+	if (OMP_TS_CODE (ts) == sel)
+	  return ts;
+  return NULL_TREE;
+}
 
+/* Similar, but returns the whole trait-selector list for SET in CTX.  */
 tree
-omp_get_context_selector (tree ctx, const char *set, const char *sel)
+omp_get_context_selector_list (tree ctx, enum omp_tss_code set)
 {
-  tree setid = get_identifier (set);
-  tree selid = sel ? get_identifier (sel) : NULL_TREE;
   for (tree tss = ctx; tss; tss = TREE_CHAIN (tss))
-    if (OMP_TSS_ID (tss) == setid)
-      {
-	if (sel == NULL)
-	  return OMP_TSS_TRAIT_SELECTORS (tss);
-	for (tree ts = OMP_TSS_TRAIT_SELECTORS (tss); ts; ts = TREE_CHAIN (ts))
-	  if (OMP_TS_ID (ts) == selid)
-	    return ts;
-      }
+    if (OMP_TSS_CODE (tss) == set)
+      return OMP_TSS_TRAIT_SELECTORS (tss);
   return NULL_TREE;
 }
 
+/* Map string S onto a trait selector set code.  */
+enum omp_tss_code
+omp_lookup_tss_code (const char * s)
+{
+  for (int i = 0; i < OMP_TRAIT_SET_LAST; i++)
+    if (strcmp (s, omp_tss_map[i]) == 0)
+      return (enum omp_tss_code) i;
+  return OMP_TRAIT_SET_INVALID;
+}
+
+/* Map string S onto a trait selector code for set SET.  */
+enum omp_ts_code
+omp_lookup_ts_code (enum omp_tss_code set, const char *s)
+{
+  unsigned int mask = 1 << set;
+  for (int i = 0; i < OMP_TRAIT_LAST; i++)
+    if ((mask & omp_ts_map[i].tss_mask) != 0
+	&& strcmp (s, omp_ts_map[i].name) == 0)
+      return (enum omp_ts_code) i;
+  return OMP_TRAIT_INVALID;
+}
+
 /* Needs to be a GC-friendly widest_int variant, but precision is
    desirable to be the same on all targets.  */
 typedef generic_wide_int <fixed_wide_int_storage <1024> > score_wide_int;
@@ -2017,10 +2145,14 @@ typedef generic_wide_int <fixed_wide_int_storage <1024> > score_wide_int;
 static bool
 omp_context_compute_score (tree ctx, score_wide_int *score, bool declare_simd)
 {
-  tree construct = omp_get_context_selector (ctx, "construct", NULL);
-  bool has_kind = omp_get_context_selector (ctx, "device", "kind");
-  bool has_arch = omp_get_context_selector (ctx, "device", "arch");
-  bool has_isa = omp_get_context_selector (ctx, "device", "isa");
+  tree construct
+    = omp_get_context_selector_list (ctx, OMP_TRAIT_SET_CONSTRUCT);
+  bool has_kind = omp_get_context_selector (ctx, OMP_TRAIT_SET_DEVICE,
+					    OMP_TRAIT_DEVICE_KIND);
+  bool has_arch = omp_get_context_selector (ctx, OMP_TRAIT_SET_DEVICE,
+					    OMP_TRAIT_DEVICE_ARCH);
+  bool has_isa = omp_get_context_selector (ctx, OMP_TRAIT_SET_DEVICE,
+					   OMP_TRAIT_DEVICE_ISA);
   bool ret = false;
   *score = 1;
   for (tree tss = ctx; tss; tss = TREE_CHAIN (tss))
@@ -2035,15 +2167,17 @@ omp_context_compute_score (tree ctx, score_wide_int *score, bool declare_simd)
 
   if (construct || has_kind || has_arch || has_isa)
     {
-      int scores[12];
-      enum tree_code constructs[5];
-      int nconstructs = 0;
+      int nconstructs = construct ? list_length (construct) : 1;
+      enum tree_code *constructs
+	= (enum tree_code *) alloca (nconstructs * sizeof (enum tree_code));
       if (construct)
 	nconstructs = omp_construct_traits_to_codes (construct, constructs);
+      int b = declare_simd ? nconstructs + 1 : 0;
+      int *scores
+	= (int *) alloca ((b + nconstructs + 3) * sizeof (int));
       if (omp_construct_selector_matches (constructs, nconstructs, scores)
 	  == 2)
 	ret = true;
-      int b = declare_simd ? nconstructs + 1 : 0;
       if (scores[b + nconstructs] + 4U < score->get_precision ())
 	{
 	  for (int n = 0; n < nconstructs; ++n)
diff --git a/gcc/omp-general.h b/gcc/omp-general.h
index dc5e5f6ba1f..ecdd9aa9022 100644
--- a/gcc/omp-general.h
+++ b/gcc/omp-general.h
@@ -135,8 +135,83 @@ struct omp_for_data
 #define OMP_TP_VALUE(NODE) \
   TREE_VALUE (NODE)
 
-extern tree make_trait_set_selector (tree, tree, tree);
-extern tree make_trait_selector (tree, tree, tree, tree);
+/* Data structures for context selectors.  */
+
+/* Trait set selector keywords.  */
+enum omp_tss_code {
+  OMP_TRAIT_SET_CONSTRUCT,
+  OMP_TRAIT_SET_DEVICE,
+  OMP_TRAIT_SET_TARGET_DEVICE,
+  OMP_TRAIT_SET_IMPLEMENTATION,
+  OMP_TRAIT_SET_USER,
+  OMP_TRAIT_SET_LAST,
+  OMP_TRAIT_SET_INVALID = -1
+};
+
+/* Trait selector keywords.  */
+enum omp_ts_code {
+  OMP_TRAIT_DEVICE_KIND,
+  OMP_TRAIT_DEVICE_ISA,
+  OMP_TRAIT_DEVICE_ARCH,
+  OMP_TRAIT_DEVICE_NUM,
+  OMP_TRAIT_IMPLEMENTATION_VENDOR,
+  OMP_TRAIT_IMPLEMENTATION_EXTENSION,
+  OMP_TRAIT_IMPLEMENTATION_ADMO,
+  OMP_TRAIT_IMPLEMENTATION_REQUIRES,
+  OMP_TRAIT_IMPLEMENTATION_UNIFIED_ADDRESS,
+  OMP_TRAIT_IMPLEMENTATION_UNIFIED_SHARED_MEMORY,
+  OMP_TRAIT_IMPLEMENTATION_DYNAMIC_ALLOCATORS,
+  OMP_TRAIT_IMPLEMENTATION_REVERSE_OFFLOAD,
+  OMP_TRAIT_USER_CONDITION,
+  OMP_TRAIT_CONSTRUCT_TARGET,
+  OMP_TRAIT_CONSTRUCT_TEAMS,
+  OMP_TRAIT_CONSTRUCT_PARALLEL,
+  OMP_TRAIT_CONSTRUCT_FOR,
+  OMP_TRAIT_CONSTRUCT_SIMD,
+  OMP_TRAIT_LAST,
+  OMP_TRAIT_INVALID = -1
+};
+
+/* All trait property forms.  */
+enum omp_tp_type {
+  OMP_TRAIT_PROPERTY_NONE,
+  OMP_TRAIT_PROPERTY_ID,
+  OMP_TRAIT_PROPERTY_NAME_LIST,
+  OMP_TRAIT_PROPERTY_EXPR,
+  OMP_TRAIT_PROPERTY_CLAUSE_LIST,
+  OMP_TRAIT_PROPERTY_EXTENSION
+};
+
+/* Map trait set selector name keywords onto strings.  */
+extern const char *omp_tss_map [];
+
+/* Map trait selector keywords onto strings, allowed contexts, and
+   allowed property names for OMP_TRAIT_PROPERTY_NAME_LIST and
+   OMP_TRAIT_PROPERTY_ID properties.  If valid_properties is null,
+   it means that any required checking has to be done explicitly
+   somewhere instead of being driven by the table.  Otherwise it's a
+   null-terminated array of strings.  */
+struct omp_ts_info {
+  const char *name;
+  unsigned int tss_mask;
+  enum omp_tp_type tp_type;
+  bool allow_score;
+  const char * const *valid_properties;
+};
+extern struct omp_ts_info omp_ts_map[];
+
+#define OMP_TSS_CODE(t)						\
+  ((enum omp_tss_code) TREE_INT_CST_LOW (OMP_TSS_ID (t)))
+#define OMP_TSS_NAME(t)			\
+  (omp_tss_map[OMP_TSS_CODE (t)])
+
+#define OMP_TS_CODE(t)						\
+  ((enum omp_ts_code) TREE_INT_CST_LOW (OMP_TS_ID (t)))
+#define OMP_TS_NAME(t)			\
+  (omp_ts_map[OMP_TS_CODE (t)].name)
+
+extern tree make_trait_set_selector (enum omp_tss_code, tree, tree);
+extern tree make_trait_selector (enum omp_ts_code, tree, tree, tree);
 extern tree make_trait_property (tree, tree, tree);
 
 extern tree omp_find_clause (tree clauses, enum omp_clause_code kind);
@@ -158,8 +233,12 @@ extern tree omp_check_context_selector (location_t loc, tree ctx);
 extern void omp_mark_declare_variant (location_t loc, tree variant,
 				      tree construct);
 extern int omp_context_selector_matches (tree);
-extern int omp_context_selector_set_compare (const char *, tree, tree);
-extern tree omp_get_context_selector (tree, const char *, const char *);
+extern int omp_context_selector_set_compare (enum omp_tss_code, tree, tree);
+extern tree omp_get_context_selector (tree, enum omp_tss_code,
+				      enum omp_ts_code);
+extern tree omp_get_context_selector_list (tree, enum omp_tss_code);
+extern enum omp_tss_code omp_lookup_tss_code (const char *);
+extern enum omp_ts_code omp_lookup_ts_code (enum omp_tss_code, const char *);
 extern tree omp_resolve_declare_variant (tree);
 extern tree oacc_launch_pack (unsigned code, tree device, unsigned op);
 extern tree oacc_replace_fn_attrib_attr (tree attribs, tree dims);
-- 
2.31.1


^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: [PATCH 0/3] OpenMP: Improve data abstractions for context selectors
  2023-11-19  9:21 [PATCH 0/3] OpenMP: Improve data abstractions for context selectors Sandra Loosemore
                   ` (2 preceding siblings ...)
  2023-11-19  9:21 ` [PATCH 3/3] OpenMP: Use enumerators for names of trait-sets and traits Sandra Loosemore
@ 2023-11-20 10:32 ` Julian Brown
  2023-11-22 16:22 ` [PATCH V2 3/3] OpenMP: Use enumerators for names of trait-sets and traits Sandra Loosemore
  4 siblings, 0 replies; 9+ messages in thread
From: Julian Brown @ 2023-11-20 10:32 UTC (permalink / raw)
  To: gcc-patches; +Cc: jakub, tobias

On Sun, 19 Nov 2023 02:21:48 -0700
Sandra Loosemore <sandra@codesourcery.com> wrote:

> This series of patches adds a layer of data abstraction, using at
> least slightly more descriptive names, and then tries to address some
> of the representation and coding issues.
> 
> Part 1 introduces some macros (e.g., OMP_TSS_ID instead of
> TREE_PURPOSE to get the name of a selector) and renames a bunch of
> variables (e.g., tss for a trait-set selector, ts for a trait
> selector, tp for a trait property).  Those changes were relatively
> mechanical.  I also added some abstraction for the trait-score so that
> it need not be handled explicitly when processing property lists.
> 
> Part 2 changes the representation of name-list properties so that both
> the string and identifier forms store the name in the same place.
> 
> Part 3 is a more radical change: it replaces the string names of
> trait-set and trait selectors with enumerators, which allows clean-up
> of those funky switch statements.  I also made things more
> table-driven.  Alas, this part is still WIP; there's an ICE in one of
> the test cases I haven't been able to track down yet.
> 
> I can continue to work on this patch set in the next couple of weeks
> if the general direction is seen as a good thing.  I believe there is
> a little more latitude re the end of stage 1 with OpenMP (as there is
> with target-specific patches) since it is not enabled by default; in
> any case I'd like to get feedback on the general direction before
> continuing too much farther with this, and adapting the metadirective
> patches to match it.

FWIW, these changes look good to me (I've been working with these data
structures in the context of adding another OpenMP feature).

I wonder if this bit might be relevant to the ICE you see in the 3rd
patch (from my WIP patches):

@@ -1247,12 +1247,17 @@ omp_mark_declare_variant (location_t loc, tree variant, tree construct)
       DECL_ATTRIBUTES (variant) = attr;
       return;
     }
+#if 0
+  /* I think this might be bogus.  It compares an extracted "construct"
+     selector set (containing e.g. just "target") with a complete context
+     selector ("construct target", ...).  */
   if ((TREE_VALUE (attr) != NULL_TREE) != (construct != NULL_TREE)
       || (construct != NULL_TREE
          && omp_context_selector_set_compare ("construct", TREE_VALUE (attr),
                                               construct)))
     error_at (loc, "%qD used as a variant with incompatible %<construct%> "
                   "selector sets", variant);
+#endif
 }

Perhaps not (it could be a bug in my own code or understanding), but
maybe!

HTH,

Julian



^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: [PATCH 3/3] OpenMP: Use enumerators for names of trait-sets and traits
  2023-11-19  9:21 ` [PATCH 3/3] OpenMP: Use enumerators for names of trait-sets and traits Sandra Loosemore
@ 2023-11-21 20:48   ` Sandra Loosemore
  0 siblings, 0 replies; 9+ messages in thread
From: Sandra Loosemore @ 2023-11-21 20:48 UTC (permalink / raw)
  To: gcc-patches; +Cc: jakub, tobias, Julian Brown

On 11/19/23 02:21, Sandra Loosemore wrote:
> This patch introduces enumerators to represent trait-set names and
> trait names, which makes it easier to use tables to control other
> behavior and for switch statements to dispatch on the tags.  The tags
> are stored in the same place in the TREE_LIST structure (OMP_TSS_ID or
> OMP_TS_ID) and are encoded there as integer constants.
> 
> This patch has only been lightly tested and still has at least one bug
> that causes an ICE.  :-(

Update: I've tracked down the ICE to me having introduced an incorrect variable 
initialization in omp_context_compute_score.  I'm now looking at fixing 
interfaces to avoid the separate bug in omp_mark_declare_variant that Julian 
reported, and I'll post a revised part 3 in the next day or two.

-Sandra

^ permalink raw reply	[flat|nested] 9+ messages in thread

* [PATCH V2 3/3] OpenMP: Use enumerators for names of trait-sets and traits
  2023-11-19  9:21 [PATCH 0/3] OpenMP: Improve data abstractions for context selectors Sandra Loosemore
                   ` (3 preceding siblings ...)
  2023-11-20 10:32 ` [PATCH 0/3] OpenMP: Improve data abstractions for context selectors Julian Brown
@ 2023-11-22 16:22 ` Sandra Loosemore
  2023-11-27 17:19   ` Tobias Burnus
  4 siblings, 1 reply; 9+ messages in thread
From: Sandra Loosemore @ 2023-11-22 16:22 UTC (permalink / raw)
  To: gcc-patches; +Cc: jakub, tobias, julian

This patch introduces enumerators to represent trait-set names and
trait names, which makes it easier to use tables to control other
behavior and for switch statements to dispatch on the tags.  The tags
are stored in the same place in the TREE_LIST structure (OMP_TSS_ID or
OMP_TS_ID) and are encoded there as integer constants.

gcc/ChangeLog
	* omp-general.h (enum omp_tss_code): New.
	(enum omp_ts_code): New.
	(enum omp_tp_type): New.
	(omp_tss_map): New.
	(struct omp_ts_info): New.
	(omp_ts_map): New.
	(OMP_TSS_CODE, OMP_TSS_NAME): New.
	(OMP_TS_CODE, OMP_TS_NAME): New.
	(make_trait_set_selector, make_trait_selector): Adjust declarations.
	(omp_construct_traits_to_codes): Likewise.
	(omp_context_selector_set_compare): Likewise.
	(omp_get_context_selector): Likewise.
	(omp_get_context_selector_list): New.
	(omp_lookup_tss_code): New.
	(omp_lookup_ts_code): New.
	* omp-general.cc (omp_construct_traits_to_codes): Pass length in
	as argument instead of returning it.  Make it table-driven.
	(omp_tss_map): New.
	(kind_properties, vendor_properties, extension_properties): New.
	(atomic_default_mem_order_properties): New.
	(omp_ts_map): New.
	(omp_check_context_selector): Simplify lookup and dispatch logic.
	(omp_mark_declare_variant): Adjust for new representation.
	(make_trait_set_selector, make_trait_selector): Adjust for new
	representations.
	(omp_context_selector_matches): Simplify dispatch logic.  Avoid
	fixed-sized buffers and adjust call to omp_construct_traits_to_codes.
	(omp_context_selector_props_compare): Adjust for new representations
	and simplify dispatch logic.
	(omp_context_selector_set_compare): Likewise.
	(omp_context_selector_compare): Likewise.
	(omp_get_context_selector): Adjust for new representations, and split
	out...
	(omp_get_context_selector_list): New function.
	(omp_lookup_tss_code): New.
	(omp_lookup_ts_code): New.
	(omp_context_compute_score): Adjust for new representations.  Avoid
	fixed-sized buffers and magic numbers.  Adjust call to
	omp_construct_traits_to_codes.
	* gimplify.cc (omp_construct_selector_matches): Avoid use of
	fixed-size buffer.  Adjust call to omp_construct_traits_to_codes.

gcc/c/ChangeLog
	* c-parser.cc (omp_construct_selectors): Delete.
	(omp_device_selectors): Delete.
	(omp_implementation_selectors): Delete.
	(omp_user_selectors): Delete.
	(c_parser_omp_context_selector): Adjust for new representations
	and simplify dispatch logic.
	(c_parser_omp_context_selector_specification): Likewise.
	(c_finish_omp_declare_variant): Adjust for new representations.

gcc/cp/ChangeLog
	* decl.cc (omp_declare_variant_finalize_one): Adjust for new
	representations.
	* parser.cc (omp_construct_selectors): Delete.
	(omp_device_selectors): Delete.
	(omp_implementation_selectors): Delete.
	(omp_user_selectors): Delete.
	(cp_parser_omp_context_selector): Adjust for new representations
	and simplify dispatch logic.
	(cp_parser_omp_context_selector_specification): Likewise.
	* pt.cc (tsubst_attribute): Adjust for new representations.

gcc/fortran/ChangeLog
	* trans-openmp.cc (gfc_trans_omp_declare_variant): Adjust for
	new representations.
---
 gcc/c/c-parser.cc           | 192 ++++---------
 gcc/cp/decl.cc              |   8 +-
 gcc/cp/parser.cc            | 189 ++++---------
 gcc/cp/pt.cc                |  15 +-
 gcc/fortran/trans-openmp.cc |  41 ++-
 gcc/gimplify.cc             |  17 +-
 gcc/omp-general.cc          | 530 +++++++++++++++++++++++-------------
 gcc/omp-general.h           |  89 +++++-
 8 files changed, 590 insertions(+), 491 deletions(-)

diff --git a/gcc/c/c-parser.cc b/gcc/c/c-parser.cc
index a2ff381e0c1..70c0e1828ca 100644
--- a/gcc/c/c-parser.cc
+++ b/gcc/c/c-parser.cc
@@ -24016,16 +24016,6 @@ c_parser_omp_declare_simd (c_parser *parser, enum pragma_context context)
     }
 }
 
-static const char *const omp_construct_selectors[] = {
-  "simd", "target", "teams", "parallel", "for", NULL };
-static const char *const omp_device_selectors[] = {
-  "kind", "isa", "arch", NULL };
-static const char *const omp_implementation_selectors[] = {
-  "vendor", "extension", "atomic_default_mem_order", "unified_address",
-  "unified_shared_memory", "dynamic_allocators", "reverse_offload", NULL };
-static const char *const omp_user_selectors[] = {
-  "condition", NULL };
-
 /* OpenMP 5.0:
 
    trait-selector:
@@ -24038,7 +24028,8 @@ static const char *const omp_user_selectors[] = {
    trait-selector-set SET.  */
 
 static tree
-c_parser_omp_context_selector (c_parser *parser, tree set, tree parms)
+c_parser_omp_context_selector (c_parser *parser, enum omp_tss_code set,
+			       tree parms)
 {
   tree ret = NULL_TREE;
   do
@@ -24052,80 +24043,52 @@ c_parser_omp_context_selector (c_parser *parser, tree set, tree parms)
 	  c_parser_error (parser, "expected trait selector name");
 	  return error_mark_node;
 	}
+      enum omp_ts_code sel
+	= omp_lookup_ts_code (set, IDENTIFIER_POINTER (selector));
 
-      tree properties = NULL_TREE;
-      tree scoreval = NULL_TREE;
-      const char *const *selectors = NULL;
-      bool allow_score = true;
-      bool allow_user = false;
-      int property_limit = 0;
-      enum { CTX_PROPERTY_NONE, CTX_PROPERTY_USER, CTX_PROPERTY_NAME_LIST,
-	     CTX_PROPERTY_ID, CTX_PROPERTY_EXPR,
-	     CTX_PROPERTY_SIMD } property_kind = CTX_PROPERTY_NONE;
-      switch (IDENTIFIER_POINTER (set)[0])
-	{
-	case 'c': /* construct */
-	  selectors = omp_construct_selectors;
-	  allow_score = false;
-	  property_limit = 1;
-	  property_kind = CTX_PROPERTY_SIMD;
-	  break;
-	case 'd': /* device */
-	  selectors = omp_device_selectors;
-	  allow_score = false;
-	  allow_user = true;
-	  property_limit = 3;
-	  property_kind = CTX_PROPERTY_NAME_LIST;
-	  break;
-	case 'i': /* implementation */
-	  selectors = omp_implementation_selectors;
-	  allow_user = true;
-	  property_limit = 3;
-	  property_kind = CTX_PROPERTY_NAME_LIST;
-	  break;
-	case 'u': /* user */
-	  selectors = omp_user_selectors;
-	  property_limit = 1;
-	  property_kind = CTX_PROPERTY_EXPR;
-	  break;
-	default:
-	  gcc_unreachable ();
-	}
-      for (int i = 0; ; i++)
+      if (sel == OMP_TRAIT_INVALID)
 	{
-	  if (selectors[i] == NULL)
+	  /* Some trait sets permit extension traits which are supposed
+	     to be ignored if the implementation doesn't support them.
+	     GCC does not support any extension traits, and if it did, they
+	     would have their own identifiers.  */
+	  if (set == OMP_TRAIT_SET_IMPLEMENTATION
+	      || set == OMP_TRAIT_SET_DEVICE
+	      || set == OMP_TRAIT_SET_TARGET_DEVICE)
 	    {
-	      if (allow_user)
-		{
-		  property_kind = CTX_PROPERTY_USER;
-		  break;
-		}
-	      else
+	      c_parser_consume_token (parser);
+	      if (c_parser_next_token_is (parser, CPP_OPEN_PAREN))
+		c_parser_balanced_token_sequence (parser);
+	      if (c_parser_next_token_is (parser, CPP_COMMA))
 		{
-		  error_at (c_parser_peek_token (parser)->location,
-			    "selector %qs not allowed for context selector "
-			    "set %qs", IDENTIFIER_POINTER (selector),
-			    IDENTIFIER_POINTER (set));
 		  c_parser_consume_token (parser);
-		  return error_mark_node;
+		  continue;
 		}
+	      else
+		break;
+	    }
+	  else
+	    {
+	      error_at (c_parser_peek_token (parser)->location,
+			"selector %qs not allowed for context selector "
+			"set %qs", IDENTIFIER_POINTER (selector),
+			omp_tss_map[set]);
+	      c_parser_consume_token (parser);
+	      return error_mark_node;
 	    }
-	  if (i == property_limit)
-	    property_kind = CTX_PROPERTY_NONE;
-	  if (strcmp (selectors[i], IDENTIFIER_POINTER (selector)) == 0)
-	    break;
 	}
-      if (property_kind == CTX_PROPERTY_NAME_LIST
-	  && IDENTIFIER_POINTER (set)[0] == 'i'
-	  && strcmp (IDENTIFIER_POINTER (selector),
-		     "atomic_default_mem_order") == 0)
-	property_kind = CTX_PROPERTY_ID;
 
       c_parser_consume_token (parser);
 
+      tree properties = NULL_TREE;
+      tree scoreval = NULL_TREE;
+      enum omp_tp_type property_kind = omp_ts_map[sel].tp_type;
+      bool allow_score = omp_ts_map[sel].allow_score;
+      tree t;
+
       if (c_parser_next_token_is (parser, CPP_OPEN_PAREN))
 	{
-	  if (property_kind == CTX_PROPERTY_NONE)
+	  if (property_kind == OMP_TRAIT_PROPERTY_NONE)
 	    {
 	      error_at (c_parser_peek_token (parser)->location,
 			"selector %qs does not accept any properties",
@@ -24168,38 +24131,7 @@ c_parser_omp_context_selector (c_parser *parser, tree set, tree parms)
 
 	  switch (property_kind)
 	    {
-	      tree t;
-	    case CTX_PROPERTY_USER:
-	      do
-		{
-		  t = c_parser_expr_no_commas (parser, NULL).value;
-		  if (TREE_CODE (t) == STRING_CST)
-		    properties = make_trait_property (NULL_TREE, t,
-						      properties);
-		  else if (t != error_mark_node)
-		    {
-		      mark_exp_read (t);
-		      t = c_fully_fold (t, false, NULL);
-		      if (!INTEGRAL_TYPE_P (TREE_TYPE (t))
-			  || !tree_fits_shwi_p (t))
-			error_at (token->location, "property must be "
-				  "constant integer expression or string "
-				  "literal");
-		      else
-			properties = make_trait_property (NULL_TREE, t,
-							  properties);
-		    }
-		  else
-		    return error_mark_node;
-
-		  if (c_parser_next_token_is (parser, CPP_COMMA))
-		    c_parser_consume_token (parser);
-		  else
-		    break;
-		}
-	      while (1);
-	      break;
-	    case CTX_PROPERTY_ID:
+	    case OMP_TRAIT_PROPERTY_ID:
 	      if (c_parser_next_token_is (parser, CPP_KEYWORD)
 		  || c_parser_next_token_is (parser, CPP_NAME))
 		{
@@ -24214,7 +24146,7 @@ c_parser_omp_context_selector (c_parser *parser, tree set, tree parms)
 		  return error_mark_node;
 		}
 	      break;
-	    case CTX_PROPERTY_NAME_LIST:
+	    case OMP_TRAIT_PROPERTY_NAME_LIST:
 	      do
 		{
 		  tree prop = OMP_TP_NAMELIST_NODE;
@@ -24244,12 +24176,14 @@ c_parser_omp_context_selector (c_parser *parser, tree set, tree parms)
 		}
 	      while (1);
 	      break;
-	    case CTX_PROPERTY_EXPR:
+	    case OMP_TRAIT_PROPERTY_EXPR:
 	      t = c_parser_expr_no_commas (parser, NULL).value;
 	      if (t != error_mark_node)
 		{
 		  mark_exp_read (t);
 		  t = c_fully_fold (t, false, NULL);
+		  /* FIXME: this is bogus, both device_num and
+		     condition selectors allow arbitrary expressions.  */
 		  if (!INTEGRAL_TYPE_P (TREE_TYPE (t))
 		      || !tree_fits_shwi_p (t))
 		    error_at (token->location, "property must be "
@@ -24261,7 +24195,9 @@ c_parser_omp_context_selector (c_parser *parser, tree set, tree parms)
 	      else
 		return error_mark_node;
 	      break;
-	    case CTX_PROPERTY_SIMD:
+	    case OMP_TRAIT_PROPERTY_CLAUSE_LIST:
+	      gcc_assert (sel == OMP_TRAIT_CONSTRUCT_SIMD);
+
 	      if (parms == NULL_TREE)
 		{
 		  error_at (token->location, "properties for %<simd%> "
@@ -24286,15 +24222,15 @@ c_parser_omp_context_selector (c_parser *parser, tree set, tree parms)
 	  parens.skip_until_found_close (parser);
 	  properties = nreverse (properties);
 	}
-      else if (property_kind == CTX_PROPERTY_NAME_LIST
-	       || property_kind == CTX_PROPERTY_ID
-	       || property_kind == CTX_PROPERTY_EXPR)
+      else if (property_kind != OMP_TRAIT_PROPERTY_NONE
+	       && property_kind != OMP_TRAIT_PROPERTY_CLAUSE_LIST
+	       && property_kind != OMP_TRAIT_PROPERTY_EXTENSION)
 	{
 	  c_parser_require (parser, CPP_OPEN_PAREN, "expected %<(%>");
 	  return error_mark_node;
 	}
 
-      ret = make_trait_selector (selector, scoreval, properties, ret);
+      ret = make_trait_selector (sel, scoreval, properties, ret);
 
       if (c_parser_next_token_is (parser, CPP_COMMA))
 	c_parser_consume_token (parser);
@@ -24328,35 +24264,17 @@ c_parser_omp_context_selector_specification (c_parser *parser, tree parms)
       const char *setp = "";
       if (c_parser_next_token_is (parser, CPP_NAME))
 	setp = IDENTIFIER_POINTER (c_parser_peek_token (parser)->value);
-      switch (setp[0])
-	{
-	case 'c':
-	  if (strcmp (setp, "construct") == 0)
-	    setp = NULL;
-	  break;
-	case 'd':
-	  if (strcmp (setp, "device") == 0)
-	    setp = NULL;
-	  break;
-	case 'i':
-	  if (strcmp (setp, "implementation") == 0)
-	    setp = NULL;
-	  break;
-	case 'u':
-	  if (strcmp (setp, "user") == 0)
-	    setp = NULL;
-	  break;
-	default:
-	  break;
-	}
-      if (setp)
+      enum omp_tss_code set = omp_lookup_tss_code (setp);
+
+      if (set == OMP_TRAIT_SET_INVALID)
 	{
+	  /* FIXME: hardwired list of names here is incomplete and
+	     liable to bit-rot.  */
 	  c_parser_error (parser, "expected %<construct%>, %<device%>, "
 				  "%<implementation%> or %<user%>");
 	  return error_mark_node;
 	}
 
-      tree set = c_parser_peek_token (parser)->value;
       c_parser_consume_token (parser);
 
       if (!c_parser_require (parser, CPP_EQ, "expected %<=%>"))
@@ -24453,7 +24371,8 @@ c_finish_omp_declare_variant (c_parser *parser, tree fndecl, tree parms)
 	  error_at (token->location, "variant %qD is not a function", variant);
 	  variant = error_mark_node;
 	}
-      else if (omp_get_context_selector (ctx, "construct", "simd") == NULL_TREE
+      else if (!omp_get_context_selector (ctx, OMP_TRAIT_SET_CONSTRUCT,
+					  OMP_TRAIT_CONSTRUCT_SIMD)
 	       && !comptypes (TREE_TYPE (fndecl), TREE_TYPE (variant)))
 	{
 	  error_at (token->location, "variant %qD and base %qD have "
@@ -24474,7 +24393,8 @@ c_finish_omp_declare_variant (c_parser *parser, tree fndecl, tree parms)
       if (variant != error_mark_node)
 	{
 	  C_DECL_USED (variant) = 1;
-	  tree construct = omp_get_context_selector (ctx, "construct", NULL);
+	  tree construct
+	    = omp_get_context_selector_list (ctx, OMP_TRAIT_SET_CONSTRUCT);
 	  omp_mark_declare_variant (match_loc, variant, construct);
 	  if (omp_context_selector_matches (ctx))
 	    {
diff --git a/gcc/cp/decl.cc b/gcc/cp/decl.cc
index b8e1098d482..70693af9cc8 100644
--- a/gcc/cp/decl.cc
+++ b/gcc/cp/decl.cc
@@ -8042,12 +8042,13 @@ omp_declare_variant_finalize_one (tree decl, tree attr)
     }
 
   tree ctx = TREE_VALUE (TREE_VALUE (attr));
-  tree simd = omp_get_context_selector (ctx, "construct", "simd");
+  tree simd = omp_get_context_selector (ctx, OMP_TRAIT_SET_CONSTRUCT,
+					OMP_TRAIT_CONSTRUCT_SIMD);
   if (simd)
     {
       TREE_VALUE (simd)
 	= c_omp_declare_simd_clauses_to_numbers (DECL_ARGUMENTS (decl),
-						 TREE_VALUE (simd));
+						 OMP_TS_PROPERTIES (simd));
       /* FIXME, adjusting simd args unimplemented.  */
       return true;
     }
@@ -8140,7 +8141,8 @@ omp_declare_variant_finalize_one (tree decl, tree attr)
 	}
       else
 	{
-	  tree construct = omp_get_context_selector (ctx, "construct", NULL);
+	  tree construct
+	    = omp_get_context_selector_list (ctx, OMP_TRAIT_SET_CONSTRUCT);
 	  omp_mark_declare_variant (match_loc, variant, construct);
 	  if (!omp_context_selector_matches (ctx))
 	    return true;
diff --git a/gcc/cp/parser.cc b/gcc/cp/parser.cc
index 9030365644d..6f5514d40c9 100644
--- a/gcc/cp/parser.cc
+++ b/gcc/cp/parser.cc
@@ -47255,16 +47255,6 @@ cp_parser_omp_declare_simd (cp_parser *parser, cp_token *pragma_tok,
     }
 }
 
-static const char *const omp_construct_selectors[] = {
-  "simd", "target", "teams", "parallel", "for", NULL };
-static const char *const omp_device_selectors[] = {
-  "kind", "isa", "arch", NULL };
-static const char *const omp_implementation_selectors[] = {
-  "vendor", "extension", "atomic_default_mem_order", "unified_address",
-  "unified_shared_memory", "dynamic_allocators", "reverse_offload", NULL };
-static const char *const omp_user_selectors[] = {
-  "condition", NULL };
-
 /* OpenMP 5.0:
 
    trait-selector:
@@ -47277,7 +47267,8 @@ static const char *const omp_user_selectors[] = {
    trait-selector-set SET.  */
 
 static tree
-cp_parser_omp_context_selector (cp_parser *parser, tree set, bool has_parms_p)
+cp_parser_omp_context_selector (cp_parser *parser, enum omp_tss_code set,
+				bool has_parms_p)
 {
   tree ret = NULL_TREE;
   do
@@ -47292,78 +47283,53 @@ cp_parser_omp_context_selector (cp_parser *parser, tree set, bool has_parms_p)
 	  return error_mark_node;
 	}
 
-      tree properties = NULL_TREE;
-      tree scoreval = NULL_TREE;
-      const char *const *selectors = NULL;
-      bool allow_score = true;
-      bool allow_user = false;
-      int property_limit = 0;
-      enum { CTX_PROPERTY_NONE, CTX_PROPERTY_USER, CTX_PROPERTY_NAME_LIST,
-	     CTX_PROPERTY_ID, CTX_PROPERTY_EXPR,
-	     CTX_PROPERTY_SIMD } property_kind = CTX_PROPERTY_NONE;
-      switch (IDENTIFIER_POINTER (set)[0])
-	{
-	case 'c': /* construct */
-	  selectors = omp_construct_selectors;
-	  allow_score = false;
-	  property_limit = 1;
-	  property_kind = CTX_PROPERTY_SIMD;
-	  break;
-	case 'd': /* device */
-	  selectors = omp_device_selectors;
-	  allow_score = false;
-	  allow_user = true;
-	  property_limit = 3;
-	  property_kind = CTX_PROPERTY_NAME_LIST;
-	  break;
-	case 'i': /* implementation */
-	  selectors = omp_implementation_selectors;
-	  allow_user = true;
-	  property_limit = 3;
-	  property_kind = CTX_PROPERTY_NAME_LIST;
-	  break;
-	case 'u': /* user */
-	  selectors = omp_user_selectors;
-	  property_limit = 1;
-	  property_kind = CTX_PROPERTY_EXPR;
-	  break;
-	default:
-	  gcc_unreachable ();
-	}
-      for (int i = 0; ; i++)
+      enum omp_ts_code sel
+	= omp_lookup_ts_code (set, IDENTIFIER_POINTER (selector));
+
+      if (sel == OMP_TRAIT_INVALID)
 	{
-	  if (selectors[i] == NULL)
+	  /* Some trait sets permit extension traits which are supposed
+	     to be ignored if the implementation doesn't support them.
+	     GCC does not support any extension traits, and if it did, they
+	     would have their own identifiers.  */
+	  if (set == OMP_TRAIT_SET_IMPLEMENTATION
+	      || set == OMP_TRAIT_SET_DEVICE
+	      || set == OMP_TRAIT_SET_TARGET_DEVICE)
 	    {
-	      if (allow_user)
-		{
-		  property_kind = CTX_PROPERTY_USER;
-		  break;
-		}
-	      else
+	      cp_lexer_consume_token (parser->lexer);
+	      if (cp_lexer_next_token_is (parser->lexer, CPP_OPEN_PAREN))
+		for (size_t n = cp_parser_skip_balanced_tokens (parser, 1) - 1;
+		     n; --n)
+		  cp_lexer_consume_token (parser->lexer);
+	      if (cp_lexer_next_token_is (parser->lexer, CPP_COMMA))
 		{
-		  error ("selector %qs not allowed for context selector "
-			 "set %qs", IDENTIFIER_POINTER (selector),
-			 IDENTIFIER_POINTER (set));
 		  cp_lexer_consume_token (parser->lexer);
-		  return error_mark_node;
+		  continue;
 		}
+	      else
+		break;
+	    }
+	  else
+	    {
+	      error_at (cp_lexer_peek_token (parser->lexer)->location,
+			"selector %qs not allowed for context selector "
+			"set %qs", IDENTIFIER_POINTER (selector),
+			omp_tss_map[set]);
+	      cp_lexer_consume_token (parser->lexer);
+	      return error_mark_node;
 	    }
-	  if (i == property_limit)
-	    property_kind = CTX_PROPERTY_NONE;
-	  if (strcmp (selectors[i], IDENTIFIER_POINTER (selector)) == 0)
-	    break;
 	}
-      if (property_kind == CTX_PROPERTY_NAME_LIST
-	  && IDENTIFIER_POINTER (set)[0] == 'i'
-	  && strcmp (IDENTIFIER_POINTER (selector),
-		     "atomic_default_mem_order") == 0)
-	property_kind = CTX_PROPERTY_ID;
-
       cp_lexer_consume_token (parser->lexer);
 
+      tree properties = NULL_TREE;
+      tree scoreval = NULL_TREE;
+      enum omp_tp_type property_kind = omp_ts_map[sel].tp_type;
+      bool allow_score = omp_ts_map[sel].allow_score;
+      tree t;
+
       if (cp_lexer_next_token_is (parser->lexer, CPP_OPEN_PAREN))
 	{
-	  if (property_kind == CTX_PROPERTY_NONE)
+	  if (property_kind == OMP_TRAIT_PROPERTY_NONE)
 	    {
 	      error ("selector %qs does not accept any properties",
 		     IDENTIFIER_POINTER (selector));
@@ -47420,38 +47386,7 @@ cp_parser_omp_context_selector (cp_parser *parser, tree set, bool has_parms_p)
 
 	  switch (property_kind)
 	    {
-	      tree t;
-	    case CTX_PROPERTY_USER:
-	      do
-		{
-		  t = cp_parser_constant_expression (parser);
-		  if (t != error_mark_node)
-		    {
-		      t = fold_non_dependent_expr (t);
-		      if (TREE_CODE (t) == STRING_CST)
-			properties = make_trait_property (NULL_TREE, t,
-							  properties);
-		      else if (!value_dependent_expression_p (t)
-			       && (!INTEGRAL_TYPE_P (TREE_TYPE (t))
-				   || !tree_fits_shwi_p (t)))
-			error_at (token->location, "property must be "
-				  "constant integer expression or string "
-				  "literal");
-		      else
-			properties = make_trait_property (NULL_TREE, t,
-							  properties);
-		    }
-		  else
-		    return error_mark_node;
-
-		  if (cp_lexer_next_token_is (parser->lexer, CPP_COMMA))
-		    cp_lexer_consume_token (parser->lexer);
-		  else
-		    break;
-		}
-	      while (1);
-	      break;
-	    case CTX_PROPERTY_ID:
+	    case OMP_TRAIT_PROPERTY_ID:
 	      if (cp_lexer_next_token_is (parser->lexer, CPP_KEYWORD)
 		  || cp_lexer_next_token_is (parser->lexer, CPP_NAME))
 		{
@@ -47466,7 +47401,7 @@ cp_parser_omp_context_selector (cp_parser *parser, tree set, bool has_parms_p)
 		  return error_mark_node;
 		}
 	      break;
-	    case CTX_PROPERTY_NAME_LIST:
+	    case OMP_TRAIT_PROPERTY_NAME_LIST:
 	      do
 		{
 		  tree prop = OMP_TP_NAMELIST_NODE;
@@ -47497,7 +47432,9 @@ cp_parser_omp_context_selector (cp_parser *parser, tree set, bool has_parms_p)
 		}
 	      while (1);
 	      break;
-	    case CTX_PROPERTY_EXPR:
+	    case OMP_TRAIT_PROPERTY_EXPR:
+	      /* FIXME: this is bogus, the expression need
+		 not be constant.  */
 	      t = cp_parser_constant_expression (parser);
 	      if (t != error_mark_node)
 		{
@@ -47514,7 +47451,9 @@ cp_parser_omp_context_selector (cp_parser *parser, tree set, bool has_parms_p)
 	      else
 		return error_mark_node;
 	      break;
-	    case CTX_PROPERTY_SIMD:
+	    case OMP_TRAIT_PROPERTY_CLAUSE_LIST:
+	      gcc_assert (sel == OMP_TRAIT_CONSTRUCT_SIMD);
+
 	      if (!has_parms_p)
 		{
 		  error_at (token->location, "properties for %<simd%> "
@@ -47536,15 +47475,15 @@ cp_parser_omp_context_selector (cp_parser *parser, tree set, bool has_parms_p)
 
 	  properties = nreverse (properties);
 	}
-      else if (property_kind == CTX_PROPERTY_NAME_LIST
-	       || property_kind == CTX_PROPERTY_ID
-	       || property_kind == CTX_PROPERTY_EXPR)
+      else if (property_kind != OMP_TRAIT_PROPERTY_NONE
+	       && property_kind != OMP_TRAIT_PROPERTY_CLAUSE_LIST
+	       && property_kind != OMP_TRAIT_PROPERTY_EXTENSION)
 	{
 	  cp_parser_require (parser, CPP_OPEN_PAREN, RT_OPEN_PAREN);
 	  return error_mark_node;
 	}
 
-      ret = make_trait_selector (selector, scoreval, properties, ret);
+      ret = make_trait_selector (sel, scoreval, properties, ret);
 
       if (cp_lexer_next_token_is (parser->lexer, CPP_COMMA))
 	cp_lexer_consume_token (parser->lexer);
@@ -47580,35 +47519,17 @@ cp_parser_omp_context_selector_specification (cp_parser *parser,
       if (cp_lexer_next_token_is (parser->lexer, CPP_NAME))
 	setp
 	  = IDENTIFIER_POINTER (cp_lexer_peek_token (parser->lexer)->u.value);
-      switch (setp[0])
-	{
-	case 'c':
-	  if (strcmp (setp, "construct") == 0)
-	    setp = NULL;
-	  break;
-	case 'd':
-	  if (strcmp (setp, "device") == 0)
-	    setp = NULL;
-	  break;
-	case 'i':
-	  if (strcmp (setp, "implementation") == 0)
-	    setp = NULL;
-	  break;
-	case 'u':
-	  if (strcmp (setp, "user") == 0)
-	    setp = NULL;
-	  break;
-	default:
-	  break;
-	}
-      if (setp)
+      enum omp_tss_code set = omp_lookup_tss_code (setp);
+
+      if (set == OMP_TRAIT_SET_INVALID)
 	{
+	  /* FIXME: hardwired list of names here is incomplete and
+	     liable to bit-rot.  */
 	  cp_parser_error (parser, "expected %<construct%>, %<device%>, "
 				   "%<implementation%> or %<user%>");
 	  return error_mark_node;
 	}
 
-      tree set = cp_lexer_peek_token (parser->lexer)->u.value;
       cp_lexer_consume_token (parser->lexer);
 
       if (!cp_parser_require (parser, CPP_EQ, RT_EQ))
diff --git a/gcc/cp/pt.cc b/gcc/cp/pt.cc
index c3815733651..ed51a838f12 100644
--- a/gcc/cp/pt.cc
+++ b/gcc/cp/pt.cc
@@ -11841,18 +11841,20 @@ tsubst_attribute (tree t, tree *decl_p, tree args,
       tree chain = TREE_CHAIN (val);
       location_t match_loc = cp_expr_loc_or_input_loc (TREE_PURPOSE (chain));
       tree ctx = copy_list (TREE_VALUE (val));
-      tree simd = get_identifier ("simd");
-      tree condition = get_identifier ("condition");
       for (tree tss = ctx; tss; tss = TREE_CHAIN (tss))
 	{
-	  const char *set = IDENTIFIER_POINTER (OMP_TSS_ID (tss));
+	  enum omp_tss_code set = OMP_TSS_CODE (tss);
 	  tree selectors = NULL_TREE;
 	  for (tree ts = OMP_TSS_TRAIT_SELECTORS (tss); ts;
 	       ts = TREE_CHAIN (ts))
 	    {
 	      tree properties = NULL_TREE;
 	      tree scoreval = NULL_TREE;
-	      if (OMP_TS_ID (ts) == simd && set[0] == 'c')
+	      /* FIXME: The body of this loop should really be dispatching
+		 according to omp_ts_map[OMP_TS_CODE (TS)].tp_type instead
+		 of having hard-wired knowledge of specific selectors.  */
+	      if (OMP_TS_CODE (ts) == OMP_TRAIT_CONSTRUCT_SIMD
+		  && set == OMP_TRAIT_SET_CONSTRUCT)
 		{
 		  tree clauses = OMP_TS_PROPERTIES (ts);
 		  clauses = tsubst_omp_clauses (clauses,
@@ -11897,7 +11899,8 @@ tsubst_attribute (tree t, tree *decl_p, tree args,
 		    else if (OMP_TP_VALUE (p))
 		      {
 			bool allow_string
-			  = (OMP_TS_ID (ts) != condition || set[0] != 'u');
+			  = (OMP_TS_CODE (ts) != OMP_TRAIT_USER_CONDITION
+			     || set != OMP_TRAIT_SET_USER);
 			tree v = OMP_TP_VALUE (p);
 			if (TREE_CODE (v) == STRING_CST && allow_string)
 			  continue;
@@ -11921,7 +11924,7 @@ tsubst_attribute (tree t, tree *decl_p, tree args,
 			OMP_TP_VALUE (p) = v;
 		      }
 		}
-	      selectors = make_trait_selector (OMP_TS_ID (ts), scoreval,
+	      selectors = make_trait_selector (OMP_TS_CODE (ts), scoreval,
 					       properties, selectors);
 	    }
 	  OMP_TSS_TRAIT_SELECTORS (tss) = nreverse (selectors);
diff --git a/gcc/fortran/trans-openmp.cc b/gcc/fortran/trans-openmp.cc
index 60154ff3751..08e32636c9f 100644
--- a/gcc/fortran/trans-openmp.cc
+++ b/gcc/fortran/trans-openmp.cc
@@ -8208,11 +8208,34 @@ gfc_trans_omp_declare_variant (gfc_namespace *ns)
 	{
 	  tree selectors = NULL_TREE;
 	  gfc_omp_selector *os;
+	  enum omp_tss_code set
+	    = omp_lookup_tss_code (oss->trait_set_selector_name);
+	  gcc_assert (set != OMP_TRAIT_SET_INVALID);
+
 	  for (os = oss->trait_selectors; os; os = os->next)
 	    {
 	      tree scoreval = NULL_TREE;
 	      tree properties = NULL_TREE;
 	      gfc_omp_trait_property *otp;
+	      enum omp_ts_code sel;
+
+	      if (set == OMP_TRAIT_SET_CONSTRUCT
+		  && !(strcmp (os->trait_selector_name, "do")))
+		sel = OMP_TRAIT_CONSTRUCT_FOR;
+	      else
+		sel = omp_lookup_ts_code (set, os->trait_selector_name);
+
+	      /* Some trait sets permit extension traits which are supposed
+		 to be ignored if the implementation doesn't support them.
+		 GCC does not support any extension traits, and if it did,
+		 they would have their own identifiers.  */
+	      if (sel == OMP_TRAIT_INVALID
+		  && (set == OMP_TRAIT_SET_IMPLEMENTATION
+		      || set == OMP_TRAIT_SET_DEVICE
+		      || set == OMP_TRAIT_SET_TARGET_DEVICE))
+		continue;
+
+	      gcc_assert (sel != OMP_TRAIT_INVALID);
 
 	      for (otp = os->properties; otp; otp = otp->next)
 		{
@@ -8263,13 +8286,10 @@ gfc_trans_omp_declare_variant (gfc_namespace *ns)
 		  scoreval = se.expr;
 		}
 
-	      tree ts_name = get_identifier (os->trait_selector_name);
-	      selectors	= make_trait_selector (ts_name, scoreval,
+	      selectors	= make_trait_selector (sel, scoreval,
 					       properties, selectors);
 	    }
-
-	  tree tss_name = get_identifier (oss->trait_set_selector_name);
-	  set_selectors = make_trait_set_selector (tss_name, selectors,
+	  set_selectors = make_trait_set_selector (set,  selectors,
 						   set_selectors);
 	}
 
@@ -8298,8 +8318,10 @@ gfc_trans_omp_declare_variant (gfc_namespace *ns)
 			 variant_proc_name, &odv->where);
 	      variant_proc_sym = NULL;
 	    }
-	  else if (omp_get_context_selector (set_selectors, "construct",
-					     "simd") == NULL_TREE)
+	  else if (omp_get_context_selector (set_selectors,
+					     OMP_TRAIT_SET_CONSTRUCT,
+					     OMP_TRAIT_CONSTRUCT_SIMD)
+		   == NULL_TREE)
 	    {
 	      char err[256];
 	      if (!gfc_compare_interfaces (ns->proc_name, variant_proc_sym,
@@ -8316,8 +8338,9 @@ gfc_trans_omp_declare_variant (gfc_namespace *ns)
 	  if (variant_proc_sym != NULL)
 	    {
 	      gfc_set_sym_referenced (variant_proc_sym);
-	      tree construct = omp_get_context_selector (set_selectors,
-							 "construct", NULL);
+	      tree construct
+		= omp_get_context_selector_list (set_selectors,
+						 OMP_TRAIT_SET_CONSTRUCT);
 	      omp_mark_declare_variant (gfc_get_location (&odv->where),
 					gfc_get_symbol_decl (variant_proc_sym),
 					construct);
diff --git a/gcc/gimplify.cc b/gcc/gimplify.cc
index 757654d5434..c29f1a93e66 100644
--- a/gcc/gimplify.cc
+++ b/gcc/gimplify.cc
@@ -13537,12 +13537,17 @@ omp_construct_selector_matches (enum tree_code *constructs, int nconstructs,
   if (tree attr = lookup_attribute ("omp declare variant variant",
 				    DECL_ATTRIBUTES (current_function_decl)))
     {
-      enum tree_code variant_constructs[5];
-      int variant_nconstructs = 0;
-      if (!target_seen)
-	variant_nconstructs
-	  = omp_construct_traits_to_codes (TREE_VALUE (attr),
-					   variant_constructs);
+      tree selectors = TREE_VALUE (attr);
+      int variant_nconstructs = list_length (selectors);
+      enum tree_code *variant_constructs = NULL;
+      if (!target_seen && variant_nconstructs)
+	{
+	  variant_constructs
+	    = (enum tree_code *) alloca (variant_nconstructs
+					 * sizeof (enum tree_code));
+	  omp_construct_traits_to_codes (selectors, variant_nconstructs,
+					 variant_constructs);
+	}
       for (int i = 0; i < variant_nconstructs; i++)
 	{
 	  ++cnt;
diff --git a/gcc/omp-general.cc b/gcc/omp-general.cc
index e4e3890449e..55a84d949bc 100644
--- a/gcc/omp-general.cc
+++ b/gcc/omp-general.cc
@@ -1013,32 +1013,29 @@ omp_max_simt_vf (void)
   return 0;
 }
 
-/* Store the construct selectors as tree codes from last to first,
-   return their number.  */
+/* Store the construct selectors as tree codes from last to first.
+   CTX is a list of trait selectors, nconstructs must be equal to its
+   length, and the array CONSTRUCTS holds the output.  */
 
-int
-omp_construct_traits_to_codes (tree ctx, enum tree_code *constructs)
+void
+omp_construct_traits_to_codes (tree ctx, int nconstructs,
+			       enum tree_code *constructs)
 {
-  int nconstructs = list_length (ctx);
   int i = nconstructs - 1;
+
+  /* Order must match the OMP_TRAIT_CONSTRUCT_* enumerators in
+     enum omp_ts_code.  */
+  static enum tree_code code_map[]
+    = { OMP_TARGET, OMP_TEAMS, OMP_PARALLEL, OMP_FOR, OMP_SIMD };
+
   for (tree ts = ctx; ts; ts = TREE_CHAIN (ts), i--)
     {
-      const char *sel = IDENTIFIER_POINTER (OMP_TS_ID (ts));
-      if (!strcmp (sel, "target"))
-	constructs[i] = OMP_TARGET;
-      else if (!strcmp (sel, "teams"))
-	constructs[i] = OMP_TEAMS;
-      else if (!strcmp (sel, "parallel"))
-	constructs[i] = OMP_PARALLEL;
-      else if (!strcmp (sel, "for") || !strcmp (sel, "do"))
-	constructs[i] = OMP_FOR;
-      else if (!strcmp (sel, "simd"))
-	constructs[i] = OMP_SIMD;
-      else
-	gcc_unreachable ();
+      enum omp_ts_code sel = OMP_TS_CODE (ts);
+      int j = (int)sel - (int)OMP_TRAIT_CONSTRUCT_TARGET;
+      gcc_assert (j >= 0 && (unsigned int) j < ARRAY_SIZE (code_map));
+      constructs[i] = code_map[j];
     }
   gcc_assert (i == -1);
-  return nconstructs;
 }
 
 /* Return true if PROP is possibly present in one of the offloading target's
@@ -1114,6 +1111,124 @@ omp_maybe_offloaded (void)
   return false;
 }
 
+/* Lookup tables for context selectors.  */
+const char *omp_tss_map[] =
+  {
+   "construct",
+   "device",
+   "target_device",
+   "implementation",
+   "user",
+   NULL
+};
+
+/* Arrays of property candidates must be null-terminated.  */
+static const char *const kind_properties[] =
+  { "host", "nohost", "cpu", "gpu", "fpga", "any", NULL };
+static const char *const vendor_properties[] =
+  { "amd", "arm", "bsc", "cray", "fujitsu", "gnu", "ibm", "intel",
+    "llvm", "nvidia", "pgi", "ti", "unknown", NULL };
+static const char *const extension_properties[] =
+  { NULL };
+static const char *const atomic_default_mem_order_properties[] =
+  { "seq_cst", "relaxed", "acq_rel", NULL };
+
+struct omp_ts_info omp_ts_map[] =
+  {
+   { "kind",
+     (1 << OMP_TRAIT_SET_DEVICE) | (1 << OMP_TRAIT_SET_TARGET_DEVICE),
+     OMP_TRAIT_PROPERTY_NAME_LIST, false,
+     kind_properties
+   },
+   { "isa",
+     (1 << OMP_TRAIT_SET_DEVICE) | (1 << OMP_TRAIT_SET_TARGET_DEVICE),
+     OMP_TRAIT_PROPERTY_NAME_LIST, false,
+     NULL
+   },
+   { "arch",
+     (1 << OMP_TRAIT_SET_DEVICE) | (1 << OMP_TRAIT_SET_TARGET_DEVICE),
+     OMP_TRAIT_PROPERTY_NAME_LIST, false,
+     NULL
+   },
+   { "device_num",
+     (1 << OMP_TRAIT_SET_TARGET_DEVICE),
+     OMP_TRAIT_PROPERTY_EXPR, false,
+     NULL
+   },
+   { "vendor",
+     (1 << OMP_TRAIT_SET_IMPLEMENTATION),
+     OMP_TRAIT_PROPERTY_NAME_LIST, true,
+     vendor_properties,
+   },
+   { "extension",
+     (1 << OMP_TRAIT_SET_IMPLEMENTATION),
+     OMP_TRAIT_PROPERTY_NAME_LIST, true,
+     extension_properties,
+   },
+   { "atomic_default_mem_order",
+     (1 << OMP_TRAIT_SET_IMPLEMENTATION),
+     OMP_TRAIT_PROPERTY_ID, true,
+     atomic_default_mem_order_properties,
+   },
+   { "requires",
+     (1 << OMP_TRAIT_SET_IMPLEMENTATION),
+     OMP_TRAIT_PROPERTY_CLAUSE_LIST, true,
+     NULL
+   },
+   { "unified_address",
+     (1 << OMP_TRAIT_SET_IMPLEMENTATION),
+     OMP_TRAIT_PROPERTY_NONE, true,
+     NULL
+   },
+   { "unified_shared_memory",
+     (1 << OMP_TRAIT_SET_IMPLEMENTATION),
+     OMP_TRAIT_PROPERTY_NONE, true,
+     NULL
+   },
+   { "dynamic_allocators",
+     (1 << OMP_TRAIT_SET_IMPLEMENTATION),
+     OMP_TRAIT_PROPERTY_NONE, true,
+     NULL
+   },
+   { "reverse_offload",
+     (1 << OMP_TRAIT_SET_IMPLEMENTATION),
+     OMP_TRAIT_PROPERTY_NONE, true,
+     NULL
+   },
+   { "condition",
+     (1 << OMP_TRAIT_SET_USER),
+     OMP_TRAIT_PROPERTY_EXPR, true,
+     NULL
+   },
+   { "target",
+     (1 << OMP_TRAIT_SET_CONSTRUCT),
+     OMP_TRAIT_PROPERTY_NONE, false,
+     NULL
+   },
+   { "teams",
+     (1 << OMP_TRAIT_SET_CONSTRUCT),
+     OMP_TRAIT_PROPERTY_NONE, false,
+     NULL
+   },
+   { "parallel",
+     (1 << OMP_TRAIT_SET_CONSTRUCT),
+     OMP_TRAIT_PROPERTY_NONE, false,
+     NULL
+   },
+   { "for",
+     (1 << OMP_TRAIT_SET_CONSTRUCT),
+     OMP_TRAIT_PROPERTY_NONE, false,
+     NULL
+   },
+   { "simd",
+     (1 << OMP_TRAIT_SET_CONSTRUCT),
+     OMP_TRAIT_PROPERTY_CLAUSE_LIST,  false,
+     NULL
+   },
+   { NULL, 0, OMP_TRAIT_PROPERTY_NONE, false, NULL }  /* OMP_TRAIT_LAST */
+  };
+
+
 /* Return a name from PROP, a property in selectors accepting
    name lists.  */
 
@@ -1145,121 +1260,101 @@ omp_context_name_list_prop (tree prop)
 tree
 omp_check_context_selector (location_t loc, tree ctx)
 {
-  /* Each trait-set-selector-name can only be specified once.
-     There are just 4 set names.  */
-  for (tree t1 = ctx; t1; t1 = TREE_CHAIN (t1))
-    for (tree t2 = TREE_CHAIN (t1); t2; t2 = TREE_CHAIN (t2))
-      if (OMP_TSS_ID (t1) == OMP_TSS_ID (t2))
-	{
-	  error_at (loc, "selector set %qs specified more than once",
-		    IDENTIFIER_POINTER (OMP_TSS_ID (t1)));
-	  return error_mark_node;
-	}
+  bool tss_seen[OMP_TRAIT_SET_LAST], ts_seen[OMP_TRAIT_LAST];
+
+  memset (tss_seen, 0, sizeof (tss_seen));
   for (tree tss = ctx; tss; tss = TREE_CHAIN (tss))
     {
-      /* Each trait-selector-name can only be specified once.  */
-      if (list_length (OMP_TSS_TRAIT_SELECTORS (tss)) < 5)
+      enum omp_tss_code tss_code = OMP_TSS_CODE (tss);
+
+      /* Each trait-set-selector-name can only be specified once.  */
+      if (tss_seen[tss_code])
 	{
-	  for (tree ts1 = OMP_TSS_TRAIT_SELECTORS (tss); ts1;
-	       ts1 = TREE_CHAIN (ts1))
-	    for (tree ts2 = TREE_CHAIN (ts1); ts2; ts2 = TREE_CHAIN (ts2))
-	      if (OMP_TS_ID (ts1) == OMP_TS_ID (ts2))
-		{
-		  error_at (loc,
-			    "selector %qs specified more than once in set %qs",
-			    IDENTIFIER_POINTER (OMP_TS_ID (ts1)),
-			    IDENTIFIER_POINTER (OMP_TSS_ID (tss)));
-		  return error_mark_node;
-		}
+	  error_at (loc, "selector set %qs specified more than once",
+		    OMP_TSS_NAME (tss));
+	  return error_mark_node;
 	}
       else
+	tss_seen[tss_code] = true;
+
+      memset (ts_seen, 0, sizeof (ts_seen));
+      for (tree ts = OMP_TSS_TRAIT_SELECTORS (tss); ts; ts = TREE_CHAIN (ts))
 	{
-	  hash_set<tree> pset;
-	  for (tree ts = OMP_TSS_TRAIT_SELECTORS (tss); ts;
-	       ts = TREE_CHAIN (ts))
-	    if (pset.add (OMP_TS_ID (ts)))
+	  enum omp_ts_code ts_code = OMP_TS_CODE (ts);
+
+	  /* Each trait-selector-name can only be specified once.  */
+	  if (ts_seen[ts_code])
+	    {
+	      error_at (loc,
+			"selector %qs specified more than once in set %qs",
+			OMP_TS_NAME (ts),
+			OMP_TSS_NAME (tss));
+	      return error_mark_node;
+	    }
+	  else
+	    ts_seen[ts_code] = true;
+
+	  if (omp_ts_map[ts_code].valid_properties == NULL)
+	    continue;
+
+	  for (tree p = OMP_TS_PROPERTIES (ts); p; p = TREE_CHAIN (p))
+	    for (unsigned j = 0; ; j++)
 	      {
-		error_at (loc,
-			  "selector %qs specified more than once in set %qs",
-			  IDENTIFIER_POINTER (OMP_TS_ID (ts)),
-			  IDENTIFIER_POINTER (OMP_TSS_ID (tss)));
-		return error_mark_node;
+		const char *candidate
+		  = omp_ts_map[ts_code].valid_properties[j];
+		if (candidate == NULL)
+		  {
+		    /* We've reached the end of the candidate array.  */
+		    if (ts_code == OMP_TRAIT_IMPLEMENTATION_ADMO)
+		      /* FIXME: not sure why this is an error vs warnings
+			 for the others, + incorrect/unknown wording?  */
+		      {
+			error_at (loc,
+				  "incorrect property %qs of %qs selector",
+				  IDENTIFIER_POINTER (OMP_TP_NAME (p)),
+				  "atomic_default_mem_order");
+			return error_mark_node;
+		      }
+		    if (OMP_TP_NAME (p) == OMP_TP_NAMELIST_NODE
+			&& (TREE_CODE (OMP_TP_VALUE (p)) == STRING_CST))
+		      warning_at (loc, 0,
+				  "unknown property %qE of %qs selector",
+				  OMP_TP_VALUE (p),
+				  OMP_TS_NAME (ts));
+		    else if (OMP_TP_NAME (p) == OMP_TP_NAMELIST_NODE)
+		      warning_at (loc, 0,
+				  "unknown property %qs of %qs selector",
+				  omp_context_name_list_prop (p),
+				  OMP_TS_NAME (ts));
+		    else if (OMP_TP_NAME (p))
+		      warning_at (loc, 0,
+				  "unknown property %qs of %qs selector",
+				  IDENTIFIER_POINTER (OMP_TP_NAME (p)),
+				  OMP_TS_NAME (ts));
+		    break;
+		  }
+		else if (OMP_TP_NAME (p) == OMP_TP_NAMELIST_NODE)
+		  /* Property-list traits.  */
+		  {
+		    const char *str = omp_context_name_list_prop (p);
+		    if (str && !strcmp (str, candidate))
+		      break;
+		  }
+		else if (!strcmp (IDENTIFIER_POINTER (OMP_TP_NAME (p)),
+				  candidate))
+		  /* Identifier traits.  */
+		  break;
 	      }
 	}
-
-      static const char *const kind[] = {
-	"host", "nohost", "cpu", "gpu", "fpga", "any", NULL };
-      static const char *const vendor[] = {
-	"amd", "arm", "bsc", "cray", "fujitsu", "gnu", "ibm", "intel",
-	"llvm", "nvidia", "pgi", "ti", "unknown", NULL };
-      static const char *const extension[] = { NULL };
-      static const char *const atomic_default_mem_order[] = {
-	"seq_cst", "relaxed", "acq_rel", NULL };
-      struct known_properties { const char *set; const char *selector;
-				const char *const *props; };
-      known_properties props[] = {
-	{ "device", "kind", kind },
-	{ "implementation", "vendor", vendor },
-	{ "implementation", "extension", extension },
-	{ "implementation", "atomic_default_mem_order",
-	  atomic_default_mem_order } };
-      for (tree ts = OMP_TSS_TRAIT_SELECTORS (tss); ts; ts = TREE_CHAIN (ts))
-	for (unsigned i = 0; i < ARRAY_SIZE (props); i++)
-	  if (!strcmp (IDENTIFIER_POINTER (OMP_TS_ID (ts)),
-					   props[i].selector)
-	      && !strcmp (IDENTIFIER_POINTER (OMP_TSS_ID (tss)),
-					      props[i].set))
-	    for (tree p = OMP_TS_PROPERTIES (ts); p; p = TREE_CHAIN (p))
-	      for (unsigned j = 0; ; j++)
-		{
-		  if (props[i].props[j] == NULL)
-		    {
-		      if (props[i].props == atomic_default_mem_order)
-			{
-			  error_at (loc,
-				    "incorrect property %qs of %qs selector",
-				    IDENTIFIER_POINTER (TREE_PURPOSE (p)),
-				    "atomic_default_mem_order");
-			  return error_mark_node;
-			}
-		      else if (OMP_TP_NAME (p) == OMP_TP_NAMELIST_NODE
-			       && (TREE_CODE (OMP_TP_VALUE (p)) == STRING_CST))
-			warning_at (loc, 0,
-				    "unknown property %qE of %qs selector",
-				    OMP_TP_VALUE (p),
-				    props[i].selector);
-		      else if (OMP_TP_NAME (p) == OMP_TP_NAMELIST_NODE)
-			warning_at (loc, 0,
-				    "unknown property %qs of %qs selector",
-				    omp_context_name_list_prop (p),
-				    props[i].selector);
-		      else if (OMP_TP_NAME (p))
-			warning_at (loc, 0,
-				    "unknown property %qs of %qs selector",
-				    IDENTIFIER_POINTER (OMP_TP_NAME (p)),
-				    props[i].selector);
-		      break;
-		    }
-		  else if (OMP_TP_NAME (p) == OMP_TP_NAMELIST_NODE)
-		    /* Property-list traits.  */
-		    {
-		      const char *str = omp_context_name_list_prop (p);
-		      if (str && !strcmp (str, props[i].props[j]))
-			break;
-		    }
-		  else if (!strcmp (IDENTIFIER_POINTER (OMP_TP_NAME (p)),
-				    props[i].props[j]))
-		    break;
-		}
     }
   return ctx;
 }
 
 
 /* Register VARIANT as variant of some base function marked with
-   #pragma omp declare variant.  CONSTRUCT is corresponding construct
-   selector set.  */
-
+   #pragma omp declare variant.  CONSTRUCT is corresponding list of
+   trait-selectors for the construct selector set.  This is stashed as the
+   value of the "omp declare variant variant" attribute on VARIANT.  */
 void
 omp_mark_declare_variant (location_t loc, tree variant, tree construct)
 {
@@ -1275,7 +1370,8 @@ omp_mark_declare_variant (location_t loc, tree variant, tree construct)
     }
   if ((TREE_VALUE (attr) != NULL_TREE) != (construct != NULL_TREE)
       || (construct != NULL_TREE
-	  && omp_context_selector_set_compare ("construct", TREE_VALUE (attr),
+	  && omp_context_selector_set_compare (OMP_TRAIT_SET_CONSTRUCT,
+					       TREE_VALUE (attr),
 					       construct)))
     error_at (loc, "%qD used as a variant with incompatible %<construct%> "
 		   "selector sets", variant);
@@ -1285,18 +1381,21 @@ omp_mark_declare_variant (location_t loc, tree variant, tree construct)
 /* Constructors for context selectors.  */
 
 tree
-make_trait_set_selector (tree name, tree selectors, tree chain)
+make_trait_set_selector (enum omp_tss_code code, tree selectors, tree chain)
 {
-  return tree_cons (name, selectors, chain);
+  return tree_cons (build_int_cst (integer_type_node, code),
+		    selectors, chain);
 }
 
 tree
-make_trait_selector (tree name, tree score, tree properties, tree chain)
+make_trait_selector (enum omp_ts_code code, tree score, tree properties,
+		     tree chain)
 {
   if (score == NULL_TREE)
-    return tree_cons (name, properties, chain);
+    return tree_cons (build_int_cst (integer_type_node, code),
+		      properties, chain);
   else
-    return tree_cons (name,
+    return tree_cons (build_int_cst (integer_type_node, code),
 		      tree_cons (OMP_TS_SCORE_NODE, score, properties),
 		      chain);
 }
@@ -1319,8 +1418,8 @@ omp_context_selector_matches (tree ctx)
   int ret = 1;
   for (tree tss = ctx; tss; tss = TREE_CHAIN (tss))
     {
-      char set = IDENTIFIER_POINTER (OMP_TSS_ID (tss))[0];
-      if (set == 'c')
+      enum omp_tss_code set = OMP_TSS_CODE (tss);
+      if (set == OMP_TRAIT_SET_CONSTRUCT)
 	{
 	  /* For now, ignore the construct set.  While something can be
 	     determined already during parsing, we don't know until end of TU
@@ -1335,10 +1434,21 @@ omp_context_selector_matches (tree ctx)
 	      continue;
 	    }
 
-	  enum tree_code constructs[5];
-	  int nconstructs
-	    = omp_construct_traits_to_codes (OMP_TSS_TRAIT_SELECTORS (tss),
+	  tree selectors = OMP_TSS_TRAIT_SELECTORS (tss);
+	  int nconstructs = list_length (selectors);
+	  enum tree_code *constructs = NULL;
+	  if (nconstructs)
+	    {
+	      /* Even though this alloca appears in a loop over selector
+		 sets, it does not repeatedly grow the stack, because
+		 there can be only one construct selector set specified.
+		 This is enforced by omp_check_context_selector.  */
+	      constructs
+		= (enum tree_code *) alloca (nconstructs
+					     * sizeof (enum tree_code));
+	      omp_construct_traits_to_codes (selectors, nconstructs,
 					     constructs);
+	    }
 
 	  if (cfun && (cfun->curr_properties & PROP_gimple_any) != 0)
 	    {
@@ -1371,11 +1481,11 @@ omp_context_selector_matches (tree ctx)
 	}
       for (tree ts = OMP_TSS_TRAIT_SELECTORS (tss); ts; ts = TREE_CHAIN (ts))
 	{
-	  const char *sel = IDENTIFIER_POINTER (OMP_TS_ID (ts));
-	  switch (*sel)
+	  enum omp_ts_code sel = OMP_TS_CODE (ts);
+	  switch (sel)
 	    {
-	    case 'v':
-	      if (set == 'i' && !strcmp (sel, "vendor"))
+	    case OMP_TRAIT_IMPLEMENTATION_VENDOR:
+	      if (set == OMP_TRAIT_SET_IMPLEMENTATION)
 		for (tree p = OMP_TS_PROPERTIES (ts); p; p = TREE_CHAIN (p))
 		  {
 		    const char *prop = omp_context_name_list_prop (p);
@@ -1386,13 +1496,13 @@ omp_context_selector_matches (tree ctx)
 		    return 0;
 		  }
 	      break;
-	    case 'e':
-	      if (set == 'i' && !strcmp (sel, "extension"))
+	    case OMP_TRAIT_IMPLEMENTATION_EXTENSION:
+	      if (set == OMP_TRAIT_SET_IMPLEMENTATION)
 		/* We don't support any extensions right now.  */
 		return 0;
 	      break;
-	    case 'a':
-	      if (set == 'i' && !strcmp (sel, "atomic_default_mem_order"))
+	    case OMP_TRAIT_IMPLEMENTATION_ADMO:
+	      if (set == OMP_TRAIT_SET_IMPLEMENTATION)
 		{
 		  if (cfun && (cfun->curr_properties & PROP_gimple_any) != 0)
 		    break;
@@ -1424,7 +1534,9 @@ omp_context_selector_matches (tree ctx)
 			   && omo != OMP_MEMORY_ORDER_ACQ_REL)
 		    return 0;
 		}
-	      if (set == 'd' && !strcmp (sel, "arch"))
+	      break;
+	    case OMP_TRAIT_DEVICE_ARCH:
+	      if (set == OMP_TRAIT_SET_DEVICE)
 		for (tree p = OMP_TS_PROPERTIES (ts); p; p = TREE_CHAIN (p))
 		  {
 		    const char *arch = omp_context_name_list_prop (p);
@@ -1461,8 +1573,8 @@ omp_context_selector_matches (tree ctx)
 		      ret = -1;
 		  }
 	      break;
-	    case 'u':
-	      if (set == 'i' && !strcmp (sel, "unified_address"))
+	    case OMP_TRAIT_IMPLEMENTATION_UNIFIED_ADDRESS:
+	      if (set == OMP_TRAIT_SET_IMPLEMENTATION)
 		{
 		  if (cfun && (cfun->curr_properties & PROP_gimple_any) != 0)
 		    break;
@@ -1474,9 +1586,10 @@ omp_context_selector_matches (tree ctx)
 		      else
 			return 0;
 		    }
-		  break;
 		}
-	      if (set == 'i' && !strcmp (sel, "unified_shared_memory"))
+	      break;
+	    case OMP_TRAIT_IMPLEMENTATION_UNIFIED_SHARED_MEMORY:
+	      if (set == OMP_TRAIT_SET_IMPLEMENTATION)
 		{
 		  if (cfun && (cfun->curr_properties & PROP_gimple_any) != 0)
 		    break;
@@ -1489,11 +1602,10 @@ omp_context_selector_matches (tree ctx)
 		      else
 			return 0;
 		    }
-		  break;
 		}
 	      break;
-	    case 'd':
-	      if (set == 'i' && !strcmp (sel, "dynamic_allocators"))
+	    case OMP_TRAIT_IMPLEMENTATION_DYNAMIC_ALLOCATORS:
+	      if (set == OMP_TRAIT_SET_IMPLEMENTATION)
 		{
 		  if (cfun && (cfun->curr_properties & PROP_gimple_any) != 0)
 		    break;
@@ -1506,11 +1618,10 @@ omp_context_selector_matches (tree ctx)
 		      else
 			return 0;
 		    }
-		  break;
 		}
 	      break;
-	    case 'r':
-	      if (set == 'i' && !strcmp (sel, "reverse_offload"))
+	    case OMP_TRAIT_IMPLEMENTATION_REVERSE_OFFLOAD:
+	      if (set == OMP_TRAIT_SET_IMPLEMENTATION)
 		{
 		  if (cfun && (cfun->curr_properties & PROP_gimple_any) != 0)
 		    break;
@@ -1522,11 +1633,10 @@ omp_context_selector_matches (tree ctx)
 		      else
 			return 0;
 		    }
-		  break;
 		}
 	      break;
-	    case 'k':
-	      if (set == 'd' && !strcmp (sel, "kind"))
+	    case OMP_TRAIT_DEVICE_KIND:
+	      if (set == OMP_TRAIT_SET_DEVICE)
 		for (tree p = OMP_TS_PROPERTIES (ts); p; p = TREE_CHAIN (p))
 		  {
 		    const char *prop = omp_context_name_list_prop (p);
@@ -1586,8 +1696,8 @@ omp_context_selector_matches (tree ctx)
 		      ret = -1;
 		  }
 	      break;
-	    case 'i':
-	      if (set == 'd' && !strcmp (sel, "isa"))
+	    case OMP_TRAIT_DEVICE_ISA:
+	      if (set == OMP_TRAIT_SET_DEVICE)
 		for (tree p = OMP_TS_PROPERTIES (ts); p; p = TREE_CHAIN (p))
 		  {
 		    const char *isa = omp_context_name_list_prop (p);
@@ -1639,8 +1749,8 @@ omp_context_selector_matches (tree ctx)
 		      ret = -1;
 		  }
 	      break;
-	    case 'c':
-	      if (set == 'u' && !strcmp (sel, "condition"))
+	    case OMP_TRAIT_USER_CONDITION:
+	      if (set == OMP_TRAIT_SET_USER)
 		for (tree p = OMP_TS_PROPERTIES (ts); p; p = TREE_CHAIN (p))
 		  if (OMP_TP_NAME (p) == NULL_TREE)
 		    {
@@ -1782,7 +1892,8 @@ omp_construct_simd_compare (tree clauses1, tree clauses2)
    Unlike set names or selector names, properties can have duplicates.  */
 
 static int
-omp_context_selector_props_compare (const char *set, const char *sel,
+omp_context_selector_props_compare (enum omp_tss_code set,
+				    enum omp_ts_code sel,
 				    tree ctx1, tree ctx2)
 {
   int ret = 0;
@@ -1795,7 +1906,8 @@ omp_context_selector_props_compare (const char *set, const char *sel,
 	    {
 	      if (OMP_TP_NAME (p1) == NULL_TREE)
 		{
-		  if (set[0] == 'u' && strcmp (sel, "condition") == 0)
+		  if (set == OMP_TRAIT_SET_USER
+		      && sel == OMP_TRAIT_USER_CONDITION)
 		    {
 		      if (integer_zerop (OMP_TP_VALUE (p1))
 			  != integer_zerop (OMP_TP_VALUE (p2)))
@@ -1842,7 +1954,7 @@ omp_context_selector_props_compare (const char *set, const char *sel,
    2 if neither context is a subset of another one.  */
 
 int
-omp_context_selector_set_compare (const char *set, tree ctx1, tree ctx2)
+omp_context_selector_set_compare (enum omp_tss_code set, tree ctx1, tree ctx2)
 {
   bool swapped = false;
   int ret = 0;
@@ -1855,18 +1967,17 @@ omp_context_selector_set_compare (const char *set, tree ctx1, tree ctx2)
       std::swap (ctx1, ctx2);
       std::swap (len1, len2);
     }
-  if (set[0] == 'c')
+  if (set == OMP_TRAIT_SET_CONSTRUCT)
     {
       tree ts1;
       tree ts2 = ctx2;
-      tree simd = get_identifier ("simd");
       /* Handle construct set specially.  In this case the order
 	 of the selector matters too.  */
       for (ts1 = ctx1; ts1; ts1 = TREE_CHAIN (ts1))
-	if (OMP_TS_ID (ts1) == OMP_TS_ID (ts2))
+	if (OMP_TS_CODE (ts1) == OMP_TS_CODE (ts2))
 	  {
 	    int r = 0;
-	    if (OMP_TS_ID (ts1) == simd)
+	    if (OMP_TS_CODE (ts1) == OMP_TRAIT_CONSTRUCT_SIMD)
 	      r = omp_construct_simd_compare (OMP_TS_PROPERTIES (ts1),
 					      OMP_TS_PROPERTIES (ts2));
 	    if (r == 2 || (ret && r && (ret < 0) != (r < 0)))
@@ -1898,17 +2009,17 @@ omp_context_selector_set_compare (const char *set, tree ctx1, tree ctx2)
     }
   for (tree ts1 = ctx1; ts1; ts1 = TREE_CHAIN (ts1))
     {
+      enum omp_ts_code sel = OMP_TS_CODE (ts1);
       tree ts2;
       for (ts2 = ctx2; ts2; ts2 = TREE_CHAIN (ts2))
-	if (OMP_TS_ID (ts1) == OMP_TS_ID (ts2))
+	if (sel == OMP_TS_CODE (ts2))
 	  {
 	    tree score1 = OMP_TS_SCORE (ts1);
 	    tree score2 = OMP_TS_SCORE (ts2);
 	    if (score1 && score2 && !simple_cst_equal (score1, score2))
 	      return 2;
 
-	    const char *sel = IDENTIFIER_POINTER (OMP_TS_ID (ts1));
-	    int r = omp_context_selector_props_compare (set, sel,
+	    int r = omp_context_selector_props_compare (set, OMP_TS_CODE (ts1),
 							OMP_TS_PROPERTIES (ts1),
 							OMP_TS_PROPERTIES (ts2));
 	    if (r == 2 || (ret && r && (ret < 0) != (r < 0)))
@@ -1954,11 +2065,11 @@ omp_context_selector_compare (tree ctx1, tree ctx2)
     }
   for (tree tss1 = ctx1; tss1; tss1 = TREE_CHAIN (tss1))
     {
+      enum omp_tss_code set = OMP_TSS_CODE (tss1);
       tree tss2;
       for (tss2 = ctx2; tss2; tss2 = TREE_CHAIN (tss2))
-	if (OMP_TSS_ID (tss1) == OMP_TSS_ID (tss2))
+	if (set == OMP_TSS_CODE (tss2))
 	  {
-	    const char *set = IDENTIFIER_POINTER (OMP_TSS_ID (tss1));
 	    int r
 	      = omp_context_selector_set_compare
 		  (set, OMP_TSS_TRAIT_SELECTORS (tss1),
@@ -1985,26 +2096,51 @@ omp_context_selector_compare (tree ctx1, tree ctx2)
 }
 
 /* From context selector CTX, return trait-selector with name SEL in
-   trait-selector-set with name SET if any, or NULL_TREE if not found.
-   If SEL is NULL, return the list of trait-selectors in SET.  */
+   trait-selector-set with name SET if any, or NULL_TREE if not found.  */
+tree
+omp_get_context_selector (tree ctx, enum omp_tss_code set,
+			  enum omp_ts_code sel)
+{
+  for (tree tss = ctx; tss; tss = TREE_CHAIN (tss))
+    if (OMP_TSS_CODE (tss) == set)
+      for (tree ts = OMP_TSS_TRAIT_SELECTORS (tss); ts; ts = TREE_CHAIN (ts))
+	if (OMP_TS_CODE (ts) == sel)
+	  return ts;
+  return NULL_TREE;
+}
 
+/* Similar, but returns the whole trait-selector list for SET in CTX.  */
 tree
-omp_get_context_selector (tree ctx, const char *set, const char *sel)
+omp_get_context_selector_list (tree ctx, enum omp_tss_code set)
 {
-  tree setid = get_identifier (set);
-  tree selid = sel ? get_identifier (sel) : NULL_TREE;
   for (tree tss = ctx; tss; tss = TREE_CHAIN (tss))
-    if (OMP_TSS_ID (tss) == setid)
-      {
-	if (sel == NULL)
-	  return OMP_TSS_TRAIT_SELECTORS (tss);
-	for (tree ts = OMP_TSS_TRAIT_SELECTORS (tss); ts; ts = TREE_CHAIN (ts))
-	  if (OMP_TS_ID (ts) == selid)
-	    return ts;
-      }
+    if (OMP_TSS_CODE (tss) == set)
+      return OMP_TSS_TRAIT_SELECTORS (tss);
   return NULL_TREE;
 }
 
+/* Map string S onto a trait selector set code.  */
+enum omp_tss_code
+omp_lookup_tss_code (const char * s)
+{
+  for (int i = 0; i < OMP_TRAIT_SET_LAST; i++)
+    if (strcmp (s, omp_tss_map[i]) == 0)
+      return (enum omp_tss_code) i;
+  return OMP_TRAIT_SET_INVALID;
+}
+
+/* Map string S onto a trait selector code for set SET.  */
+enum omp_ts_code
+omp_lookup_ts_code (enum omp_tss_code set, const char *s)
+{
+  unsigned int mask = 1 << set;
+  for (int i = 0; i < OMP_TRAIT_LAST; i++)
+    if ((mask & omp_ts_map[i].tss_mask) != 0
+	&& strcmp (s, omp_ts_map[i].name) == 0)
+      return (enum omp_ts_code) i;
+  return OMP_TRAIT_INVALID;
+}
+
 /* Needs to be a GC-friendly widest_int variant, but precision is
    desirable to be the same on all targets.  */
 typedef generic_wide_int <fixed_wide_int_storage <1024> > score_wide_int;
@@ -2017,14 +2153,18 @@ typedef generic_wide_int <fixed_wide_int_storage <1024> > score_wide_int;
 static bool
 omp_context_compute_score (tree ctx, score_wide_int *score, bool declare_simd)
 {
-  tree construct = omp_get_context_selector (ctx, "construct", NULL);
-  bool has_kind = omp_get_context_selector (ctx, "device", "kind");
-  bool has_arch = omp_get_context_selector (ctx, "device", "arch");
-  bool has_isa = omp_get_context_selector (ctx, "device", "isa");
+  tree selectors
+    = omp_get_context_selector_list (ctx, OMP_TRAIT_SET_CONSTRUCT);
+  bool has_kind = omp_get_context_selector (ctx, OMP_TRAIT_SET_DEVICE,
+					    OMP_TRAIT_DEVICE_KIND);
+  bool has_arch = omp_get_context_selector (ctx, OMP_TRAIT_SET_DEVICE,
+					    OMP_TRAIT_DEVICE_ARCH);
+  bool has_isa = omp_get_context_selector (ctx, OMP_TRAIT_SET_DEVICE,
+					   OMP_TRAIT_DEVICE_ISA);
   bool ret = false;
   *score = 1;
   for (tree tss = ctx; tss; tss = TREE_CHAIN (tss))
-    if (OMP_TSS_TRAIT_SELECTORS (tss) != construct)
+    if (OMP_TSS_TRAIT_SELECTORS (tss) != selectors)
       for (tree ts = OMP_TSS_TRAIT_SELECTORS (tss); ts; ts = TREE_CHAIN (ts))
 	{
 	  tree s = OMP_TS_SCORE (ts);
@@ -2033,13 +2173,19 @@ omp_context_compute_score (tree ctx, score_wide_int *score, bool declare_simd)
 					    TYPE_SIGN (TREE_TYPE (s)));
 	}
 
-  if (construct || has_kind || has_arch || has_isa)
+  if (selectors || has_kind || has_arch || has_isa)
     {
-      int scores[12];
-      enum tree_code constructs[5];
-      int nconstructs = 0;
-      if (construct)
-	nconstructs = omp_construct_traits_to_codes (construct, constructs);
+      int nconstructs = list_length (selectors);
+      enum tree_code *constructs = NULL;
+      if (nconstructs)
+	{
+	  constructs
+	    = (enum tree_code *) alloca (nconstructs
+					 * sizeof (enum tree_code));
+	  omp_construct_traits_to_codes (selectors, nconstructs, constructs);
+	}
+      int *scores
+	= (int *) alloca ((2 * nconstructs + 2) * sizeof (int));
       if (omp_construct_selector_matches (constructs, nconstructs, scores)
 	  == 2)
 	ret = true;
diff --git a/gcc/omp-general.h b/gcc/omp-general.h
index dc5e5f6ba1f..39d80574be7 100644
--- a/gcc/omp-general.h
+++ b/gcc/omp-general.h
@@ -135,8 +135,83 @@ struct omp_for_data
 #define OMP_TP_VALUE(NODE) \
   TREE_VALUE (NODE)
 
-extern tree make_trait_set_selector (tree, tree, tree);
-extern tree make_trait_selector (tree, tree, tree, tree);
+/* Data structures for context selectors.  */
+
+/* Trait set selector keywords.  */
+enum omp_tss_code {
+  OMP_TRAIT_SET_CONSTRUCT,
+  OMP_TRAIT_SET_DEVICE,
+  OMP_TRAIT_SET_TARGET_DEVICE,
+  OMP_TRAIT_SET_IMPLEMENTATION,
+  OMP_TRAIT_SET_USER,
+  OMP_TRAIT_SET_LAST,
+  OMP_TRAIT_SET_INVALID = -1
+};
+
+/* Trait selector keywords.  */
+enum omp_ts_code {
+  OMP_TRAIT_DEVICE_KIND,
+  OMP_TRAIT_DEVICE_ISA,
+  OMP_TRAIT_DEVICE_ARCH,
+  OMP_TRAIT_DEVICE_NUM,
+  OMP_TRAIT_IMPLEMENTATION_VENDOR,
+  OMP_TRAIT_IMPLEMENTATION_EXTENSION,
+  OMP_TRAIT_IMPLEMENTATION_ADMO,
+  OMP_TRAIT_IMPLEMENTATION_REQUIRES,
+  OMP_TRAIT_IMPLEMENTATION_UNIFIED_ADDRESS,
+  OMP_TRAIT_IMPLEMENTATION_UNIFIED_SHARED_MEMORY,
+  OMP_TRAIT_IMPLEMENTATION_DYNAMIC_ALLOCATORS,
+  OMP_TRAIT_IMPLEMENTATION_REVERSE_OFFLOAD,
+  OMP_TRAIT_USER_CONDITION,
+  OMP_TRAIT_CONSTRUCT_TARGET,
+  OMP_TRAIT_CONSTRUCT_TEAMS,
+  OMP_TRAIT_CONSTRUCT_PARALLEL,
+  OMP_TRAIT_CONSTRUCT_FOR,
+  OMP_TRAIT_CONSTRUCT_SIMD,
+  OMP_TRAIT_LAST,
+  OMP_TRAIT_INVALID = -1
+};
+
+/* All trait property forms.  */
+enum omp_tp_type {
+  OMP_TRAIT_PROPERTY_NONE,
+  OMP_TRAIT_PROPERTY_ID,
+  OMP_TRAIT_PROPERTY_NAME_LIST,
+  OMP_TRAIT_PROPERTY_EXPR,
+  OMP_TRAIT_PROPERTY_CLAUSE_LIST,
+  OMP_TRAIT_PROPERTY_EXTENSION
+};
+
+/* Map trait set selector name keywords onto strings.  */
+extern const char *omp_tss_map [];
+
+/* Map trait selector keywords onto strings, allowed contexts, and
+   allowed property names for OMP_TRAIT_PROPERTY_NAME_LIST and
+   OMP_TRAIT_PROPERTY_ID properties.  If valid_properties is null,
+   it means that any required checking has to be done explicitly
+   somewhere instead of being driven by the table.  Otherwise it's a
+   null-terminated array of strings.  */
+struct omp_ts_info {
+  const char *name;
+  unsigned int tss_mask;
+  enum omp_tp_type tp_type;
+  bool allow_score;
+  const char * const *valid_properties;
+};
+extern struct omp_ts_info omp_ts_map[];
+
+#define OMP_TSS_CODE(t)						\
+  ((enum omp_tss_code) TREE_INT_CST_LOW (OMP_TSS_ID (t)))
+#define OMP_TSS_NAME(t)			\
+  (omp_tss_map[OMP_TSS_CODE (t)])
+
+#define OMP_TS_CODE(t)						\
+  ((enum omp_ts_code) TREE_INT_CST_LOW (OMP_TS_ID (t)))
+#define OMP_TS_NAME(t)			\
+  (omp_ts_map[OMP_TS_CODE (t)].name)
+
+extern tree make_trait_set_selector (enum omp_tss_code, tree, tree);
+extern tree make_trait_selector (enum omp_ts_code, tree, tree, tree);
 extern tree make_trait_property (tree, tree, tree);
 
 extern tree omp_find_clause (tree clauses, enum omp_clause_code kind);
@@ -153,13 +228,17 @@ extern gimple *omp_build_barrier (tree lhs);
 extern tree find_combined_omp_for (tree *, int *, void *);
 extern poly_uint64 omp_max_vf (void);
 extern int omp_max_simt_vf (void);
-extern int omp_construct_traits_to_codes (tree, enum tree_code *);
+extern void omp_construct_traits_to_codes (tree, int, enum tree_code *);
 extern tree omp_check_context_selector (location_t loc, tree ctx);
 extern void omp_mark_declare_variant (location_t loc, tree variant,
 				      tree construct);
 extern int omp_context_selector_matches (tree);
-extern int omp_context_selector_set_compare (const char *, tree, tree);
-extern tree omp_get_context_selector (tree, const char *, const char *);
+extern int omp_context_selector_set_compare (enum omp_tss_code, tree, tree);
+extern tree omp_get_context_selector (tree, enum omp_tss_code,
+				      enum omp_ts_code);
+extern tree omp_get_context_selector_list (tree, enum omp_tss_code);
+extern enum omp_tss_code omp_lookup_tss_code (const char *);
+extern enum omp_ts_code omp_lookup_ts_code (enum omp_tss_code, const char *);
 extern tree omp_resolve_declare_variant (tree);
 extern tree oacc_launch_pack (unsigned code, tree device, unsigned op);
 extern tree oacc_replace_fn_attrib_attr (tree attribs, tree dims);
-- 
2.31.1


^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: [PATCH V2 3/3] OpenMP: Use enumerators for names of trait-sets and traits
  2023-11-22 16:22 ` [PATCH V2 3/3] OpenMP: Use enumerators for names of trait-sets and traits Sandra Loosemore
@ 2023-11-27 17:19   ` Tobias Burnus
  2023-11-27 18:18     ` Tobias Burnus
  0 siblings, 1 reply; 9+ messages in thread
From: Tobias Burnus @ 2023-11-27 17:19 UTC (permalink / raw)
  To: Sandra Loosemore, gcc-patches; +Cc: jakub, julian

Hi Sandra,

{BTW: 1/3 needs to be eventually rebased as it no longer applies
cleanly; I have not checked 2/3 or 3/3 yet.]

1/3+2/3 look good to me, unless Jakub has some comments, I think they
can go it.

Regarding 3/3, some first comments. I still want to read it a bit more
careful and play with it.

On 22.11.23 17:22, Sandra Loosemore wrote:
> +static const char *const vendor_properties[] =
> +  { "amd", "arm", "bsc", "cray", "fujitsu", "gnu", "ibm", "intel",
> +    "llvm", "nvidia", "pgi", "ti", "unknown", NULL };

Can you add "hpe"? Cf. "OpenMP API 5.2 Supplementary Source Code" at
https://www.openmp.org/specifications/

> +static const char *const atomic_default_mem_order_properties[] =
> +  { "seq_cst", "relaxed", "acq_rel", NULL };

Can you add "acquire" and "release"? Those have been added in OpenMP 5.1
for 'omp atomic', supported since GCC 12; albeit, for requires, that's
new since 5.2.

> +   { "atomic_default_mem_order",
> +     (1 << OMP_TRAIT_SET_IMPLEMENTATION),
> +     OMP_TRAIT_PROPERTY_ID, true,
> +     atomic_default_mem_order_properties,
> +   },
> +   { "requires",
> +     (1 << OMP_TRAIT_SET_IMPLEMENTATION),
> +     OMP_TRAIT_PROPERTY_CLAUSE_LIST, true,
> +     NULL
> +   },
> +   { "unified_address",
> +     (1 << OMP_TRAIT_SET_IMPLEMENTATION),
> +     OMP_TRAIT_PROPERTY_NONE, true,
> +     NULL
> +   },

I don't understand this code. This looks as if "requires" and "unified_address"
are on the same level but in my understanding they have to be used as in:

  match(implementation = {requires(unified_address, atomic_default_mem_order_properties(release)})

while from the syntax, it looks as if this would permit:

  match(implementation = {unified_address, atomic_default_mem_order_properties(release))

Disclaimer: It might be that the code handles it correctly but I just misread it.
Or that I misread the spec.

  * * *

> +                   warning_at (loc, 0,
> +                               "unknown property %qE of %qs selector",

All '0' OpenMP warnings should now use 'OPT_Wopenmp' instead.

  * * *

> -       if (selectors[i] == NULL)
> +       /* Some trait sets permit extension traits which are supposed
> +          to be ignored if the implementation doesn't support them.
> +          GCC does not support any extension traits, and if it did, they
> +          would have their own identifiers.  */

I am not sure whether I get this correctly. In my understanding

   match(implementation = {extension(ompx_myCompiler_abcd)])

should parse without error - but evaluate as false / not matching. Thus, it is not really
ignored but parsed – but still causing a not-matched.

(We can argue whether that should be silently accepted or still show a warning.)


Likewise for:
   match (implementation = { ompx_myCompiler_abcd(1) } )

albeit here a warning could make more sense than for 'extension', especially if a
typo fix would be available.

 From the comment, it looks like as it is completely ignored - such that there could be still a match.

Disclaimer: I might have misunderstood the code - or might have missed something in the spec.

Tobias

-----------------
Siemens Electronic Design Automation GmbH; Anschrift: Arnulfstraße 201, 80634 München; Gesellschaft mit beschränkter Haftung; Geschäftsführer: Thomas Heurung, Frank Thürauf; Sitz der Gesellschaft: München; Registergericht München, HRB 106955

^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: [PATCH V2 3/3] OpenMP: Use enumerators for names of trait-sets and traits
  2023-11-27 17:19   ` Tobias Burnus
@ 2023-11-27 18:18     ` Tobias Burnus
  0 siblings, 0 replies; 9+ messages in thread
From: Tobias Burnus @ 2023-11-27 18:18 UTC (permalink / raw)
  To: Sandra Loosemore, gcc-patches; +Cc: jakub, julian

On 27.11.23 18:19, Tobias Burnus wrote:
>> +   { "unified_address",
>> +     (1 << OMP_TRAIT_SET_IMPLEMENTATION),
>> +     OMP_TRAIT_PROPERTY_NONE, true,
>> +     NULL
>> +   },
>
> I don't understand this code. This looks as if "requires" and
> "unified_address"
> are on the same level but in my understanding they have to be used as in:
>
>  match(implementation = {requires(unified_address,
> atomic_default_mem_order_properties(release)})
>
> while from the syntax, it looks as if this would permit:
>
>  match(implementation = {unified_address,
> atomic_default_mem_order_properties(release))


Sandra pointed me to the spec: OpenMP 5.0 only permits the latter, i.e.
using the clause names of 'requires' directly. Since OpenMP 5.1, this
use is deprecated (removed in TR11/TR12) - in favor of the first syntax,
i.e. using them as argument to 'requires()'.

Thus, the code is fine. — And shows all the joy needing to read multiple
spec versions at the same time without getting confused.

Tobias

-----------------
Siemens Electronic Design Automation GmbH; Anschrift: Arnulfstraße 201, 80634 München; Gesellschaft mit beschränkter Haftung; Geschäftsführer: Thomas Heurung, Frank Thürauf; Sitz der Gesellschaft: München; Registergericht München, HRB 106955

^ permalink raw reply	[flat|nested] 9+ messages in thread

end of thread, other threads:[~2023-11-27 18:18 UTC | newest]

Thread overview: 9+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2023-11-19  9:21 [PATCH 0/3] OpenMP: Improve data abstractions for context selectors Sandra Loosemore
2023-11-19  9:21 ` [PATCH 1/3] OpenMP: Introduce accessor macros and constructors " Sandra Loosemore
2023-11-19  9:21 ` [PATCH 2/3] OpenMP: Unify representation of name-list properties Sandra Loosemore
2023-11-19  9:21 ` [PATCH 3/3] OpenMP: Use enumerators for names of trait-sets and traits Sandra Loosemore
2023-11-21 20:48   ` Sandra Loosemore
2023-11-20 10:32 ` [PATCH 0/3] OpenMP: Improve data abstractions for context selectors Julian Brown
2023-11-22 16:22 ` [PATCH V2 3/3] OpenMP: Use enumerators for names of trait-sets and traits Sandra Loosemore
2023-11-27 17:19   ` Tobias Burnus
2023-11-27 18:18     ` Tobias Burnus

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).