This is the mail archive of the gcc-patches@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

RFC (branch prediction): PATCH to implement P0479R5, [[likely]] and [[unlikely]].


[[likely]] and [[unlikely]] are equivalent to the GNU hot/cold attributes,
except that they can be applied to arbitrary statements as well as labels;
this is most likely to be useful for marking if/else branches as likely or
unlikely.  Conveniently, PREDICT_EXPR fits the bill nicely as a
representation.

I also had to fix marking case labels as hot/cold, which didn't work before.
Which then required me to force __attribute ((fallthrough)) to apply to the
statement rather than the label.

Tested x86_64-pc-linux-gnu.  Does this seem like a sane implementation
approach to people with more experience with PREDICT_EXPR?

gcc/
	* gimplify.c (gimplify_case_label_expr): Handle hot/cold attributes.
gcc/c-family/
	* c-lex.c (c_common_has_attribute): Handle likely/unlikely.
gcc/cp/
	* parser.c (cp_parser_std_attribute): Handle likely/unlikely.
	(cp_parser_statement): Call process_stmt_hotness_attribute.
	(cp_parser_label_for_labeled_statement): Apply attributes to case.
	* cp-gimplify.c (lookup_hotness_attribute, remove_hotness_attribute)
	(process_stmt_hotness_attribute): New.
	* decl.c (finish_case_label): Give label in template type void.
	* pt.c (tsubst_expr) [CASE_LABEL_EXPR]: Copy attributes.
	[PREDICT_EXPR]: Handle.
---
 gcc/cp/cp-tree.h                          |  2 +
 gcc/c-family/c-lex.c                      |  4 +-
 gcc/cp/cp-gimplify.c                      | 42 +++++++++++++++++++++
 gcc/cp/decl.c                             |  2 +-
 gcc/cp/parser.c                           | 45 +++++++++++++++++++----
 gcc/cp/pt.c                               | 12 +++++-
 gcc/gimplify.c                            | 10 ++++-
 gcc/testsuite/g++.dg/cpp2a/attr-likely1.C | 38 +++++++++++++++++++
 gcc/testsuite/g++.dg/cpp2a/attr-likely2.C | 10 +++++
 gcc/testsuite/g++.dg/cpp2a/feat-cxx2a.C   | 12 ++++++
 gcc/ChangeLog                             |  4 ++
 gcc/c-family/ChangeLog                    |  4 ++
 gcc/cp/ChangeLog                          | 12 ++++++
 13 files changed, 184 insertions(+), 13 deletions(-)
 create mode 100644 gcc/testsuite/g++.dg/cpp2a/attr-likely1.C
 create mode 100644 gcc/testsuite/g++.dg/cpp2a/attr-likely2.C

diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h
index c4d79c0cf7f..c55352ec5ff 100644
--- a/gcc/cp/cp-tree.h
+++ b/gcc/cp/cp-tree.h
@@ -7541,6 +7541,8 @@ extern bool cxx_omp_disregard_value_expr	(tree, bool);
 extern void cp_fold_function			(tree);
 extern tree cp_fully_fold			(tree);
 extern void clear_fold_cache			(void);
+extern tree lookup_hotness_attribute		(tree);
+extern tree process_stmt_hotness_attribute	(tree);
 
 /* in name-lookup.c */
 extern tree strip_using_decl                    (tree);
diff --git a/gcc/c-family/c-lex.c b/gcc/c-family/c-lex.c
index 28a820a2a3d..3cc015083e0 100644
--- a/gcc/c-family/c-lex.c
+++ b/gcc/c-family/c-lex.c
@@ -356,7 +356,9 @@ c_common_has_attribute (cpp_reader *pfile)
 		       || is_attribute_p ("nodiscard", attr_name)
 		       || is_attribute_p ("fallthrough", attr_name))
 		result = 201603;
-	      else if (is_attribute_p ("no_unique_address", attr_name))
+	      else if (is_attribute_p ("no_unique_address", attr_name)
+		       || is_attribute_p ("likely", attr_name)
+		       || is_attribute_p ("unlikely", attr_name))
 		result = 201803;
 	      if (result)
 		attr_name = NULL_TREE;
diff --git a/gcc/cp/cp-gimplify.c b/gcc/cp/cp-gimplify.c
index eb761b118a1..f8212187162 100644
--- a/gcc/cp/cp-gimplify.c
+++ b/gcc/cp/cp-gimplify.c
@@ -2674,4 +2674,46 @@ cp_fold (tree x)
   return x;
 }
 
+/* Look up either "hot" or "cold" in attribute list LIST.  */
+
+tree
+lookup_hotness_attribute (tree list)
+{
+  tree attr = lookup_attribute ("hot", list);
+  if (attr)
+    return attr;
+  return lookup_attribute ("cold", list);
+}
+
+/* Remove both "hot" and "cold" attributes from LIST.  */
+
+static tree
+remove_hotness_attribute (tree list)
+{
+  return remove_attribute ("hot", remove_attribute ("cold", list));
+}
+
+/* If [[likely]] or [[unlikely]] appear on this statement, turn it into a
+   PREDICT_EXPR.  */
+
+tree
+process_stmt_hotness_attribute (tree std_attrs)
+{
+  if (std_attrs == error_mark_node)
+    return std_attrs;
+  if (tree attr = lookup_hotness_attribute (std_attrs))
+    {
+      tree name = get_attribute_name (attr);
+      bool hot = is_attribute_p ("hot", name);
+      tree pred = build_predict_expr (hot ? PRED_HOT_LABEL : PRED_COLD_LABEL,
+				      hot ? TAKEN : NOT_TAKEN);
+      add_stmt (pred);
+      if (tree other = lookup_hotness_attribute (TREE_CHAIN (attr)))
+	warning (OPT_Wattributes, "ignoring attribute %qE after earlier %qE",
+		 get_attribute_name (other), name);
+      std_attrs = remove_hotness_attribute (std_attrs);
+    }
+  return std_attrs;
+}
+
 #include "gt-cp-cp-gimplify.h"
diff --git a/gcc/cp/decl.c b/gcc/cp/decl.c
index 42994055d5f..73f27038e5c 100644
--- a/gcc/cp/decl.c
+++ b/gcc/cp/decl.c
@@ -3624,7 +3624,7 @@ finish_case_label (location_t loc, tree low_value, tree high_value)
 
       /* For templates, just add the case label; we'll do semantic
 	 analysis at instantiation-time.  */
-      label = build_decl (loc, LABEL_DECL, NULL_TREE, NULL_TREE);
+      label = build_decl (loc, LABEL_DECL, NULL_TREE, void_type_node);
       return add_stmt (build_case_label (low_value, high_value, label));
     }
 
diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c
index 0428f6dda90..bdc35fa0cb8 100644
--- a/gcc/cp/parser.c
+++ b/gcc/cp/parser.c
@@ -10875,6 +10875,7 @@ cp_parser_statement (cp_parser* parser, tree in_statement_expr,
   /* Peek at the next token.  */
   token = cp_lexer_peek_token (parser->lexer);
   /* Remember the location of the first token in the statement.  */
+  cp_token *statement_token = token;
   statement_location = token->location;
   add_debug_begin_stmt (statement_location);
   /* If this is a keyword, then that will often determine what kind of
@@ -10896,12 +10897,14 @@ cp_parser_statement (cp_parser* parser, tree in_statement_expr,
 
 	case RID_IF:
 	case RID_SWITCH:
+	  std_attrs = process_stmt_hotness_attribute (std_attrs);
 	  statement = cp_parser_selection_statement (parser, if_p, chain);
 	  break;
 
 	case RID_WHILE:
 	case RID_DO:
 	case RID_FOR:
+	  std_attrs = process_stmt_hotness_attribute (std_attrs);
 	  statement = cp_parser_iteration_statement (parser, if_p, false, 0);
 	  break;
 
@@ -10909,6 +10912,7 @@ cp_parser_statement (cp_parser* parser, tree in_statement_expr,
 	case RID_CONTINUE:
 	case RID_RETURN:
 	case RID_GOTO:
+	  std_attrs = process_stmt_hotness_attribute (std_attrs);
 	  statement = cp_parser_jump_statement (parser);
 	  break;
 
@@ -10918,15 +10922,24 @@ cp_parser_statement (cp_parser* parser, tree in_statement_expr,
 	case RID_AT_FINALLY:
 	case RID_AT_SYNCHRONIZED:
 	case RID_AT_THROW:
+	  std_attrs = process_stmt_hotness_attribute (std_attrs);
 	  statement = cp_parser_objc_statement (parser);
 	  break;
 
 	case RID_TRY:
+	  std_attrs = process_stmt_hotness_attribute (std_attrs);
 	  statement = cp_parser_try_block (parser);
 	  break;
 
 	case RID_NAMESPACE:
 	  /* This must be a namespace alias definition.  */
+	  if (std_attrs != NULL_TREE)
+	    {
+	      /*  Attributes should be parsed as part of the the
+		  declaration, so let's un-parse them.  */
+	      saved_tokens.rollback();
+	      std_attrs = NULL_TREE;
+	    }
 	  cp_parser_declaration_statement (parser);
 	  return;
 	  
@@ -10935,9 +10948,11 @@ cp_parser_statement (cp_parser* parser, tree in_statement_expr,
 	case RID_SYNCHRONIZED:
 	case RID_ATOMIC_NOEXCEPT:
 	case RID_ATOMIC_CANCEL:
+	  std_attrs = process_stmt_hotness_attribute (std_attrs);
 	  statement = cp_parser_transaction (parser, token);
 	  break;
 	case RID_TRANSACTION_CANCEL:
+	  std_attrs = process_stmt_hotness_attribute (std_attrs);
 	  statement = cp_parser_transaction_cancel (parser);
 	  break;
 
@@ -10996,12 +11011,9 @@ cp_parser_statement (cp_parser* parser, tree in_statement_expr,
       if (cp_lexer_next_token_is_not (parser->lexer, CPP_SEMICOLON))
 	{
 	  if (std_attrs != NULL_TREE)
-	    {
-	      /*  Attributes should be parsed as part of the the
-		  declaration, so let's un-parse them.  */
-	      saved_tokens.rollback();
-	      std_attrs = NULL_TREE;
-	    }
+	    /* Attributes should be parsed as part of the declaration,
+	       so let's un-parse them.  */
+	    saved_tokens.rollback();
 
 	  cp_parser_parse_tentatively (parser);
 	  /* Try to parse the declaration-statement.  */
@@ -11009,11 +11021,16 @@ cp_parser_statement (cp_parser* parser, tree in_statement_expr,
 	  /* If that worked, we're done.  */
 	  if (cp_parser_parse_definitely (parser))
 	    return;
+	  /* It didn't work, restore the post-attribute position.  */
+	  if (std_attrs)
+	    cp_lexer_set_token_position (parser->lexer, statement_token);
 	}
       /* All preceding labels have been parsed at this point.  */
       if (loc_after_labels != NULL)
 	*loc_after_labels = statement_location;
 
+      std_attrs = process_stmt_hotness_attribute (std_attrs);
+
       /* Look for an expression-statement instead.  */
       statement = cp_parser_expression_statement (parser, in_statement_expr);
 
@@ -11126,7 +11143,10 @@ cp_parser_label_for_labeled_statement (cp_parser* parser, tree attributes)
 	  {
 	    tree l = finish_case_label (token->location, expr, expr_hi);
 	    if (l && TREE_CODE (l) == CASE_LABEL_EXPR)
-	      FALLTHROUGH_LABEL_P (CASE_LABEL (l)) = fallthrough_p;
+	      {
+		label = CASE_LABEL (l);
+		FALLTHROUGH_LABEL_P (label) = fallthrough_p;
+	      }
 	  }
 	else
 	  error_at (token->location,
@@ -11143,7 +11163,10 @@ cp_parser_label_for_labeled_statement (cp_parser* parser, tree attributes)
 	{
 	  tree l = finish_case_label (token->location, NULL_TREE, NULL_TREE);
 	  if (l && TREE_CODE (l) == CASE_LABEL_EXPR)
-	    FALLTHROUGH_LABEL_P (CASE_LABEL (l)) = fallthrough_p;
+	      {
+		label = CASE_LABEL (l);
+		FALLTHROUGH_LABEL_P (label) = fallthrough_p;
+	      }
 	}
       else
 	error_at (token->location, "case label not within a switch statement");
@@ -11173,6 +11196,8 @@ cp_parser_label_for_labeled_statement (cp_parser* parser, tree attributes)
       cp_parser_parse_tentatively (parser);
       attrs = cp_parser_gnu_attributes_opt (parser);
       if (attrs == NULL_TREE
+	  /* And fallthrough always binds to the expression-statement.  */
+	  || attribute_fallthrough_p (attrs)
 	  || cp_lexer_next_token_is_not (parser->lexer, CPP_SEMICOLON))
 	cp_parser_abort_tentative_parse (parser);
       else if (!cp_parser_parse_definitely (parser))
@@ -25528,6 +25553,10 @@ cp_parser_std_attribute (cp_parser *parser, tree attr_ns)
       else if (is_attribute_p ("optimize_for_synchronized", attr_id))
 	TREE_PURPOSE (attribute)
 	  = get_identifier ("transaction_callable");
+      else if (is_attribute_p ("likely", attr_id))
+	TREE_PURPOSE (attribute) = get_identifier ("hot");
+      else if (is_attribute_p ("unlikely", attr_id))
+	TREE_PURPOSE (attribute) = get_identifier ("cold");
       /* Transactional Memory attributes are GNU attributes.  */
       else if (tm_attr_to_mask (attr_id))
 	TREE_PURPOSE (attribute) = attr_id;
diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c
index 0c33c8e1527..dfd9a436465 100644
--- a/gcc/cp/pt.c
+++ b/gcc/cp/pt.c
@@ -17175,12 +17175,17 @@ tsubst_expr (tree t, tree args, tsubst_flags_t complain, tree in_decl,
 
     case CASE_LABEL_EXPR:
       {
+	tree decl = CASE_LABEL (t);
 	tree low = RECUR (CASE_LOW (t));
 	tree high = RECUR (CASE_HIGH (t));
 	tree l = finish_case_label (EXPR_LOCATION (t), low, high);
 	if (l && TREE_CODE (l) == CASE_LABEL_EXPR)
-	  FALLTHROUGH_LABEL_P (CASE_LABEL (l))
-	    = FALLTHROUGH_LABEL_P (CASE_LABEL (t));
+	  {
+	    tree label = CASE_LABEL (l);
+	    FALLTHROUGH_LABEL_P (label) = FALLTHROUGH_LABEL_P (decl);
+	    if (DECL_ATTRIBUTES (decl) != NULL_TREE)
+	      cplus_decl_attributes (&label, DECL_ATTRIBUTES (decl), 0);
+	  }
       }
       break;
 
@@ -17731,6 +17736,9 @@ tsubst_expr (tree t, tree args, tsubst_flags_t complain, tree in_decl,
 			  RECUR (TREE_OPERAND (t, 1)),
 			  RECUR (TREE_OPERAND (t, 2))));
 
+    case PREDICT_EXPR:
+      RETURN (add_stmt (copy_node (t)));
+
     default:
       gcc_assert (!STATEMENT_CODE_P (TREE_CODE (t)));
 
diff --git a/gcc/gimplify.c b/gcc/gimplify.c
index d7cb7840a5d..7fd0ab297f2 100644
--- a/gcc/gimplify.c
+++ b/gcc/gimplify.c
@@ -2504,11 +2504,19 @@ gimplify_case_label_expr (tree *expr_p, gimple_seq *pre_p)
     if (ctxp->case_labels.exists ())
       break;
 
-  label_stmt = gimple_build_label (CASE_LABEL (*expr_p));
+  tree label = CASE_LABEL (*expr_p);
+  label_stmt = gimple_build_label (label);
   gimple_set_location (label_stmt, EXPR_LOCATION (*expr_p));
   ctxp->case_labels.safe_push (*expr_p);
   gimplify_seq_add_stmt (pre_p, label_stmt);
 
+  if (lookup_attribute ("cold", DECL_ATTRIBUTES (label)))
+    gimple_seq_add_stmt (pre_p, gimple_build_predict (PRED_COLD_LABEL,
+						      NOT_TAKEN));
+  else if (lookup_attribute ("hot", DECL_ATTRIBUTES (label)))
+    gimple_seq_add_stmt (pre_p, gimple_build_predict (PRED_HOT_LABEL,
+						      TAKEN));
+
   return GS_ALL_DONE;
 }
 
diff --git a/gcc/testsuite/g++.dg/cpp2a/attr-likely1.C b/gcc/testsuite/g++.dg/cpp2a/attr-likely1.C
new file mode 100644
index 00000000000..43de249bd5a
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp2a/attr-likely1.C
@@ -0,0 +1,38 @@
+// { dg-do compile { target c++2a } }
+// { dg-additional-options -fdump-tree-gimple }
+// { dg-final { scan-tree-dump-times "hot label" 5 "gimple" } }
+// { dg-final { scan-tree-dump-times "cold label" 3 "gimple" } }
+
+bool b;
+
+template <class T> int f()
+{
+  if (b)
+    [[likely]] return 0;
+  else
+    [[unlikely]] flabel: return 1;
+  switch (b)
+    {
+      [[likely]] case true: break;
+    };
+  return 1;
+}
+
+int main()
+{
+  if (b)
+    [[likely]] return 0;
+  else if (b)
+    [[unlikely]] elabel:
+      return 1;
+  else
+    [[likely]] b = false;
+
+  f<int>();
+
+  switch (b)
+    {
+      [[likely]] case true: break;
+      [[unlikely]] case false: break;
+    };
+}
diff --git a/gcc/testsuite/g++.dg/cpp2a/attr-likely2.C b/gcc/testsuite/g++.dg/cpp2a/attr-likely2.C
new file mode 100644
index 00000000000..3c951828c95
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp2a/attr-likely2.C
@@ -0,0 +1,10 @@
+// { dg-do compile { target c++2a } }
+
+bool b;
+int main()
+{
+  if (b)
+    [[likely, likely]] b;	// { dg-warning "ignoring" }
+  else
+    [[likely]] [[unlikely]] b;	// { dg-warning "ignoring" }
+}
diff --git a/gcc/testsuite/g++.dg/cpp2a/feat-cxx2a.C b/gcc/testsuite/g++.dg/cpp2a/feat-cxx2a.C
index dba77179b82..b80cc342364 100644
--- a/gcc/testsuite/g++.dg/cpp2a/feat-cxx2a.C
+++ b/gcc/testsuite/g++.dg/cpp2a/feat-cxx2a.C
@@ -456,6 +456,18 @@
 #    error "__has_cpp_attribute(no_unique_address) != 201803"
 #  endif
 
+#  if ! __has_cpp_attribute(likely)
+#    error "__has_cpp_attribute(likely)"
+#  elif __has_cpp_attribute(likely) != 201803
+#    error "__has_cpp_attribute(likely) != 201803"
+#  endif
+
+#  if ! __has_cpp_attribute(unlikely)
+#    error "__has_cpp_attribute(unlikely)"
+#  elif __has_cpp_attribute(unlikely) != 201803
+#    error "__has_cpp_attribute(unlikely) != 201803"
+#  endif
+
 #else
 #  error "__has_cpp_attribute"
 #endif
diff --git a/gcc/ChangeLog b/gcc/ChangeLog
index 3f98c9001f4..52961030239 100644
--- a/gcc/ChangeLog
+++ b/gcc/ChangeLog
@@ -1,3 +1,7 @@
+2018-11-12  Jason Merrill  <jason@redhat.com>
+
+	* gimplify.c (gimplify_case_label_expr): Handle hot/cold attributes.
+
 2018-11-13  Alan Modra  <amodra@gmail.com>
 
 	* config/rs6000/rs6000.c (rs6000_secondary_reload_inner): Negate
diff --git a/gcc/c-family/ChangeLog b/gcc/c-family/ChangeLog
index 165f9b7efcc..910dd628e87 100644
--- a/gcc/c-family/ChangeLog
+++ b/gcc/c-family/ChangeLog
@@ -1,3 +1,7 @@
+2018-11-11  Jason Merrill  <jason@redhat.com>
+
+	* c-lex.c (c_common_has_attribute): Handle likely/unlikely.
+
 2018-11-12  Jason Merrill  <jason@redhat.com>
 
 	* c-cppbuiltin.c (c_cpp_builtins): Define
diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog
index 5497a0829e3..0da4b720e0e 100644
--- a/gcc/cp/ChangeLog
+++ b/gcc/cp/ChangeLog
@@ -1,3 +1,15 @@
+2018-11-12  Jason Merrill  <jason@redhat.com>
+
+	Implement P0479R5, [[likely]] and [[unlikely]].
+	* parser.c (cp_parser_std_attribute): Handle likely/unlikely.
+	(cp_parser_statement): Call process_stmt_hotness_attribute.
+	(cp_parser_label_for_labeled_statement): Apply attributes to case.
+	* cp-gimplify.c (lookup_hotness_attribute, remove_hotness_attribute)
+	(process_stmt_hotness_attribute): New.
+	* decl.c (finish_case_label): Give label in template type void.
+	* pt.c (tsubst_expr) [CASE_LABEL_EXPR]: Copy attributes.
+	[PREDICT_EXPR]: Handle.
+
 2018-11-12  Jason Merrill  <jason@redhat.com>
 
 	Implement P0722R3, destroying operator delete.

base-commit: 76b94d4ba654e9af1882865933343d11f5c3b18b
-- 
2.17.2


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]