[PATCH, libstdc++] More

2019-11-15 Thread Ed Smith-Rowland via gcc-patches


First of all, the redo of the iterator portion in response to 
https://gcc.gnu.org/ml/gcc-patches/2019-11/msg01467.html passed testing.


This patch contains constexpr char_traits. I also found an old extension 
that had been left out of the constexpr bandwagon that I caught up.


This patch also includes constexpr string_view::copy which depends on 
teh type_traits.


This gets all of p1032 except string::copy (although constexpr 
char_traits should almost enable this too once constexpr string is in).  
I'm done.


This passes on x86_64-linux.

OK?


2019-11-16  Edward Smith-Rowland  <3dw...@verizon.net>

	Implement the char_traits and string_view part of C++20 p1032 Misc.
	constexpr bits.
	* include/bits/char_traits.h (move, copy, assign): Constexpr.
	* include/bits/stl_algobase.h (__memcpy, __memset): New.
	* include/ext/pod_char_traits.h (from, to, operator==, operator<)
	(assign, eq, lt, compare, length, find, move, copy, assign)
	(to_char_type, to_int_type, eq_int_type, eof, not_eof):
	Make these constespr for appropriate standards.
	* testsuite/21_strings/char_traits/requirements/char/constexpr.cc: New test.
	* testsuite/21_strings/char_traits/requirements/wchar_t/constexpr.cc: New test.
	* include/std/string_view (copy): Constexpr.
	* testsuite/21_strings/basic_string_view/operations/copy/char/constexpr.cc: New test.
	* testsuite/21_strings/basic_string_view/operations/copy/wchar_t/constexpr.cc: New test.

Index: include/bits/char_traits.h
===
--- include/bits/char_traits.h	(revision 278318)
+++ include/bits/char_traits.h	(working copy)
@@ -113,13 +113,13 @@
   static _GLIBCXX14_CONSTEXPR const char_type*
   find(const char_type* __s, std::size_t __n, const char_type& __a);
 
-  static char_type*
+  static _GLIBCXX20_CONSTEXPR char_type*
   move(char_type* __s1, const char_type* __s2, std::size_t __n);
 
-  static char_type*
+  static _GLIBCXX20_CONSTEXPR char_type*
   copy(char_type* __s1, const char_type* __s2, std::size_t __n);
 
-  static char_type*
+  static _GLIBCXX20_CONSTEXPR char_type*
   assign(char_type* __s, std::size_t __n, char_type __a);
 
   static _GLIBCXX_CONSTEXPR char_type
@@ -179,18 +179,17 @@
 }
 
   template
-typename char_traits<_CharT>::char_type*
+_GLIBCXX20_CONSTEXPR typename char_traits<_CharT>::char_type*
 char_traits<_CharT>::
 move(char_type* __s1, const char_type* __s2, std::size_t __n)
 {
   if (__n == 0)
 	return __s1;
-  return static_cast<_CharT*>(__builtin_memmove(__s1, __s2,
-		__n * sizeof(char_type)));
+  return static_cast<_CharT*>(std::__memmove(__s1, __s2, __n));
 }
 
   template
-typename char_traits<_CharT>::char_type*
+_GLIBCXX20_CONSTEXPR typename char_traits<_CharT>::char_type*
 char_traits<_CharT>::
 copy(char_type* __s1, const char_type* __s2, std::size_t __n)
 {
@@ -200,7 +199,7 @@
 }
 
   template
-typename char_traits<_CharT>::char_type*
+_GLIBCXX20_CONSTEXPR typename char_traits<_CharT>::char_type*
 char_traits<_CharT>::
 assign(char_type* __s, std::size_t __n, char_type __a)
 {
@@ -349,28 +348,28 @@
 	return static_cast(__builtin_memchr(__s, __a, __n));
   }
 
-  static char_type*
+  static _GLIBCXX20_CONSTEXPR char_type*
   move(char_type* __s1, const char_type* __s2, size_t __n)
   {
 	if (__n == 0)
 	  return __s1;
-	return static_cast(__builtin_memmove(__s1, __s2, __n));
+	return static_cast(std::__memmove(__s1, __s2, __n));
   }
 
-  static char_type*
+  static _GLIBCXX20_CONSTEXPR char_type*
   copy(char_type* __s1, const char_type* __s2, size_t __n)
   {
 	if (__n == 0)
 	  return __s1;
-	return static_cast(__builtin_memcpy(__s1, __s2, __n));
+	return static_cast(std::__memcpy(__s1, __s2, __n));
   }
 
-  static char_type*
+  static _GLIBCXX20_CONSTEXPR char_type*
   assign(char_type* __s, size_t __n, char_type __a)
   {
 	if (__n == 0)
 	  return __s;
-	return static_cast(__builtin_memset(__s, __a, __n));
+	return static_cast(std::__memset(__s, __a, __n));
   }
 
   static _GLIBCXX_CONSTEXPR char_type
@@ -458,27 +457,42 @@
 	return wmemchr(__s, __a, __n);
   }
 
-  static char_type*
+  static _GLIBCXX20_CONSTEXPR char_type*
   move(char_type* __s1, const char_type* __s2, size_t __n)
   {
 	if (__n == 0)
 	  return __s1;
+#ifdef __cpp_lib_is_constant_evaluated
+	if (std::is_constant_evaluated())
+	  return static_cast(std::__memmove(__s1, __s2, __n));
+	else
+#endif
 	return wmemmove(__s1, __s2, __n);
   }
 
-  static char_type*
+  static _GLIBCXX20_CONSTEXPR char_type*
   copy(char_type* __s1, const char_type* __s2, size_t __n)
   {
 	if (__n == 0)
 	  return __s1;
+#ifdef __cpp_lib_is_constant_evaluated
+	if (std::is_constant_evaluated())
+	  return static_cast(std::__memcpy(__s1, __s2, __n));
+	else
+#endif
 	return 

Re: Symver attribute

2019-11-15 Thread Martin Sebor

On 11/15/19 9:04 AM, Jan Hubicka wrote:

Hi,
thanks for feedback. Here is updated patch that incorporates Martin's
changes, formatting corrections and makes symvers of aliases work.


Just a couple of questions and a few minor nits, mostly having to
do with my favorite subject of quoting things in diagnostics ;-)



Honza

* c-family/c-attribs.c (handle_symver_attribute): New.
(c_common_attribytes): Add symver.
* cgraph.h (symtab_node): Add symver flag.
* cgraphunit.c (process_symver_attribute): New.
(process_common_attributes): Use it.
(cgraph_node::assemble_thunks_and_aliases): Assemble symvers.
* config/elfos.h (ASM_OUTPUT_SYMVER_DIRECTIVE): New.
* lto-cgraph.c (lto_output_node, lto_output_varpool_node,
input_overwrite_node, input_varpool_node): Stream symver attributes.
* output.h (do_assemble_symver): Declare.
* symtab.c (symtab_node::dump_base): Dump symver flag.
(symtab_node::verify_base): Sanity check symver.
(symtab_node::resolve_alias): Add support for symvers.
* varasm.c (do_assemble_symver): New.
* varpool.c (varpool_node::assemble_aliases): Output symver.

* doc/extend.texi (symver): Document new attribute.
Index: c-family/c-attribs.c
===
--- c-family/c-attribs.c(revision 278293)
+++ c-family/c-attribs.c(working copy)
@@ -146,6 +146,7 @@ static tree handle_omp_declare_target_at
  static tree handle_designated_init_attribute (tree *, tree, tree, int, bool 
*);
  static tree handle_patchable_function_entry_attribute (tree *, tree, tree,
   int, bool *);
+static tree handle_symver_attribute (tree *, tree, tree, int, bool *);
  static tree handle_copy_attribute (tree *, tree, tree, int, bool *);
  
  /* Helper to define attribute exclusions.  */

@@ -473,6 +474,8 @@ const struct attribute_spec c_common_att
  NULL },
{ "nocf_check", 0, 0, false, true, true, true,
  handle_nocf_check_attribute, NULL },
+  { "symver",  1, -1, true, false, false, false,
+ handle_symver_attribute, NULL},
{ "copy",   1, 1, false, false, false, false,
  handle_copy_attribute, NULL },
{ "noinit", 0, 0, true,  false, false, false,
@@ -2329,6 +2332,59 @@ handle_noplt_attribute (tree *node, tree
return NULL_TREE;
  }
  
+static tree

+handle_symver_attribute (tree *node, tree ARG_UNUSED (name), tree args,
+int ARG_UNUSED (flags), bool *no_add_attrs)
+{
+  tree symver;
+  const char *symver_str;
+
+  if (TREE_CODE (*node) != FUNCTION_DECL && TREE_CODE (*node) != VAR_DECL)


Should the attribute apply to member functions as well?  If not,
FWIW, I think VAR_OR_FUNCTION_DECL_P() tests for just functions
and variables.


+{
+  warning (OPT_Wattributes,
+  "% attribute is only applicable on functions and "
+  "variables");


"applicable to functions" as below (though I think the far more
common phrase among GCC messages is "applies to functions").


+  *no_add_attrs = true;
+  return NULL_TREE;
+}
+
+  if (!decl_in_symtab_p (*node))
+{
+  warning (OPT_Wattributes,
+  "% attribute is only applicable to symbols");
+  *no_add_attrs = true;
+  return NULL_TREE;
+}
+
+  for (; args; args = TREE_CHAIN (args))
+{
+  symver = TREE_VALUE (args);
+  if (TREE_CODE (symver) != STRING_CST)
+   {
+ error ("% attribute argument not a string constant");
+ *no_add_attrs = true;
+ return NULL_TREE;
+   }
+
+  symver_str = TREE_STRING_POINTER (symver);
+
+  int ats = 0;
+  for (int n = 0; n < TREE_STRING_LENGTH (symver); n++)
+   if (symver_str[n] == '@')
+ ats++;
+
+  if (ats != 1 && ats != 2)
+   {
+ error ("symver attribute argument must have format "


The "symver" part should be quoted same as above.


+"%");
+ *no_add_attrs = true;
+ return NULL_TREE;
+   }
+}
+
+  return NULL_TREE;
+}
+
  /* Handle an "alias" or "ifunc" attribute; arguments as in
 struct attribute_spec.handler, except that IS_ALIAS tells us
 whether this is an alias as opposed to ifunc attribute.  */
Index: cgraph.h
===
--- cgraph.h(revision 278293)
+++ cgraph.h(working copy)
@@ -497,6 +497,8 @@ public:
   and their visibility needs to be copied from their "masters" at
   the end of parsing.  */
unsigned cpp_implicit_alias : 1;
+  /* The alias is a symbol version.  */
+  unsigned symver : 1;
/* Set once the definition was analyzed.  The list of references and
   other properties are built during analysis.  */

[PATCH 43/49] analyzer: new file: exploded-graph.h

2019-11-15 Thread David Malcolm
This patch adds exploded_graph and related classes, for managing
exploring paths through the user's code as a directed graph
of  pairs.

gcc/ChangeLog:
* analyzer/exploded-graph.h: New file.
---
 gcc/analyzer/exploded-graph.h | 754 ++
 1 file changed, 754 insertions(+)
 create mode 100644 gcc/analyzer/exploded-graph.h

diff --git a/gcc/analyzer/exploded-graph.h b/gcc/analyzer/exploded-graph.h
new file mode 100644
index 000..f97d2b6
--- /dev/null
+++ b/gcc/analyzer/exploded-graph.h
@@ -0,0 +1,754 @@
+/* Classes for managing a directed graph of  pairs.
+   Copyright (C) 2019 Free Software Foundation, Inc.
+   Contributed by David Malcolm .
+
+This file is part of GCC.
+
+GCC is free software; you can redistribute it and/or modify it
+under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 3, or (at your option)
+any later version.
+
+GCC is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GCC; see the file COPYING3.  If not see
+.  */
+
+#ifndef GCC_ANALYZER_EXPLODED_GRAPH_H
+#define GCC_ANALYZER_EXPLODED_GRAPH_H
+
+#include "fibonacci_heap.h"
+#include "analyzer/analyzer-logging.h"
+#include "analyzer/constraint-manager.h"
+#include "analyzer/diagnostic-manager.h"
+#include "analyzer/program-point.h"
+#include "analyzer/program-state.h"
+#include "analyzer/shortest-paths.h"
+
+///
+
+/* Concrete implementation of region_model_context, wiring it up to the
+   rest of the analysis engine.  */
+
+class impl_region_model_context : public region_model_context, public log_user
+{
+ public:
+  impl_region_model_context (exploded_graph ,
+const exploded_node *enode_for_diag,
+
+/* TODO: should we be getting the ECs from the
+   old state, rather than the new?  */
+const program_state *old_state,
+program_state *new_state,
+state_change *change,
+
+const gimple *stmt,
+stmt_finder *stmt_finder = NULL);
+
+  impl_region_model_context (program_state *state,
+state_change *change,
+const extrinsic_state _state);
+
+  void warn (pending_diagnostic *d) FINAL OVERRIDE;
+
+  void remap_svalue_ids (const svalue_id_map ) FINAL OVERRIDE;
+
+  int on_svalue_purge (svalue_id first_unused_sid,
+  const svalue_id_map ) FINAL OVERRIDE;
+
+  logger *get_logger () FINAL OVERRIDE
+  {
+return log_user::get_logger ();
+  }
+
+  void on_state_leak (const state_machine ,
+ int sm_idx,
+ svalue_id sid,
+ svalue_id first_unused_sid,
+ const svalue_id_map ,
+ state_machine::state_t state);
+
+  void on_inherited_svalue (svalue_id parent_sid,
+   svalue_id child_sid) FINAL OVERRIDE;
+
+  void on_cast (svalue_id src_sid,
+   svalue_id dst_sid) FINAL OVERRIDE;
+
+  void on_condition (tree lhs, enum tree_code op, tree rhs) FINAL OVERRIDE;
+
+  exploded_graph *m_eg;
+  const exploded_node *m_enode_for_diag;
+  const program_state *m_old_state;
+  program_state *m_new_state;
+  state_change *m_change;
+  const gimple *m_stmt;
+  stmt_finder *m_stmt_finder;
+  const extrinsic_state _ext_state;
+};
+
+
+
+/* A  pair, used internally by
+   exploded_node as its immutable data, and as a key for identifying
+   exploded_nodes we've already seen in the graph.  */
+
+struct point_and_state
+{
+  point_and_state (const program_point ,
+  const program_state )
+  : m_point (point),
+m_state (state),
+m_hash (m_point.hash () ^ m_state.hash ())
+  {
+  }
+
+  hashval_t hash () const
+  {
+return m_hash;
+  }
+  bool operator== (const point_and_state ) const
+  {
+return m_point == other.m_point && m_state == other.m_state;
+  }
+
+  void set_state (const program_state )
+  {
+m_state = state;
+m_hash = m_point.hash () ^ m_state.hash ();
+  }
+
+  program_point m_point;
+  program_state m_state;
+  hashval_t m_hash;
+};
+
+/* A traits class for exploded graphs and their nodes and edges.  */
+
+struct eg_traits
+{
+  typedef exploded_node node_t;
+  typedef exploded_edge edge_t;
+  typedef exploded_graph graph_t;
+  struct dump_args_t
+  {
+dump_args_t (const exploded_graph ) : m_eg (eg) {}
+const exploded_graph _eg;
+  };
+  typedef exploded_cluster 

[PATCH 45/49] analyzer: new files: engine.{cc|h}

2019-11-15 Thread David Malcolm
This patch adds the core analysis code, which explores "interesting"
interprocedual paths in the code, updating state machines to check
for API misuses, and issuing diagnostics for such misuses.

gcc/ChangeLog:
* analyzer/engine.cc: New file.
* analyzer/engine.h: New file.
---
 gcc/analyzer/engine.cc | 3416 
 gcc/analyzer/engine.h  |   26 +
 2 files changed, 3442 insertions(+)
 create mode 100644 gcc/analyzer/engine.cc
 create mode 100644 gcc/analyzer/engine.h

diff --git a/gcc/analyzer/engine.cc b/gcc/analyzer/engine.cc
new file mode 100644
index 000..34941d2
--- /dev/null
+++ b/gcc/analyzer/engine.cc
@@ -0,0 +1,3416 @@
+/* The analysis "engine".
+   Copyright (C) 2019 Free Software Foundation, Inc.
+   Contributed by David Malcolm .
+
+This file is part of GCC.
+
+GCC is free software; you can redistribute it and/or modify it
+under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 3, or (at your option)
+any later version.
+
+GCC is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GCC; see the file COPYING3.  If not see
+.  */
+
+#include "config.h"
+#include "gcc-plugin.h"
+#include "system.h"
+#include "coretypes.h"
+#include "tree.h"
+#include "params.h"
+#include "gcc-rich-location.h"
+#include "analyzer/exploded-graph.h"
+#include "analyzer/analysis-plan.h"
+#include "analyzer/state-purge.h"
+
+/* For an overview, see gcc/doc/analyzer.texi.  */
+
+static int readability_comparator (const void *p1, const void *p2);
+
+
+
+/* class impl_region_model_context : public region_model_context, public 
log_user.  */
+
+impl_region_model_context::
+impl_region_model_context (exploded_graph ,
+  const exploded_node *enode_for_diag,
+  const program_state *old_state,
+  program_state *new_state,
+  state_change *change,
+  const gimple *stmt,
+  stmt_finder *stmt_finder)
+: log_user (eg.get_logger ()), m_eg (),
+  m_enode_for_diag (enode_for_diag),
+  m_old_state (old_state),
+  m_new_state (new_state),
+  m_change (change),
+  m_stmt (stmt),
+  m_stmt_finder (stmt_finder),
+  m_ext_state (eg.get_ext_state ())
+{
+}
+
+impl_region_model_context::
+impl_region_model_context (program_state *state,
+  state_change *change,
+  const extrinsic_state _state)
+: log_user (NULL), m_eg (NULL), m_enode_for_diag (NULL),
+  m_old_state (NULL),
+  m_new_state (state),
+  m_change (change),
+  m_stmt (NULL),
+  m_stmt_finder (NULL),
+  m_ext_state (ext_state)
+{
+}
+
+void
+impl_region_model_context::warn (pending_diagnostic *d)
+{
+  LOG_FUNC (get_logger ());
+  if (m_eg)
+m_eg->get_diagnostic_manager ().add_diagnostic
+  (m_enode_for_diag, m_enode_for_diag->get_supernode (),
+   m_stmt, m_stmt_finder, d);
+}
+
+void
+impl_region_model_context::remap_svalue_ids (const svalue_id_map )
+{
+  m_new_state->remap_svalue_ids (map);
+  if (m_change)
+m_change->remap_svalue_ids (map);
+}
+
+int
+impl_region_model_context::on_svalue_purge (svalue_id first_unused_sid,
+   const svalue_id_map )
+{
+  int total = 0;
+  int sm_idx;
+  sm_state_map *smap;
+  FOR_EACH_VEC_ELT (m_new_state->m_checker_states, sm_idx, smap)
+{
+  const state_machine  = m_ext_state.get_sm (sm_idx);
+  total += smap->on_svalue_purge (sm, sm_idx, first_unused_sid,
+ map, this);
+}
+  if (m_change)
+total += m_change->on_svalue_purge (first_unused_sid);
+  return total;
+}
+
+
+
+/* class setjmp_svalue : public svalue.  */
+
+/* Compare the fields of this setjmp_svalue with OTHER, returning true
+   if they are equal.
+   For use by svalue::operator==.  */
+
+bool
+setjmp_svalue::compare_fields (const setjmp_svalue ) const
+{
+  return m_enode == other.m_enode;
+}
+
+/* Implementation of svalue::add_to_hash vfunc for setjmp_svalue.  */
+
+void
+setjmp_svalue::add_to_hash (inchash::hash ) const
+{
+  hstate.add_int (m_enode->m_index);
+}
+
+/* Get the index of the stored exploded_node.  */
+
+int
+setjmp_svalue::get_index () const
+{
+  return m_enode->m_index;
+}
+
+/* Implementation of svalue::print_details vfunc for setjmp_svalue.  */
+
+void
+setjmp_svalue::print_details (const region_model  ATTRIBUTE_UNUSED,
+ svalue_id this_sid ATTRIBUTE_UNUSED,
+ 

[PATCH 47/49] analyzer: new files: diagnostic-manager.{cc|h}

2019-11-15 Thread David Malcolm
This patch adds diagnostic_manager and related support classes for
saving, deduplicating, and emitting analyzer diagnostics.

gcc/ChangeLog:
* analyzer/diagnostic-manager.cc: New file.
* analyzer/diagnostic-manager.h: New file.
---
 gcc/analyzer/diagnostic-manager.cc | 1117 
 gcc/analyzer/diagnostic-manager.h  |  116 
 2 files changed, 1233 insertions(+)
 create mode 100644 gcc/analyzer/diagnostic-manager.cc
 create mode 100644 gcc/analyzer/diagnostic-manager.h

diff --git a/gcc/analyzer/diagnostic-manager.cc 
b/gcc/analyzer/diagnostic-manager.cc
new file mode 100644
index 000..fae38c7
--- /dev/null
+++ b/gcc/analyzer/diagnostic-manager.cc
@@ -0,0 +1,1117 @@
+/* Classes for saving, deduplicating, and emitting analyzer diagnostics.
+   Copyright (C) 2019 Free Software Foundation, Inc.
+   Contributed by David Malcolm .
+
+This file is part of GCC.
+
+GCC is free software; you can redistribute it and/or modify it
+under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 3, or (at your option)
+any later version.
+
+GCC is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GCC; see the file COPYING3.  If not see
+.  */
+
+#include "config.h"
+#include "gcc-plugin.h"
+#include "system.h"
+#include "coretypes.h"
+#include "tree.h"
+#include "pretty-print.h"
+#include "gcc-rich-location.h"
+#include "gimple-pretty-print.h"
+#include "analyzer/analyzer.h"
+#include "analyzer/diagnostic-manager.h"
+#include "analyzer/exploded-graph.h"
+#include "analyzer/checker-path.h"
+
+/* class saved_diagnostic.  */
+
+/* saved_diagnostic's ctor.
+   Take ownership of D and STMT_FINDER.  */
+
+saved_diagnostic::saved_diagnostic (const state_machine *sm,
+   const exploded_node *enode,
+   const supernode *snode, const gimple *stmt,
+   stmt_finder *stmt_finder,
+   tree var, state_machine::state_t state,
+   pending_diagnostic *d)
+: m_sm (sm), m_enode (enode), m_snode (snode), m_stmt (stmt),
+ /* stmt_finder could be on-stack; we want our own copy that can
+outlive that.  */
+  m_stmt_finder (stmt_finder ? stmt_finder->clone () : NULL),
+  m_var (var), m_state (state),
+  m_d (d)
+{
+  gcc_assert (m_stmt || m_stmt_finder);
+
+  /* We must have an enode in order to be able to look for paths
+ through the exploded_graph to this diagnostic.  */
+  gcc_assert (m_enode);
+}
+
+/* saved_diagnostic's dtor.  */
+
+saved_diagnostic::~saved_diagnostic ()
+{
+  delete m_stmt_finder;
+  delete m_d;
+}
+
+
+
+/* class diagnostic_manager.  */
+
+/* diagnostic_manager's ctor.  */
+
+diagnostic_manager::diagnostic_manager (logger *logger, int verbosity)
+: log_user (logger), m_verbosity (verbosity)
+{
+}
+
+/* Queue pending_diagnostic D at ENODE for later emission.  */
+
+void
+diagnostic_manager::add_diagnostic (const state_machine *sm,
+   const exploded_node *enode,
+   const supernode *snode, const gimple *stmt,
+   stmt_finder *finder,
+   tree var, state_machine::state_t state,
+   pending_diagnostic *d)
+{
+  LOG_FUNC (get_logger ());
+
+  /* We must have an enode in order to be able to look for paths
+ through the exploded_graph to the diagnostic.  */
+  gcc_assert (enode);
+
+  saved_diagnostic *sd
+= new saved_diagnostic (sm, enode, snode, stmt, finder, var, state, d);
+  m_saved_diagnostics.safe_push (sd);
+  if (get_logger ())
+log ("adding saved diagnostic %i at SN %i: %qs",
+m_saved_diagnostics.length () - 1,
+snode->m_index, d->get_kind ());
+}
+
+/* Queue pending_diagnostic D at ENODE for later emission.  */
+
+void
+diagnostic_manager::add_diagnostic (const exploded_node *enode,
+   const supernode *snode, const gimple *stmt,
+   stmt_finder *finder,
+   pending_diagnostic *d)
+{
+  gcc_assert (enode);
+  add_diagnostic (NULL, enode, snode, stmt, finder, NULL_TREE, 0, d);
+}
+
+/* A class for identifying sets of duplicated pending_diagnostic.
+
+   We want to find the simplest dedupe_candidate amongst those that share a
+   dedupe_key.  */
+
+class dedupe_key
+{
+public:
+  dedupe_key (const saved_diagnostic ,
+ const exploded_path )
+  : m_sd (sd), m_stmt (sd.m_stmt)
+  {
+/* Support deferring the 

[PATCH 46/49] analyzer: new files: checker-path.{cc|h}

2019-11-15 Thread David Malcolm
This patch adds a family of classes for representing paths of events
for analyzer diagnostics.

gcc/ChangeLog:
* analyzer/checker-path.cc: New file.
* analyzer/checker-path.h: New file.
---
 gcc/analyzer/checker-path.cc | 899 +++
 gcc/analyzer/checker-path.h  | 563 +++
 2 files changed, 1462 insertions(+)
 create mode 100644 gcc/analyzer/checker-path.cc
 create mode 100644 gcc/analyzer/checker-path.h

diff --git a/gcc/analyzer/checker-path.cc b/gcc/analyzer/checker-path.cc
new file mode 100644
index 000..5302504
--- /dev/null
+++ b/gcc/analyzer/checker-path.cc
@@ -0,0 +1,899 @@
+/* Subclasses of diagnostic_path and diagnostic_event for analyzer diagnostics.
+   Copyright (C) 2019 Free Software Foundation, Inc.
+   Contributed by David Malcolm .
+
+This file is part of GCC.
+
+GCC is free software; you can redistribute it and/or modify it
+under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 3, or (at your option)
+any later version.
+
+GCC is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GCC; see the file COPYING3.  If not see
+.  */
+
+#include "config.h"
+#include "gcc-plugin.h"
+#include "system.h"
+#include "coretypes.h"
+#include "tree.h"
+#include "gimple.h"
+#include "gimple-pretty-print.h"
+#include "analyzer/analyzer.h"
+#include "analyzer/checker-path.h"
+#include "analyzer/supergraph.h"
+#include "analyzer/diagnostic-manager.h"
+#include "analyzer/exploded-graph.h"
+
+
+
+/* Get a string for EK.  */
+
+const char *
+event_kind_to_string (enum event_kind ek)
+{
+  switch (ek)
+{
+default:
+  gcc_unreachable ();
+case EK_DEBUG:
+  return "EK_DEBUG";
+case EK_STMT:
+  return "EK_STMT";
+case EK_FUNCTION_ENTRY:
+  return "EK_FUNCTION_ENTRY";
+case EK_STATE_CHANGE:
+  return "EK_STATE_CHANGE";
+case EK_START_CFG_EDGE:
+  return "EK_START_CFG_EDGE";
+case EK_END_CFG_EDGE:
+  return "EK_END_CFG_EDGE";
+case EK_CALL_EDGE:
+  return "EK_CALL_EDGE";
+case EK_RETURN_EDGE:
+  return "EK_RETURN_EDGE";
+case EK_SETJMP:
+  return "EK_SETJMP";
+case EK_REWIND_FROM_LONGJMP:
+  return "EK_REWIND_FROM_LONGJMP";
+case EK_REWIND_TO_SETJMP:
+  return "EK_REWIND_TO_SETJMP";
+case EK_WARNING:
+  return "EK_WARNING";
+}
+}
+
+
+
+/* class checker_event : public diagnostic_event.  */
+
+/* Dump this event to PP (for debugging/logging purposes).  */
+
+void
+checker_event::dump (pretty_printer *pp) const
+{
+  label_text event_desc (get_desc (false));
+  pp_printf (pp, "\"%s\" (depth %i, m_loc=%x)",
+event_desc.m_buffer,
+get_stack_depth (),
+get_location ());
+  event_desc.maybe_free ();
+}
+
+/* Hook for being notified when this event has its final id EMISSION_ID
+   and is about to emitted for PD.
+
+   Base implementation of checker_event::prepare_for_emission vfunc;
+   subclasses that override this should chain up to it.
+
+   Record PD and EMISSION_ID, and call the get_desc vfunc, so that any
+   side-effects of the call to get_desc take place before
+   pending_diagnostic::emit is called.
+
+   For example, state_change_event::get_desc can call
+   pending_diagnostic::describe_state_change; free_of_non_heap can use this
+   to tweak the message (TODO: would be neater to simply capture the
+   pertinent data within the sm-state).  */
+
+void
+checker_event::prepare_for_emission (checker_path *,
+pending_diagnostic *pd,
+diagnostic_event_id_t emission_id)
+{
+  m_pending_diagnostic = pd;
+  m_emission_id = emission_id;
+
+  label_text desc = get_desc (false);
+  desc.maybe_free ();
+}
+
+
+
+/* class debug_event : public checker_event.  */
+
+/* Implementation of diagnostic_event::get_desc vfunc for
+   debug_event.
+   Use the saved string as the event's description.  */
+
+label_text
+debug_event::get_desc (bool) const
+{
+  return label_text::borrow (m_desc);
+}
+
+
+
+/* class statement_event : public checker_event.  */
+
+/* statement_event's ctor.  */
+
+statement_event::statement_event (const gimple *stmt, tree fndecl, int depth,
+ const program_state _state)
+: checker_event (EK_STMT, gimple_location (stmt), fndecl, depth),
+  m_stmt (stmt),

[PATCH 48/49] gdbinit.in: add break-on-saved-diagnostic

2019-11-15 Thread David Malcolm
This patch adds a "break-on-saved-diagnostic" command to gdbinit.in,
useful for debugging when a diagnostic is queued by the analyzer.

gcc/ChangeLog:
* gdbinit.in (break-on-saved-diagnostic): New command.
---
 gcc/gdbinit.in | 10 ++
 1 file changed, 10 insertions(+)

diff --git a/gcc/gdbinit.in b/gcc/gdbinit.in
index 42302ae..c7e4a33 100644
--- a/gcc/gdbinit.in
+++ b/gcc/gdbinit.in
@@ -219,6 +219,16 @@ is emitted (as opposed to those warnings that are 
suppressed by
 command-line options).
 end
 
+define break-on-saved-diagnostic
+break diagnostic_manager::add_diagnostic
+end
+
+document break-on-saved-diagnostic
+Put a breakpoint on diagnostic_manager::add_diagnostic, called within
+the analyzer whenever a diagnostic is saved for later de-duplication and
+possible emission.
+end
+
 define reload-gdbhooks
 python import imp; imp.reload(gdbhooks)
 end
-- 
1.8.5.3



[PATCH 39/49] analyzer: new files: analysis-plan.{cc|h}

2019-11-15 Thread David Malcolm
This patch adds an analysis_plan class, which encapsulate decisions about
how the analysis should happen (e.g. the order in which functions should
be traversed).

gcc/ChangeLog:
* analyzer/analysis-plan.cc: New file.
* analyzer/analysis-plan.h: New file.
---
 gcc/analyzer/analysis-plan.cc | 115 ++
 gcc/analyzer/analysis-plan.h  |  56 
 2 files changed, 171 insertions(+)
 create mode 100644 gcc/analyzer/analysis-plan.cc
 create mode 100644 gcc/analyzer/analysis-plan.h

diff --git a/gcc/analyzer/analysis-plan.cc b/gcc/analyzer/analysis-plan.cc
new file mode 100644
index 000..920783b
--- /dev/null
+++ b/gcc/analyzer/analysis-plan.cc
@@ -0,0 +1,115 @@
+/* A class to encapsulate decisions about how the analysis should happen.
+   Copyright (C) 2019 Free Software Foundation, Inc.
+   Contributed by David Malcolm .
+
+This file is part of GCC.
+
+GCC is free software; you can redistribute it and/or modify it
+under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 3, or (at your option)
+any later version.
+
+GCC is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GCC; see the file COPYING3.  If not see
+.  */
+
+#include "config.h"
+#include "gcc-plugin.h"
+#include "system.h"
+#include "coretypes.h"
+#include "tree.h"
+#include "cgraph.h"
+#include "timevar.h"
+#include "ipa-utils.h"
+#include "params.h"
+#include "analyzer/analyzer.h"
+#include "analyzer/analysis-plan.h"
+#include "analyzer/supergraph.h"
+
+/* class analysis_plan.  */
+
+/* analysis_plan's ctor.  */
+
+analysis_plan::analysis_plan (const supergraph , logger *logger)
+: log_user (logger), m_sg (sg),
+  m_cgraph_node_postorder (XCNEWVEC (struct cgraph_node *,
+symtab->cgraph_count)),
+  m_index_by_uid (symtab->cgraph_max_uid)
+{
+  LOG_SCOPE (logger);
+  auto_client_timevar tv ("creating analysis plan");
+
+  m_num_cgraph_nodes = ipa_reverse_postorder (m_cgraph_node_postorder);
+  gcc_assert (m_num_cgraph_nodes == symtab->cgraph_count);
+  if (get_logger_file ())
+ipa_print_order (get_logger_file (),
+"analysis_plan", m_cgraph_node_postorder,
+m_num_cgraph_nodes);
+
+  /* Populate m_index_by_uid.  */
+  for (int i = 0; i < symtab->cgraph_max_uid; i++)
+m_index_by_uid.quick_push (-1);
+  for (int i = 0; i < m_num_cgraph_nodes; i++)
+{
+  gcc_assert (m_cgraph_node_postorder[i]->get_uid ()
+ < symtab->cgraph_max_uid);
+  m_index_by_uid[m_cgraph_node_postorder[i]->get_uid ()] = i;
+}
+}
+
+/* analysis_plan's dtor.  */
+
+analysis_plan::~analysis_plan ()
+{
+  free (m_cgraph_node_postorder);
+}
+
+/* Comparator for use by the exploded_graph's worklist, to order FUN_A
+   and FUN_B so that functions that are to be summarized are visited
+   before the summary is needed (based on a sort of the callgraph).  */
+
+int
+analysis_plan::cmp_function (function *fun_a, function *fun_b) const
+{
+  cgraph_node *node_a = cgraph_node::get (fun_a->decl);
+  cgraph_node *node_b = cgraph_node::get (fun_b->decl);
+
+  int idx_a = m_index_by_uid[node_a->get_uid ()];
+  int idx_b = m_index_by_uid[node_b->get_uid ()];
+
+  return idx_b - idx_a;
+}
+
+/* Return true if the call EDGE should be analyzed using a call summary.
+   Return false if it should be analyzed using a full call and return.  */
+
+bool
+analysis_plan::use_summary_p (const cgraph_edge *edge) const
+{
+  /* Don't use call summaries if -fno-analyzer-call-summaries.  */
+  if (!flag_analyzer_call_summaries)
+return false;
+
+  /* TODO: don't count callsites each time.  */
+  int num_call_sites = 0;
+  const cgraph_node *callee = edge->callee;
+  for (cgraph_edge *edge = callee->callers; edge; edge = edge->next_caller)
+++num_call_sites;
+
+  /* Don't use a call summary if there's only one call site.  */
+  if (num_call_sites <= 1)
+return false;
+
+  /* Require the callee to be sufficiently complex to be worth
+ summarizing.  */
+  if ((int)m_sg.get_num_snodes (callee->get_fun ())
+  < PARAM_VALUE (PARAM_ANALYZER_MIN_SNODES_FOR_CALL_SUMMARY))
+return false;
+
+  return true;
+}
diff --git a/gcc/analyzer/analysis-plan.h b/gcc/analyzer/analysis-plan.h
new file mode 100644
index 000..c9396ec
--- /dev/null
+++ b/gcc/analyzer/analysis-plan.h
@@ -0,0 +1,56 @@
+/* A class to encapsulate decisions about how the analysis should happen.
+   Copyright (C) 2019 Free Software Foundation, Inc.
+   Contributed by David Malcolm .
+
+This file is part of GCC.
+
+GCC is free software; you can redistribute it and/or modify it
+under the terms of the GNU General Public 

[PATCH 41/49] analyzer: new files: program-point.{cc|h}

2019-11-15 Thread David Malcolm
This patch introduces function_point and program_point, classes
for tracking locations within the program (the latter adding
a call_string for tracking interprocedural location).

gcc/ChangeLog:
* analyzer/program-point.cc: New file.
* analyzer/program-point.h: New file.
---
 gcc/analyzer/program-point.cc | 490 ++
 gcc/analyzer/program-point.h  | 316 +++
 2 files changed, 806 insertions(+)
 create mode 100644 gcc/analyzer/program-point.cc
 create mode 100644 gcc/analyzer/program-point.h

diff --git a/gcc/analyzer/program-point.cc b/gcc/analyzer/program-point.cc
new file mode 100644
index 000..fcf77af
--- /dev/null
+++ b/gcc/analyzer/program-point.cc
@@ -0,0 +1,490 @@
+/* Classes for representing locations within the program.
+   Copyright (C) 2019 Free Software Foundation, Inc.
+   Contributed by David Malcolm .
+
+This file is part of GCC.
+
+GCC is free software; you can redistribute it and/or modify it
+under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 3, or (at your option)
+any later version.
+
+GCC is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GCC; see the file COPYING3.  If not see
+.  */
+
+#include "config.h"
+#include "gcc-plugin.h"
+#include "system.h"
+#include "coretypes.h"
+#include "tree.h"
+#include "gimple-pretty-print.h"
+#include "gcc-rich-location.h"
+#include "params.h"
+#include "analyzer/program-point.h"
+#include "analyzer/exploded-graph.h"
+#include "analyzer/analysis-plan.h"
+
+/* Get a string for PK.  */
+
+const char *
+point_kind_to_string (enum point_kind pk)
+{
+  switch (pk)
+{
+default:
+  gcc_unreachable ();
+case PK_ORIGIN:
+  return "PK_ORIGIN";
+case PK_BEFORE_SUPERNODE:
+  return "PK_BEFORE_SUPERNODE";
+case PK_BEFORE_STMT:
+  return "PK_BEFORE_STMT";
+case PK_AFTER_SUPERNODE:
+  return "PK_AFTER_SUPERNODE";
+case PK_EMPTY:
+  return "PK_EMPTY";
+case PK_DELETED:
+  return "PK_DELETED";
+}
+}
+
+/* class function_point.  */
+
+/* Print this function_point to PP.  */
+
+void
+function_point::print (pretty_printer *pp, const format ) const
+{
+  switch (get_kind ())
+{
+default:
+  gcc_unreachable ();
+
+case PK_ORIGIN:
+  pp_printf (pp, "origin");
+  break;
+
+case PK_BEFORE_SUPERNODE:
+  {
+   if (m_from_edge)
+ pp_printf (pp, "before SN: %i (from SN: %i)",
+m_supernode->m_index, m_from_edge->m_src->m_index);
+   else
+ pp_printf (pp, "before SN: %i (NULL from-edge)",
+m_supernode->m_index);
+   f.spacer (pp);
+   for (gphi_iterator gpi
+  = const_cast(get_supernode ())->start_phis ();
+!gsi_end_p (gpi); gsi_next ())
+ {
+   const gphi *phi = gpi.phi ();
+   pp_gimple_stmt_1 (pp, phi, 0, (dump_flags_t)0);
+ }
+  }
+  break;
+
+case PK_BEFORE_STMT:
+  pp_printf (pp, "before (SN: %i stmt: %i): ", m_supernode->m_index,
+m_stmt_idx);
+  f.spacer (pp);
+  pp_gimple_stmt_1 (pp, get_stmt (), 0, (dump_flags_t)0);
+  if (f.m_newlines)
+   {
+ pp_newline (pp);
+ print_source_line (pp);
+   }
+  break;
+
+case PK_AFTER_SUPERNODE:
+  pp_printf (pp, "after SN: %i", m_supernode->m_index);
+  break;
+}
+}
+
+/* Generate a hash value for this function_point.  */
+
+hashval_t
+function_point::hash () const
+{
+  inchash::hash hstate;
+  if (m_supernode)
+hstate.add_int (m_supernode->m_index);
+  hstate.add_ptr (m_from_edge);
+  hstate.add_int (m_stmt_idx);
+  hstate.add_int (m_kind);
+  return hstate.end ();
+}
+
+/* Get the gimple stmt for this function_point, if any.  */
+
+const gimple *
+function_point::get_stmt () const
+{
+  if (m_kind == PK_BEFORE_STMT)
+return m_supernode->m_stmts[m_stmt_idx];
+  else if (m_kind == PK_AFTER_SUPERNODE)
+return m_supernode->get_last_stmt ();
+  else
+return NULL;
+}
+
+/* Get a location for this function_point, if any.  */
+
+location_t
+function_point::get_location () const
+{
+  const gimple *stmt = get_stmt ();
+  if (stmt)
+return stmt->location;
+
+  return UNKNOWN_LOCATION;
+}
+
+/* A subclass of diagnostic_context for use by
+   program_point::print_source_line.  */
+
+class debug_diagnostic_context : public diagnostic_context
+{
+public:
+  debug_diagnostic_context ()
+  {
+diagnostic_initialize (this, 0);
+show_line_numbers_p = true;
+show_caret = true;
+  }
+  ~debug_diagnostic_context ()
+  {
+diagnostic_finish (this);
+  }
+};
+
+/* Print the source line (if any) 

[PATCH 44/49] analyzer: new files: state-purge.{cc|h}

2019-11-15 Thread David Malcolm
This patch adds classes for tracking what state can be safely purged
at any given point in the program.

gcc/ChangeLog:
* analyzer/state-purge.cc: New file.
* analyzer/state-purge.h: New file.
---
 gcc/analyzer/state-purge.cc | 516 
 gcc/analyzer/state-purge.h  | 170 +++
 2 files changed, 686 insertions(+)
 create mode 100644 gcc/analyzer/state-purge.cc
 create mode 100644 gcc/analyzer/state-purge.h

diff --git a/gcc/analyzer/state-purge.cc b/gcc/analyzer/state-purge.cc
new file mode 100644
index 000..caaa946
--- /dev/null
+++ b/gcc/analyzer/state-purge.cc
@@ -0,0 +1,516 @@
+/* Classes for purging state at function_points.
+   Copyright (C) 2019 Free Software Foundation, Inc.
+   Contributed by David Malcolm .
+
+This file is part of GCC.
+
+GCC is free software; you can redistribute it and/or modify it
+under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 3, or (at your option)
+any later version.
+
+GCC is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GCC; see the file COPYING3.  If not see
+.  */
+
+#include "config.h"
+#include "gcc-plugin.h"
+#include "system.h"
+#include "coretypes.h"
+#include "tree.h"
+#include "timevar.h"
+#include "tree-ssa-alias.h"
+#include "gimple.h"
+#include "stringpool.h"
+#include "tree-vrp.h"
+#include "gimple-ssa.h"
+#include "tree-ssanames.h"
+#include "tree-phinodes.h"
+#include "ssa-iterators.h"
+#include "gimple-pretty-print.h"
+#include "analyzer/analyzer.h"
+#include "analyzer/state-purge.h"
+
+/* state_purge_map's ctor.  Walk all SSA names in all functions, building
+   a state_purge_per_ssa_name instance for each.  */
+
+state_purge_map::state_purge_map (const supergraph ,
+ logger *logger)
+: log_user (logger), m_sg (sg)
+{
+  LOG_FUNC (logger);
+
+  auto_client_timevar tv ("state_purge_map ctor");
+
+  cgraph_node *node;
+  FOR_EACH_FUNCTION_WITH_GIMPLE_BODY (node)
+  {
+function *fun = node->get_fun ();
+if (logger)
+  log ("function: %s", function_name (fun));
+//printf ("function: %s\n", function_name (fun));
+tree name;
+unsigned int i;;
+FOR_EACH_SSA_NAME (i, name, fun)
+  {
+   /* For now, don't bother tracking the .MEM SSA names.  */
+   if (tree var = SSA_NAME_VAR (name))
+ if (TREE_CODE (var) == VAR_DECL)
+   if (VAR_DECL_IS_VIRTUAL_OPERAND (var))
+ continue;
+   m_map.put (name, new state_purge_per_ssa_name (*this, name, fun));
+  }
+  }
+}
+
+/* state_purge_map's dtor.  */
+
+state_purge_map::~state_purge_map ()
+{
+  for (iterator iter = m_map.begin (); iter != m_map.end (); ++iter)
+delete (*iter).second;
+}
+
+/* state_purge_per_ssa_name's ctor.
+
+   Locate all uses of VAR within FUN.
+   Walk backwards from each use, marking program points, until
+   we reach the def stmt, populating m_points_needing_var.
+
+   We have to track program points rather than
+   just stmts since there could be empty basic blocks on the way.  */
+
+state_purge_per_ssa_name::state_purge_per_ssa_name (const state_purge_map ,
+   tree name,
+   function *fun)
+: m_points_needing_name (), m_name (name), m_fun (fun)
+{
+  LOG_FUNC (map.get_logger ());
+
+  if (map.get_logger ())
+{
+  map.log ("SSA name: %qE within %qD", name, fun->decl);
+
+  /* Show def stmt.  */
+  const gimple *def_stmt = SSA_NAME_DEF_STMT (name);
+  pretty_printer pp;
+  pp_gimple_stmt_1 (, def_stmt, 0, (dump_flags_t)0);
+  map.log ("def stmt: %s", pp_formatted_text ());
+}
+
+  auto_vec worklist;
+
+  /* Add all immediate uses of name to the worklist.
+ Compare with debug_immediate_uses.  */
+  imm_use_iterator iter;
+  use_operand_p use_p;
+  FOR_EACH_IMM_USE_FAST (use_p, iter, name)
+{
+  if (USE_STMT (use_p))
+   {
+ const gimple *use_stmt = USE_STMT (use_p);
+ if (map.get_logger ())
+   {
+ pretty_printer pp;
+ pp_gimple_stmt_1 (, use_stmt, 0, (dump_flags_t)0);
+ map.log ("used by stmt: %s", pp_formatted_text ());
+   }
+
+ const supernode *snode
+   = map.get_sg ().get_supernode_for_stmt (use_stmt);
+
+ /* If it's a use within a phi node, then we care about
+which in-edge we came from.  */
+ if (use_stmt->code == GIMPLE_PHI)
+   {
+ for (gphi_iterator gpi
+= const_cast (snode)->start_phis ();
+  !gsi_end_p (gpi); gsi_next ())
+   {
+ 

[PATCH 42/49] analyzer: new files: program-state.{cc|h}

2019-11-15 Thread David Malcolm
This patch introduces classes for tracking the state at a particular
path of analysis.

gcc/ChangeLog:
* analyzer/program-state.cc: New file.
* analyzer/program-state.h: New file.
---
 gcc/analyzer/program-state.cc | 1284 +
 gcc/analyzer/program-state.h  |  360 
 2 files changed, 1644 insertions(+)
 create mode 100644 gcc/analyzer/program-state.cc
 create mode 100644 gcc/analyzer/program-state.h

diff --git a/gcc/analyzer/program-state.cc b/gcc/analyzer/program-state.cc
new file mode 100644
index 000..ae15795
--- /dev/null
+++ b/gcc/analyzer/program-state.cc
@@ -0,0 +1,1284 @@
+/* Classes for representing the state of interest at a given path of analysis.
+   Copyright (C) 2019 Free Software Foundation, Inc.
+   Contributed by David Malcolm .
+
+This file is part of GCC.
+
+GCC is free software; you can redistribute it and/or modify it
+under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 3, or (at your option)
+any later version.
+
+GCC is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GCC; see the file COPYING3.  If not see
+.  */
+
+#include "config.h"
+#include "gcc-plugin.h"
+#include "system.h"
+#include "coretypes.h"
+#include "tree.h"
+#include "diagnostic.h"
+#include "analyzer/analyzer.h"
+#include "analyzer/program-state.h"
+#include "analyzer/constraint-manager.h"
+#include "analyzer/exploded-graph.h"
+#include "analyzer/state-purge.h"
+#include "analyzer/analyzer-selftests.h"
+
+
+
+/* class sm_state_map.  */
+
+/* Clone the sm_state_map.  */
+
+sm_state_map *
+sm_state_map::clone () const
+{
+  return new sm_state_map (*this);
+}
+
+/* Clone this sm_state_map, remapping all svalue_ids within it with ID_MAP.
+
+   Return NULL if there are any svalue_ids that have sm-state for which
+   ID_MAP maps them to svalue_id::null (and thus the clone would have lost
+   the sm-state information). */
+
+sm_state_map *
+sm_state_map::clone_with_remapping (const one_way_svalue_id_map _map) const
+{
+  sm_state_map *result = new sm_state_map ();
+  for (typename map_t::iterator iter = m_map.begin ();
+   iter != m_map.end ();
+   ++iter)
+{
+  svalue_id sid = (*iter).first;
+  gcc_assert (!sid.null_p ());
+  entry_t e = (*iter).second;
+  /* TODO: what should we do if the origin maps from non-null to null?
+Is that loss of information acceptable?  */
+  id_map.update (_origin);
+
+  svalue_id new_sid = id_map.get_dst_for_src (sid);
+  if (new_sid.null_p ())
+   {
+ delete result;
+ return NULL;
+   }
+  result->m_map.put (new_sid, e);
+}
+  return result;
+}
+
+/* Print this sm_state_map (for SM) to PP.  */
+
+void
+sm_state_map::print (const state_machine , pretty_printer *pp) const
+{
+  pp_string (pp, "{");
+  for (typename map_t::iterator iter = m_map.begin ();
+   iter != m_map.end ();
+   ++iter)
+{
+  if (iter != m_map.begin ())
+   pp_string (pp, ", ");
+  svalue_id sid = (*iter).first;
+  sid.print (pp);
+
+  entry_t e = (*iter).second;
+  pp_printf (pp, ": %s (origin: ",
+sm.get_state_name (e.m_state));
+  e.m_origin.print (pp);
+  pp_string (pp, ")");
+}
+  pp_string (pp, "}");
+}
+
+/* Dump this object (for SM) to stderr.  */
+
+DEBUG_FUNCTION void
+sm_state_map::dump (const state_machine ) const
+{
+  pretty_printer pp;
+  pp_show_color () = pp_show_color (global_dc->printer);
+  pp.buffer->stream = stderr;
+  print (sm, );
+  pp_newline ();
+  pp_flush ();
+}
+
+/* Return true if no states have been set within this map
+   (all expressions are for the start state).  */
+
+bool
+sm_state_map::is_empty_p () const
+{
+  return m_map.elements () == 0;
+}
+
+/* Generate a hash value for this sm_state_map.  */
+
+hashval_t
+sm_state_map::hash () const
+{
+  hashval_t result = 0;
+
+  /* Accumulate the result by xoring a hash for each slot, so that the
+ result doesn't depend on the ordering of the slots in the map.  */
+
+  for (typename map_t::iterator iter = m_map.begin ();
+   iter != m_map.end ();
+   ++iter)
+{
+  inchash::hash hstate;
+  inchash::add ((*iter).first, hstate);
+  entry_t e = (*iter).second;
+  hstate.add_int (e.m_state);
+  inchash::add (e.m_origin, hstate);
+  result ^= hstate.end ();
+}
+
+  return result;
+}
+
+/* Equality operator for sm_state_map.  */
+
+bool
+sm_state_map::operator== (const sm_state_map ) const
+{
+  if (m_map.elements () != other.m_map.elements ())
+return false;
+
+  for (typename 

[PATCH 40/49] analyzer: new files: call-string.{cc|h}

2019-11-15 Thread David Malcolm
This patch adds call_string, a class for representing the
call stacks at a program_point, so that we can ensure that
paths through the code are interprocedurally valid.

gcc/ChangeLog:
* analyzer/call-string.cc: New file.
* analyzer/call-string.h: New file.
---
 gcc/analyzer/call-string.cc | 201 
 gcc/analyzer/call-string.h  |  74 
 2 files changed, 275 insertions(+)
 create mode 100644 gcc/analyzer/call-string.cc
 create mode 100644 gcc/analyzer/call-string.h

diff --git a/gcc/analyzer/call-string.cc b/gcc/analyzer/call-string.cc
new file mode 100644
index 000..796b5e7
--- /dev/null
+++ b/gcc/analyzer/call-string.cc
@@ -0,0 +1,201 @@
+/* Call stacks at program points.
+   Copyright (C) 2019 Free Software Foundation, Inc.
+   Contributed by David Malcolm .
+
+This file is part of GCC.
+
+GCC is free software; you can redistribute it and/or modify it
+under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 3, or (at your option)
+any later version.
+
+GCC is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GCC; see the file COPYING3.  If not see
+.  */
+
+#include "config.h"
+#include "gcc-plugin.h"
+#include "system.h"
+#include "coretypes.h"
+#include "pretty-print.h"
+#include "tree.h"
+#include "analyzer/call-string.h"
+#include "analyzer/supergraph.h"
+
+/* class call_string.  */
+
+/* call_string's copy ctor.  */
+
+call_string::call_string (const call_string )
+: m_return_edges (other.m_return_edges.length ())
+{
+  const return_superedge *e;
+  int i;
+  FOR_EACH_VEC_ELT (other.m_return_edges, i, e)
+m_return_edges.quick_push (e);
+}
+
+/* call_string's assignment operator.  */
+
+call_string&
+call_string::operator= (const call_string )
+{
+  // would be much simpler if we could rely on vec<> assignment op
+  m_return_edges.truncate (0);
+  m_return_edges.reserve (other.m_return_edges.length (), true);
+  const return_superedge *e;
+  int i;
+  FOR_EACH_VEC_ELT (other.m_return_edges, i, e)
+m_return_edges.quick_push (e);
+  return *this;
+}
+
+/* call_string's equality operator.  */
+
+bool
+call_string::operator== (const call_string ) const
+{
+  if (m_return_edges.length () != other.m_return_edges.length ())
+return false;
+  const return_superedge *e;
+  int i;
+  FOR_EACH_VEC_ELT (m_return_edges, i, e)
+if (e != other.m_return_edges[i])
+  return false;
+  return true;
+}
+
+/* Print this to PP.  */
+
+void
+call_string::print (pretty_printer *pp) const
+{
+  pp_string (pp, "[");
+
+  const return_superedge *e;
+  int i;
+  FOR_EACH_VEC_ELT (m_return_edges, i, e)
+{
+  if (i > 0)
+   pp_string (pp, ", ");
+  pp_printf (pp, "(SN: %i -> SN: %i in %s)",
+e->m_src->m_index, e->m_dest->m_index,
+function_name (e->m_dest->m_fun));
+}
+
+  pp_string (pp, "]");
+}
+
+/* Generate a hash value for this call_string.  */
+
+hashval_t
+call_string::hash () const
+{
+  inchash::hash hstate;
+  int i;
+  const return_superedge *e;
+  FOR_EACH_VEC_ELT (m_return_edges, i, e)
+hstate.add_ptr (e);
+  return hstate.end ();
+}
+
+/* Push the return superedge for CALL_SEDGE onto the end of this
+   call_string.  */
+
+void
+call_string::push_call (const supergraph ,
+   const call_superedge *call_sedge)
+{
+  gcc_assert (call_sedge);
+  const return_superedge *return_sedge = call_sedge->get_edge_for_return (sg);
+  gcc_assert (return_sedge);
+  m_return_edges.safe_push (return_sedge);
+}
+
+/* Count the number of times the top-most call site appears in the
+   stack.  */
+
+int
+call_string::calc_recursion_depth () const
+{
+  if (m_return_edges.is_empty ())
+return 0;
+  const return_superedge *top_return_sedge
+= m_return_edges[m_return_edges.length () - 1];
+
+  int result = 0;
+  const return_superedge *e;
+  int i;
+  FOR_EACH_VEC_ELT (m_return_edges, i, e)
+if (e == top_return_sedge)
+  ++result;
+  return result;
+}
+
+/* Comparator for call strings.
+   Return negative if A is before B.
+   Return positive if B is after A.
+   Return 0 if they are equal.  */
+
+int
+call_string::cmp (const call_string ,
+ const call_string )
+{
+  int result = cmp_1 (a, b);
+
+  /* Check that the ordering is symmetric  */
+#if CHECKING_P
+  int reversed = cmp_1 (b, a);
+  gcc_assert (reversed == -result);
+#endif
+
+  /* We should only have 0 for equal pairs.  */
+  gcc_assert (result != 0
+ || a == b);
+
+  return result;
+}
+
+/* Implementation of call_string::cmp.
+   This implements a version of lexicographical order.  */
+
+int
+call_string::cmp_1 (const call_string ,
+  

[PATCH 37/49] analyzer: new file: sm-sensitive.cc

2019-11-15 Thread David Malcolm
This patch adds a state machine checker for tracking exposure of
sensitive data (e.g. writing passwords to log files).

This checker isn't ready for production, and is presented as a
proof-of-concept of the sm-based approach.

gcc/ChangeLog:
* analyzer/sm-sensitive.cc: New file.
---
 gcc/analyzer/sm-sensitive.cc | 209 +++
 1 file changed, 209 insertions(+)
 create mode 100644 gcc/analyzer/sm-sensitive.cc

diff --git a/gcc/analyzer/sm-sensitive.cc b/gcc/analyzer/sm-sensitive.cc
new file mode 100644
index 000..f634b8f
--- /dev/null
+++ b/gcc/analyzer/sm-sensitive.cc
@@ -0,0 +1,209 @@
+/* An experimental state machine, for tracking exposure of sensitive
+   data (e.g. through logging).
+   Copyright (C) 2019 Free Software Foundation, Inc.
+   Contributed by David Malcolm .
+
+This file is part of GCC.
+
+GCC is free software; you can redistribute it and/or modify it
+under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 3, or (at your option)
+any later version.
+
+GCC is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GCC; see the file COPYING3.  If not see
+.  */
+
+#include "config.h"
+#include "gcc-plugin.h"
+#include "system.h"
+#include "coretypes.h"
+#include "tree.h"
+#include "gimple.h"
+#include "diagnostic-path.h"
+#include "diagnostic-metadata.h"
+#include "analyzer/analyzer.h"
+#include "analyzer/pending-diagnostic.h"
+#include "analyzer/sm.h"
+
+namespace {
+
+/* An experimental state machine, for tracking exposure of sensitive
+   data (e.g. through logging).  */
+
+class sensitive_state_machine : public state_machine
+{
+public:
+  sensitive_state_machine (logger *logger);
+
+  bool inherited_state_p () const FINAL OVERRIDE { return true; }
+
+  bool on_stmt (sm_context *sm_ctxt,
+   const supernode *node,
+   const gimple *stmt) const FINAL OVERRIDE;
+
+  void on_condition (sm_context *sm_ctxt,
+const supernode *node,
+const gimple *stmt,
+tree lhs,
+enum tree_code op,
+tree rhs) const FINAL OVERRIDE;
+
+  void on_leak (sm_context *sm_ctxt,
+   const supernode *node,
+   const gimple *stmt,
+   tree var,
+   state_machine::state_t state) const FINAL OVERRIDE;
+  bool can_purge_p (state_t s) const FINAL OVERRIDE;
+
+private:
+  void warn_for_any_exposure (sm_context *sm_ctxt,
+ const supernode *node,
+ const gimple *stmt,
+ tree arg) const;
+
+  /* Start state.  */
+  state_t m_start;
+
+  /* State for "sensitive" data, such as a password.  */
+  state_t m_sensitive;
+
+  /* Stop state, for a value we don't want to track any more.  */
+  state_t m_stop;
+};
+
+
+
+class exposure_through_output_file
+  : public pending_diagnostic_subclass
+{
+public:
+  exposure_through_output_file (tree arg) : m_arg (arg) {}
+
+  const char *get_kind () const FINAL OVERRIDE { return 
"exposure_through_output_file"; }
+
+  bool operator== (const exposure_through_output_file ) const
+  {
+return m_arg == other.m_arg;
+  }
+
+  bool emit (rich_location *rich_loc) FINAL OVERRIDE
+  {
+diagnostic_metadata m;
+/* CWE-532: Information Exposure Through Log Files */
+m.add_cwe (532);
+return warning_at (rich_loc, m, OPT_Wanalyzer_exposure_through_output_file,
+  "sensitive value %qE written to output file",
+  m_arg);
+  }
+
+private:
+  tree m_arg;
+};
+
+
+
+/* sensitive_state_machine's ctor.  */
+
+sensitive_state_machine::sensitive_state_machine (logger *logger)
+: state_machine ("sensitive", logger)
+{
+  m_start = add_state ("start");
+  m_sensitive = add_state ("sensitive");
+  m_stop = add_state ("stop");
+}
+
+/* Warn about an exposure at NODE and STMT if ARG is in the "sensitive"
+   state.  */
+
+void
+sensitive_state_machine::warn_for_any_exposure (sm_context *sm_ctxt,
+   const supernode *node,
+   const gimple *stmt,
+   tree arg) const
+{
+  sm_ctxt->warn_for_state (node, stmt, arg, m_sensitive,
+  new exposure_through_output_file (arg));
+}
+
+/* Implementation of state_machine::on_stmt vfunc for
+   sensitive_state_machine.  */
+
+bool
+sensitive_state_machine::on_stmt (sm_context *sm_ctxt,
+

[PATCH 38/49] analyzer: new file: sm-taint.cc

2019-11-15 Thread David Malcolm
This patch adds a state machine checker for tracking "taint",
where data potentially under an attacker's control is used for
things like array indices without sanitization (CWE-129).

This checker isn't ready for production, and is presented as a
proof-of-concept of the sm-based approach.

gcc/ChangeLog:
* analyzer/sm-taint.cc: New file.
---
 gcc/analyzer/sm-taint.cc | 338 +++
 1 file changed, 338 insertions(+)
 create mode 100644 gcc/analyzer/sm-taint.cc

diff --git a/gcc/analyzer/sm-taint.cc b/gcc/analyzer/sm-taint.cc
new file mode 100644
index 000..c664a54
--- /dev/null
+++ b/gcc/analyzer/sm-taint.cc
@@ -0,0 +1,338 @@
+/* An experimental state machine, for tracking "taint": unsanitized uses
+   of data potentially under an attacker's control.
+
+   Copyright (C) 2019 Free Software Foundation, Inc.
+   Contributed by David Malcolm .
+
+This file is part of GCC.
+
+GCC is free software; you can redistribute it and/or modify it
+under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 3, or (at your option)
+any later version.
+
+GCC is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GCC; see the file COPYING3.  If not see
+.  */
+
+#include "config.h"
+#include "gcc-plugin.h"
+#include "system.h"
+#include "coretypes.h"
+#include "tree.h"
+#include "gimple.h"
+#include "diagnostic-path.h"
+#include "diagnostic-metadata.h"
+#include "analyzer/analyzer.h"
+#include "analyzer/pending-diagnostic.h"
+#include "analyzer/sm.h"
+
+namespace {
+
+/* An experimental state machine, for tracking "taint": unsanitized uses
+   of data potentially under an attacker's control.  */
+
+class taint_state_machine : public state_machine
+{
+public:
+  taint_state_machine (logger *logger);
+
+  bool inherited_state_p () const FINAL OVERRIDE { return true; }
+
+  bool on_stmt (sm_context *sm_ctxt,
+   const supernode *node,
+   const gimple *stmt) const FINAL OVERRIDE;
+
+  void on_condition (sm_context *sm_ctxt,
+const supernode *node,
+const gimple *stmt,
+tree lhs,
+enum tree_code op,
+tree rhs) const FINAL OVERRIDE;
+
+  void on_leak (sm_context *sm_ctxt,
+   const supernode *node,
+   const gimple *stmt,
+   tree var,
+   state_machine::state_t state) const FINAL OVERRIDE;
+  bool can_purge_p (state_t s) const FINAL OVERRIDE;
+
+  /* Start state.  */
+  state_t m_start;
+
+  /* State for a "tainted" value: unsanitized data potentially under an
+ attacker's control.  */
+  state_t m_tainted;
+
+  /* State for a "tainted" value that has a lower bound.  */
+  state_t m_has_lb;
+
+  /* State for a "tainted" value that has an upper bound.  */
+  state_t m_has_ub;
+
+  /* Stop state, for a value we don't want to track any more.  */
+  state_t m_stop;
+};
+
+
+
+enum bounds
+{
+  BOUNDS_NONE,
+  BOUNDS_UPPER,
+  BOUNDS_LOWER
+};
+
+class tainted_array_index
+  : public pending_diagnostic_subclass
+{
+public:
+  tainted_array_index (const taint_state_machine , tree arg,
+  enum bounds has_bounds)
+  : m_sm (sm), m_arg (arg), m_has_bounds (has_bounds) {}
+
+  const char *get_kind () const FINAL OVERRIDE { return "tainted_array_index"; 
}
+
+  bool operator== (const tainted_array_index ) const
+  {
+return m_arg == other.m_arg;
+  }
+
+  bool emit (rich_location *rich_loc) FINAL OVERRIDE
+  {
+diagnostic_metadata m;
+m.add_cwe (129);
+switch (m_has_bounds)
+  {
+  default:
+   gcc_unreachable ();
+  case BOUNDS_NONE:
+   return warning_at (rich_loc, m, OPT_Wanalyzer_tainted_array_index,
+  "use of tainted value %qE in array lookup"
+  " without bounds checking",
+  m_arg);
+   break;
+  case BOUNDS_UPPER:
+   return warning_at (rich_loc, m, OPT_Wanalyzer_tainted_array_index,
+  "use of tainted value %qE in array lookup"
+  " without lower-bounds checking",
+  m_arg);
+   break;
+  case BOUNDS_LOWER:
+   return warning_at (rich_loc, m, OPT_Wanalyzer_tainted_array_index,
+  "use of tainted value %qE in array lookup"
+  " without upper-bounds checking",
+  m_arg);
+   break;
+  }
+  }
+
+  label_text describe_state_change (const evdesc::state_change )
+FINAL OVERRIDE
+  {
+if 

[PATCH 36/49] analyzer: new file: sm-pattern-test.cc

2019-11-15 Thread David Malcolm
This patch adds a custom state machine checker intended purely for DejaGnu
testing of the sm "machinery".

gcc/ChangeLog:
* analyzer/sm-pattern-test.cc: New file.
---
 gcc/analyzer/sm-pattern-test.cc | 165 
 1 file changed, 165 insertions(+)
 create mode 100644 gcc/analyzer/sm-pattern-test.cc

diff --git a/gcc/analyzer/sm-pattern-test.cc b/gcc/analyzer/sm-pattern-test.cc
new file mode 100644
index 000..cf42cfd
--- /dev/null
+++ b/gcc/analyzer/sm-pattern-test.cc
@@ -0,0 +1,165 @@
+/* A state machine for use in DejaGnu tests, to check that
+   pattern-matching works as expected.
+
+   Copyright (C) 2019 Free Software Foundation, Inc.
+   Contributed by David Malcolm .
+
+This file is part of GCC.
+
+GCC is free software; you can redistribute it and/or modify it
+under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 3, or (at your option)
+any later version.
+
+GCC is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GCC; see the file COPYING3.  If not see
+.  */
+
+#include "config.h"
+#include "gcc-plugin.h"
+#include "system.h"
+#include "coretypes.h"
+#include "tree.h"
+#include "gimple.h"
+#include "tree-pretty-print.h"
+#include "diagnostic-path.h"
+#include "diagnostic-metadata.h"
+#include "analyzer/analyzer.h"
+#include "analyzer/pending-diagnostic.h"
+#include "analyzer/sm.h"
+
+namespace {
+
+/* A state machine for use in DejaGnu tests, to check that
+   pattern-matching works as expected.  */
+
+class pattern_test_state_machine : public state_machine
+{
+public:
+  pattern_test_state_machine (logger *logger);
+
+  bool inherited_state_p () const FINAL OVERRIDE { return false; }
+
+  bool on_stmt (sm_context *sm_ctxt,
+   const supernode *node,
+   const gimple *stmt) const FINAL OVERRIDE;
+
+  void on_condition (sm_context *sm_ctxt,
+const supernode *node,
+const gimple *stmt,
+tree lhs,
+enum tree_code op,
+tree rhs) const FINAL OVERRIDE;
+
+  void on_leak (sm_context *sm_ctxt,
+   const supernode *node,
+   const gimple *stmt,
+   tree var,
+   state_machine::state_t state) const FINAL OVERRIDE;
+  bool can_purge_p (state_t s) const FINAL OVERRIDE;
+
+private:
+  state_t m_start;
+};
+
+
+
+class pattern_match : public pending_diagnostic_subclass
+{
+public:
+  pattern_match (tree lhs, enum tree_code op, tree rhs)
+  : m_lhs (lhs), m_op (op), m_rhs (rhs) {}
+
+  const char *get_kind () const FINAL OVERRIDE { return "pattern_match"; }
+
+  bool operator== (const pattern_match ) const
+  {
+return (m_lhs == other.m_lhs
+   && m_op == other.m_op
+   && m_rhs == other.m_rhs);
+  }
+
+  bool emit (rich_location *rich_loc) FINAL OVERRIDE
+  {
+return warning_at (rich_loc, 0, "pattern match on %<%E %s %E%>",
+  m_lhs, op_symbol_code (m_op), m_rhs);
+  }
+
+private:
+  tree m_lhs;
+  enum tree_code m_op;
+  tree m_rhs;
+};
+
+
+
+pattern_test_state_machine::pattern_test_state_machine (logger *logger)
+: state_machine ("pattern-test", logger)
+{
+  m_start = add_state ("start");
+}
+
+bool
+pattern_test_state_machine::on_stmt (sm_context *sm_ctxt ATTRIBUTE_UNUSED,
+const supernode *node ATTRIBUTE_UNUSED,
+const gimple *stmt ATTRIBUTE_UNUSED) const
+{
+  return false;
+}
+
+/* Implementation of state_machine::on_condition vfunc for
+   pattern_test_state_machine.
+
+   Queue a pattern_match diagnostic for any comparison against a
+   constant.  */
+
+void
+pattern_test_state_machine::on_condition (sm_context *sm_ctxt,
+ const supernode *node,
+ const gimple *stmt,
+ tree lhs,
+ enum tree_code op,
+ tree rhs) const
+{
+  if (stmt == NULL)
+return;
+
+  if (!CONSTANT_CLASS_P (rhs))
+return;
+
+  pending_diagnostic *diag = new pattern_match (lhs, op, rhs);
+  sm_ctxt->warn_for_state (node, stmt, lhs, m_start, diag);
+}
+
+void
+pattern_test_state_machine::on_leak (sm_context *sm_ctxt ATTRIBUTE_UNUSED,
+const supernode *node ATTRIBUTE_UNUSED,
+const gimple *stmt ATTRIBUTE_UNUSED,
+

[PATCH 34/49] analyzer: new file: sm-malloc.cc

2019-11-15 Thread David Malcolm
This patch adds a state machine checker for malloc/free.

gcc/ChangeLog:
* analyzer/sm-malloc.cc: New file.
---
 gcc/analyzer/sm-malloc.cc | 799 ++
 1 file changed, 799 insertions(+)
 create mode 100644 gcc/analyzer/sm-malloc.cc

diff --git a/gcc/analyzer/sm-malloc.cc b/gcc/analyzer/sm-malloc.cc
new file mode 100644
index 000..4e02f37
--- /dev/null
+++ b/gcc/analyzer/sm-malloc.cc
@@ -0,0 +1,799 @@
+/* A state machine for detecting misuses of the malloc/free API.
+   Copyright (C) 2019 Free Software Foundation, Inc.
+   Contributed by David Malcolm .
+
+This file is part of GCC.
+
+GCC is free software; you can redistribute it and/or modify it
+under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 3, or (at your option)
+any later version.
+
+GCC is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GCC; see the file COPYING3.  If not see
+.  */
+
+#include "config.h"
+#include "gcc-plugin.h"
+#include "system.h"
+#include "coretypes.h"
+#include "tree.h"
+#include "gimple.h"
+#include "diagnostic-path.h"
+#include "diagnostic-metadata.h"
+#include "analyzer/analyzer.h"
+#include "analyzer/pending-diagnostic.h"
+#include "analyzer/sm.h"
+
+namespace {
+
+
+
+/* A state machine for detecting misuses of the malloc/free API.  */
+
+class malloc_state_machine : public state_machine
+{
+public:
+  malloc_state_machine (logger *logger);
+
+  bool inherited_state_p () const FINAL OVERRIDE { return false; }
+
+  bool on_stmt (sm_context *sm_ctxt,
+   const supernode *node,
+   const gimple *stmt) const FINAL OVERRIDE;
+
+  void on_condition (sm_context *sm_ctxt,
+const supernode *node,
+const gimple *stmt,
+tree lhs,
+enum tree_code op,
+tree rhs) const FINAL OVERRIDE;
+
+  void on_leak (sm_context *sm_ctxt,
+   const supernode *node,
+   const gimple *stmt,
+   tree var,
+   state_machine::state_t state) const FINAL OVERRIDE;
+  bool can_purge_p (state_t s) const FINAL OVERRIDE;
+
+  /* Start state.  */
+  state_t m_start;
+
+  /* State for a pointer returned from malloc that hasn't been checked for
+ NULL.
+ It could be a pointer to heap-allocated memory, or could be NULL.  */
+  state_t m_unchecked;
+
+  /* State for a pointer that's known to be NULL.  */
+  state_t m_null;
+
+  /* State for a pointer to heap-allocated memory, known to be non-NULL.  */
+  state_t m_nonnull;
+
+  /* State for a pointer to freed memory.  */
+  state_t m_freed;
+
+  /* State for a pointer that's known to not be on the heap (e.g. to a local
+ or global).  */
+  state_t m_non_heap; // TODO: or should this be a different state machine?
+  // or do we need child values etc?
+
+  /* Stop state, for pointers we don't want to track any more.  */
+  state_t m_stop;
+};
+
+
+
+/* Class for diagnostics relating to malloc_state_machine.  */
+
+class malloc_diagnostic : public pending_diagnostic
+{
+public:
+  malloc_diagnostic (const malloc_state_machine , tree arg)
+  : m_sm (sm), m_arg (arg)
+  {}
+
+  bool subclass_equal_p (const pending_diagnostic _other) const OVERRIDE
+  {
+return m_arg == ((const malloc_diagnostic &)base_other).m_arg;
+  }
+
+  label_text describe_state_change (const evdesc::state_change )
+OVERRIDE
+  {
+if (change.m_old_state == m_sm.m_start
+   && change.m_new_state == m_sm.m_unchecked)
+  // TODO: verify that it's the allocation stmt, not a copy
+  return label_text::borrow ("allocated here");
+if (change.m_old_state == m_sm.m_unchecked
+   && change.m_new_state == m_sm.m_nonnull)
+  return change.formatted_print ("assuming %qE is non-NULL",
+change.m_expr);
+if (change.m_new_state == m_sm.m_null)
+  return change.formatted_print ("assuming %qE is NULL",
+change.m_expr);
+return label_text ();
+  }
+
+protected:
+  const malloc_state_machine _sm;
+  tree m_arg;
+};
+
+/* Concrete subclass for reporting double-free diagnostics.  */
+
+class double_free : public malloc_diagnostic
+{
+public:
+  double_free (const malloc_state_machine , tree arg)
+  : malloc_diagnostic (sm, arg)
+  {}
+
+  const char *get_kind () const FINAL OVERRIDE { return "double_free"; }
+
+  bool emit (rich_location *rich_loc) FINAL OVERRIDE
+  {
+auto_diagnostic_group d;
+diagnostic_metadata m;
+

[PATCH 33/49] analyzer: new files: sm.{cc|h}

2019-11-15 Thread David Malcolm
This patch adds a "state_machine" base class for describing
API checkers in terms of state machine transitions.  Followup
patches use this to add specific API checkers.

gcc/ChangeLog:
* analyzer/sm.cc: New file.
* analyzer/sm.h: New file.
---
 gcc/analyzer/sm.cc | 135 
 gcc/analyzer/sm.h  | 160 +
 2 files changed, 295 insertions(+)
 create mode 100644 gcc/analyzer/sm.cc
 create mode 100644 gcc/analyzer/sm.h

diff --git a/gcc/analyzer/sm.cc b/gcc/analyzer/sm.cc
new file mode 100644
index 000..eda9350
--- /dev/null
+++ b/gcc/analyzer/sm.cc
@@ -0,0 +1,135 @@
+/* Modeling API uses and misuses via state machines.
+   Copyright (C) 2019 Free Software Foundation, Inc.
+   Contributed by David Malcolm .
+
+This file is part of GCC.
+
+GCC is free software; you can redistribute it and/or modify it
+under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 3, or (at your option)
+any later version.
+
+GCC is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GCC; see the file COPYING3.  If not see
+.  */
+
+#include "config.h"
+#include "gcc-plugin.h"
+#include "system.h"
+#include "coretypes.h"
+#include "tree.h"
+#include "gimple.h"
+#include "analyzer/analyzer.h"
+#include "analyzer/sm.h"
+
+
+
+/* If STMT is an assignment to zero, return the LHS.  */
+
+tree
+is_zero_assignment (const gimple *stmt)
+{
+  const gassign *assign_stmt = dyn_cast  (stmt);
+  if (!assign_stmt)
+return NULL_TREE;
+
+  enum tree_code op = gimple_assign_rhs_code (assign_stmt);
+  if (op != INTEGER_CST)
+return NULL_TREE;
+
+  if (!zerop (gimple_assign_rhs1 (assign_stmt)))
+return NULL_TREE;
+
+  return gimple_assign_lhs (assign_stmt);
+}
+
+/* If COND_STMT is a comparison against zero of the form (LHS OP 0),
+   return true and write what's being compared to *OUT_LHS and the kind of
+   the comparison to *OUT_OP.  */
+
+bool
+is_comparison_against_zero (const gcond *cond_stmt,
+   tree *out_lhs, enum tree_code *out_op)
+{
+  enum tree_code op = gimple_cond_code (cond_stmt);
+  tree lhs = gimple_cond_lhs (cond_stmt);
+  tree rhs = gimple_cond_rhs (cond_stmt);
+  if (!zerop (rhs))
+return false;
+  // TODO: make it symmetric?
+
+  switch (op)
+{
+case NE_EXPR:
+case EQ_EXPR:
+  *out_lhs = lhs;
+  *out_op = op;
+  return true;
+
+default:
+  return false;
+}
+}
+
+bool
+any_pointer_p (tree var)
+{
+  if (TREE_CODE (TREE_TYPE (var)) != POINTER_TYPE)
+return false;
+
+  return true;
+}
+
+
+
+state_machine::state_t
+state_machine::add_state (const char *name)
+{
+  m_state_names.safe_push (name);
+  return m_state_names.length () - 1;
+}
+
+const char *
+state_machine::get_state_name (state_t s) const
+{
+  return m_state_names[s];
+}
+
+void
+state_machine::validate (state_t s) const
+{
+  gcc_assert (s < m_state_names.length ());
+}
+
+
+
+void
+make_checkers (auto_delete_vec  , logger *logger)
+{
+  out.safe_push (make_malloc_state_machine (logger));
+  out.safe_push (make_fileptr_state_machine (logger));
+  out.safe_push (make_taint_state_machine (logger));
+  out.safe_push (make_sensitive_state_machine (logger));
+
+  /* We only attempt to run the pattern tests if it might have been manually
+ enabled (for DejaGnu purposes).  */
+  if (flag_analyzer_checker)
+out.safe_push (make_pattern_test_state_machine (logger));
+
+  if (flag_analyzer_checker)
+{
+  unsigned read_index, write_index;
+  state_machine **sm;
+
+  /* TODO: this leaks the machines
+Would be nice to log the things that were removed.  */
+  VEC_ORDERED_REMOVE_IF (out, read_index, write_index, sm,
+0 != strcmp (flag_analyzer_checker,
+ (*sm)->get_name ()));
+}
+}
diff --git a/gcc/analyzer/sm.h b/gcc/analyzer/sm.h
new file mode 100644
index 000..0a89f8a
--- /dev/null
+++ b/gcc/analyzer/sm.h
@@ -0,0 +1,160 @@
+/* Modeling API uses and misuses via state machines.
+   Copyright (C) 2019 Free Software Foundation, Inc.
+   Contributed by David Malcolm .
+
+This file is part of GCC.
+
+GCC is free software; you can redistribute it and/or modify it
+under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 3, or (at your option)
+any later version.
+
+GCC is distributed in 

[PATCH 30/49] analyzer: new files: constraint-manager.{cc|h}

2019-11-15 Thread David Malcolm
This patch adds classes for tracking the equivalence classes and
constraints that hold at a point on an execution path.

gcc/ChangeLog:
* analyzer/constraint-manager.cc: New file.
* analyzer/constraint-manager.h: New file.
---
 gcc/analyzer/constraint-manager.cc | 2263 
 gcc/analyzer/constraint-manager.h  |  248 
 2 files changed, 2511 insertions(+)
 create mode 100644 gcc/analyzer/constraint-manager.cc
 create mode 100644 gcc/analyzer/constraint-manager.h

diff --git a/gcc/analyzer/constraint-manager.cc 
b/gcc/analyzer/constraint-manager.cc
new file mode 100644
index 000..12846f2
--- /dev/null
+++ b/gcc/analyzer/constraint-manager.cc
@@ -0,0 +1,2263 @@
+/* Tracking equivalence classes and constraints at a point on an execution 
path.
+   Copyright (C) 2019 Free Software Foundation, Inc.
+   Contributed by David Malcolm .
+
+This file is part of GCC.
+
+GCC is free software; you can redistribute it and/or modify it
+under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 3, or (at your option)
+any later version.
+
+GCC is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GCC; see the file COPYING3.  If not see
+.  */
+
+#include "config.h"
+#include "gcc-plugin.h"
+#include "system.h"
+#include "coretypes.h"
+#include "tree.h"
+#include "gimple.h"
+#include "gimple-iterator.h"
+#include "graphviz.h"
+#include "selftest.h"
+#include "analyzer/analyzer.h"
+#include "analyzer/supergraph.h"
+#include "analyzer/constraint-manager.h"
+#include "analyzer/analyzer-selftests.h"
+
+/* One of the end-points of a range.  */
+
+struct bound
+{
+  bound () : m_constant (NULL_TREE), m_closed (false) {}
+  bound (tree constant, bool closed)
+  : m_constant (constant), m_closed (closed) {}
+
+  void ensure_closed (bool is_upper);
+
+  const char * get_relation_as_str () const;
+
+  tree m_constant;
+  bool m_closed;
+};
+
+/* A range of values, used for determining if a value has been
+   constrained to just one possible constant value.  */
+
+struct range
+{
+  range () : m_lower_bound (), m_upper_bound () {}
+  range (const bound , const bound )
+  : m_lower_bound (lower), m_upper_bound (upper) {}
+
+  void dump (pretty_printer *pp) const;
+
+  bool constrained_to_single_element (tree *out);
+
+  bound m_lower_bound;
+  bound m_upper_bound;
+};
+
+
+
+/* struct bound.  */
+
+/* Ensure that this bound is closed by converting an open bound to a
+   closed one.  */
+
+void
+bound::ensure_closed (bool is_upper)
+{
+  if (!m_closed)
+{
+  /* Offset by 1 in the appropriate direction.
+For example, convert 3 < x into 4 <= x,
+and convert x < 5 into x <= 4.  */
+  gcc_assert (CONSTANT_CLASS_P (m_constant));
+  m_constant = fold_build2 (is_upper ? MINUS_EXPR : PLUS_EXPR,
+   TREE_TYPE (m_constant),
+   m_constant, integer_one_node);
+  gcc_assert (CONSTANT_CLASS_P (m_constant));
+  m_closed = true;
+}
+}
+
+/* Get "<=" vs "<" for this bound.  */
+
+const char *
+bound::get_relation_as_str () const
+{
+  if (m_closed)
+return "<=";
+  else
+return "<";
+}
+
+
+
+/* struct range.  */
+
+/* Dump this range to PP, which must support %E for tree.  */
+
+void
+range::dump (pretty_printer *pp) const
+{
+PUSH_IGNORE_WFORMAT
+  pp_printf (pp, "%qE %s x %s %qE",
+m_lower_bound.m_constant,
+m_lower_bound.get_relation_as_str (),
+m_upper_bound.get_relation_as_str (),
+m_upper_bound.m_constant);
+POP_IGNORE_WFORMAT
+}
+
+/* Determine if there is only one possible value for this range.
+   If so, return true and write the constant to *OUT.
+   Otherwise, return false.  */
+
+bool
+range::constrained_to_single_element (tree *out)
+{
+  if (!INTEGRAL_TYPE_P (TREE_TYPE (m_lower_bound.m_constant)))
+return false;
+  if (!INTEGRAL_TYPE_P (TREE_TYPE (m_upper_bound.m_constant)))
+return false;
+
+  /* Convert any open bounds to closed bounds.  */
+  m_lower_bound.ensure_closed (false);
+  m_upper_bound.ensure_closed (true);
+
+  // Are they equal?
+  tree comparison
+= fold_build2 (EQ_EXPR, boolean_type_node,
+  m_lower_bound.m_constant,
+  m_upper_bound.m_constant);
+  if (comparison == boolean_true_node)
+{
+  *out = m_lower_bound.m_constant;
+  return true;
+}
+  else
+return false;
+}
+
+
+
+/* class equiv_class.  

[PATCH 35/49] analyzer: new file: sm-file.cc

2019-11-15 Thread David Malcolm
This patch adds a state machine checker for stdio's FILE stream API.

gcc/ChangeLog:
* analyzer/sm-file.cc: New file.
---
 gcc/analyzer/sm-file.cc | 338 
 1 file changed, 338 insertions(+)
 create mode 100644 gcc/analyzer/sm-file.cc

diff --git a/gcc/analyzer/sm-file.cc b/gcc/analyzer/sm-file.cc
new file mode 100644
index 000..4fc308c
--- /dev/null
+++ b/gcc/analyzer/sm-file.cc
@@ -0,0 +1,338 @@
+/* A state machine for detecting misuses of 's FILE * API.
+   Copyright (C) 2019 Free Software Foundation, Inc.
+   Contributed by David Malcolm .
+
+This file is part of GCC.
+
+GCC is free software; you can redistribute it and/or modify it
+under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 3, or (at your option)
+any later version.
+
+GCC is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GCC; see the file COPYING3.  If not see
+.  */
+
+#include "config.h"
+#include "gcc-plugin.h"
+#include "system.h"
+#include "coretypes.h"
+#include "tree.h"
+#include "gimple.h"
+#include "diagnostic-path.h"
+#include "diagnostic-metadata.h"
+#include "analyzer/analyzer.h"
+#include "analyzer/pending-diagnostic.h"
+#include "analyzer/sm.h"
+
+namespace {
+
+/* A state machine for detecting misuses of 's FILE * API.  */
+
+class fileptr_state_machine : public state_machine
+{
+public:
+  fileptr_state_machine (logger *logger);
+
+  bool inherited_state_p () const FINAL OVERRIDE { return false; }
+
+  bool on_stmt (sm_context *sm_ctxt,
+   const supernode *node,
+   const gimple *stmt) const FINAL OVERRIDE;
+
+  void on_condition (sm_context *sm_ctxt,
+const supernode *node,
+const gimple *stmt,
+tree lhs,
+enum tree_code op,
+tree rhs) const FINAL OVERRIDE;
+
+  void on_leak (sm_context *sm_ctxt,
+   const supernode *node,
+   const gimple *stmt,
+   tree var,
+   state_machine::state_t state) const FINAL OVERRIDE;
+  bool can_purge_p (state_t s) const FINAL OVERRIDE;
+
+  /* Start state.  */
+  state_t m_start;
+
+  /* State for a FILE * returned from fopen that hasn't been checked for
+ NULL.
+ It could be an open stream, or could be NULL.  */
+  state_t m_unchecked;
+
+  /* State for a FILE * that's known to be NULL.  */
+  state_t m_null;
+
+  /* State for a FILE * that's known to be a non-NULL open stream.  */
+  state_t m_nonnull;
+
+  /* State for a FILE * that's had fclose called on it.  */
+  state_t m_closed;
+
+  /* Stop state, for a FILE * we don't want to track any more.  */
+  state_t m_stop;
+};
+
+
+
+class file_diagnostic : public pending_diagnostic
+{
+public:
+  file_diagnostic (const fileptr_state_machine , tree arg)
+  : m_sm (sm), m_arg (arg)
+  {}
+
+  bool subclass_equal_p (const pending_diagnostic _other) const OVERRIDE
+  {
+return m_arg == ((const file_diagnostic &)base_other).m_arg;
+  }
+
+  label_text describe_state_change (const evdesc::state_change )
+OVERRIDE
+  {
+if (change.m_old_state == m_sm.m_start
+   && change.m_new_state == m_sm.m_unchecked)
+  // TODO: verify that it's the fopen stmt, not a copy
+  return label_text::borrow ("opened here");
+if (change.m_old_state == m_sm.m_unchecked
+   && change.m_new_state == m_sm.m_nonnull)
+  return change.formatted_print ("assuming %qE is non-NULL",
+change.m_expr);
+if (change.m_new_state == m_sm.m_null)
+  return change.formatted_print ("assuming %qE is NULL",
+change.m_expr);
+return label_text ();
+  }
+
+protected:
+  const fileptr_state_machine _sm;
+  tree m_arg;
+};
+
+class double_fclose : public file_diagnostic
+{
+public:
+  double_fclose (const fileptr_state_machine , tree arg)
+: file_diagnostic (sm, arg)
+  {}
+
+  const char *get_kind () const FINAL OVERRIDE { return "double_fclose"; }
+
+  bool emit (rich_location *rich_loc) FINAL OVERRIDE
+  {
+return warning_at (rich_loc, OPT_Wanalyzer_double_fclose,
+  "double % of FILE %qE",
+  m_arg);
+  }
+
+  label_text describe_state_change (const evdesc::state_change )
+OVERRIDE
+  {
+if (change.m_new_state == m_sm.m_closed)
+  {
+   m_first_fclose_event = change.m_event_id;
+   return change.formatted_print ("first %qs here", "fclose");
+  }
+return file_diagnostic::describe_state_change (change);
+  }
+
+  label_text describe_final_event 

[PATCH 32/49] analyzer: new files: pending-diagnostic.{cc|h}

2019-11-15 Thread David Malcolm
This patch adds classes used by the analyzer for handling its diagnostics
(queueing them, deduplicating them, precision-of-wording hooks).

gcc/ChangeLog:
* analyzer/pending-diagnostic.cc: New file.
* analyzer/pending-diagnostic.h: New file.
---
 gcc/analyzer/pending-diagnostic.cc |  61 +
 gcc/analyzer/pending-diagnostic.h  | 265 +
 2 files changed, 326 insertions(+)
 create mode 100644 gcc/analyzer/pending-diagnostic.cc
 create mode 100644 gcc/analyzer/pending-diagnostic.h

diff --git a/gcc/analyzer/pending-diagnostic.cc 
b/gcc/analyzer/pending-diagnostic.cc
new file mode 100644
index 000..96ab824
--- /dev/null
+++ b/gcc/analyzer/pending-diagnostic.cc
@@ -0,0 +1,61 @@
+/* Classes for analyzer diagnostics.
+   Copyright (C) 2019 Free Software Foundation, Inc.
+   Contributed by David Malcolm .
+
+This file is part of GCC.
+
+GCC is free software; you can redistribute it and/or modify it
+under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 3, or (at your option)
+any later version.
+
+GCC is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GCC; see the file COPYING3.  If not see
+.  */
+
+#include "config.h"
+#include "gcc-plugin.h"
+#include "system.h"
+#include "coretypes.h"
+#include "tree.h"
+#include "intl.h"
+#include "diagnostic.h"
+#include "analyzer/analyzer.h"
+#include "analyzer/pending-diagnostic.h"
+
+/* Generate a label_text by printing FMT.
+
+   Use a clone of the global_dc for formatting callbacks.
+
+   Use this evdesc::event_desc's m_colorize flag to control colorization
+   (so that e.g. we can disable it for JSON output).  */
+
+label_text
+evdesc::event_desc::formatted_print (const char *fmt, ...) const
+{
+  pretty_printer *pp = global_dc->printer->clone ();
+
+  pp_show_color (pp) = m_colorize;
+
+  text_info ti;
+  rich_location rich_loc (line_table, UNKNOWN_LOCATION);
+  va_list ap;
+  va_start (ap, fmt);
+  ti.format_spec = _(fmt);
+  ti.args_ptr = 
+  ti.err_no = 0;
+  ti.x_data = NULL;
+  ti.m_richloc = _loc;
+  pp_format (pp, );
+  pp_output_formatted_text (pp);
+  va_end (ap);
+
+  label_text result = label_text::take (xstrdup (pp_formatted_text (pp)));
+  delete pp;
+  return result;
+}
diff --git a/gcc/analyzer/pending-diagnostic.h 
b/gcc/analyzer/pending-diagnostic.h
new file mode 100644
index 000..f1ab484
--- /dev/null
+++ b/gcc/analyzer/pending-diagnostic.h
@@ -0,0 +1,265 @@
+/* Classes for analyzer diagnostics.
+   Copyright (C) 2019 Free Software Foundation, Inc.
+   Contributed by David Malcolm .
+
+This file is part of GCC.
+
+GCC is free software; you can redistribute it and/or modify it
+under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 3, or (at your option)
+any later version.
+
+GCC is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GCC; see the file COPYING3.  If not see
+.  */
+
+#ifndef GCC_ANALYZER_PENDING_DIAGNOSTIC_H
+#define GCC_ANALYZER_PENDING_DIAGNOSTIC_H
+
+#include "diagnostic-event-id.h"
+#include "analyzer/sm.h"
+
+/* Various bundles of information used for generating more precise
+   messages for events within a diagnostic_path, for passing to the
+   various "describe_*" vfuncs of pending_diagnostic.  See those
+   for more information.  */
+
+namespace evdesc {
+
+struct event_desc
+{
+  event_desc (bool colorize) : m_colorize (colorize) {}
+
+  label_text formatted_print (const char *fmt, ...) const
+ATTRIBUTE_GCC_DIAG(2,3);
+
+  bool m_colorize;
+};
+
+/* For use by pending_diagnostic::describe_state_change.  */
+
+struct state_change : public event_desc
+{
+  state_change (bool colorize,
+   tree expr,
+   tree origin,
+   state_machine::state_t old_state,
+   state_machine::state_t new_state,
+   diagnostic_event_id_t event_id)
+  : event_desc (colorize),
+m_expr (expr), m_origin (origin),
+m_old_state (old_state), m_new_state (new_state),
+m_event_id (event_id)
+  {}
+
+  tree m_expr;
+  tree m_origin;
+  state_machine::state_t m_old_state;
+  state_machine::state_t m_new_state;
+  diagnostic_event_id_t m_event_id;
+};
+
+/* For use by pending_diagnostic::describe_call_with_state.  */
+
+struct call_with_state : public event_desc
+{
+  call_with_state (bool colorize,
+  tree caller_fndecl, tree 

[PATCH 28/49] analyzer: new files: analyzer.{cc|h}

2019-11-15 Thread David Malcolm
gcc/ChangeLog:
* analyzer/analyzer.cc: New file.
* analyzer/analyzer.h: New file.
---
 gcc/analyzer/analyzer.cc | 125 ++
 gcc/analyzer/analyzer.h  | 126 +++
 2 files changed, 251 insertions(+)
 create mode 100644 gcc/analyzer/analyzer.cc
 create mode 100644 gcc/analyzer/analyzer.h

diff --git a/gcc/analyzer/analyzer.cc b/gcc/analyzer/analyzer.cc
new file mode 100644
index 000..399925c
--- /dev/null
+++ b/gcc/analyzer/analyzer.cc
@@ -0,0 +1,125 @@
+/* Utility functions for the analyzer.
+   Copyright (C) 2019 Free Software Foundation, Inc.
+   Contributed by David Malcolm .
+
+This file is part of GCC.
+
+GCC is free software; you can redistribute it and/or modify it
+under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 3, or (at your option)
+any later version.
+
+GCC is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GCC; see the file COPYING3.  If not see
+.  */
+
+#include "config.h"
+#include "gcc-plugin.h"
+#include "system.h"
+#include "coretypes.h"
+#include "tree.h"
+#include "gimple.h"
+#include "diagnostic.h"
+#include "intl.h"
+#include "analyzer/analyzer.h"
+
+/* Helper function for checkers.  Is the CALL to the given function name?  */
+
+bool
+is_named_call_p (const gcall *call, const char *funcname)
+{
+  gcc_assert (funcname);
+
+  tree fndecl = gimple_call_fndecl (call);
+  if (!fndecl)
+return false;
+
+  return 0 == strcmp (IDENTIFIER_POINTER (DECL_NAME (fndecl)), funcname);
+}
+
+/* Helper function for checkers.  Is the CALL to the given function name,
+   and with the given number of arguments?  */
+
+bool
+is_named_call_p (const gcall *call, const char *funcname,
+unsigned int num_args)
+{
+  gcc_assert (funcname);
+
+  if (!is_named_call_p (call, funcname))
+return false;
+
+  if (gimple_call_num_args (call) != num_args)
+return false;
+
+  return true;
+}
+
+/* Return true if stmt is a setjmp call.  */
+
+bool
+is_setjmp_call_p (const gimple *stmt)
+{
+  /* TODO: is there a less hacky way to check for "setjmp"?  */
+  if (const gcall *call = dyn_cast  (stmt))
+if (is_named_call_p (call, "_setjmp", 1))
+  return true;
+
+  return false;
+}
+
+/* Return true if stmt is a longjmp call.  */
+
+bool
+is_longjmp_call_p (const gcall *call)
+{
+  /* TODO: is there a less hacky way to check for "longjmp"?  */
+  if (is_named_call_p (call, "longjmp", 2))
+return true;
+
+  return false;
+}
+
+/* Generate a label_text instance by formatting FMT, using a
+   temporary clone of the global_dc's printer (thus using its
+   formatting callbacks).
+
+   Colorize if the global_dc supports colorization and CAN_COLORIZE is
+   true.  */
+
+label_text
+make_label_text (bool can_colorize, const char *fmt, ...)
+{
+  pretty_printer *pp = global_dc->printer->clone ();
+  pp_clear_output_area (pp);
+
+  if (!can_colorize)
+pp_show_color (pp) = false;
+
+  text_info ti;
+  rich_location rich_loc (line_table, UNKNOWN_LOCATION);
+
+  va_list ap;
+
+  va_start (ap, fmt);
+
+  ti.format_spec = _(fmt);
+  ti.args_ptr = 
+  ti.err_no = 0;
+  ti.x_data = NULL;
+  ti.m_richloc = _loc;
+
+  pp_format (pp, );
+  pp_output_formatted_text (pp);
+
+  va_end (ap);
+
+  label_text result = label_text::take (xstrdup (pp_formatted_text (pp)));
+  delete pp;
+  return result;
+}
diff --git a/gcc/analyzer/analyzer.h b/gcc/analyzer/analyzer.h
new file mode 100644
index 000..ace8924
--- /dev/null
+++ b/gcc/analyzer/analyzer.h
@@ -0,0 +1,126 @@
+/* Utility functions for the analyzer.
+   Copyright (C) 2019 Free Software Foundation, Inc.
+   Contributed by David Malcolm .
+
+This file is part of GCC.
+
+GCC is free software; you can redistribute it and/or modify it
+under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 3, or (at your option)
+any later version.
+
+GCC is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GCC; see the file COPYING3.  If not see
+.  */
+
+#ifndef GCC_ANALYZER_ANALYZER_H
+#define GCC_ANALYZER_ANALYZER_H
+
+/* Forward decls of common types, with indentation to show inheritance.  */
+
+class graphviz_out;
+class supergraph;
+class supernode;
+class superedge;
+  class cfg_superedge;
+class switch_cfg_superedge;
+  class callgraph_superedge;
+class call_superedge;
+

[PATCH 27/49] analyzer: new files: supergraph.{cc|h}

2019-11-15 Thread David Malcolm
This patch adds a "supergraph" class that combines CFGs and callgraph into
one directed graph, along with "supernode" and "superedge" classes.

gcc/ChangeLog:
* analyzer/supergraph.cc: New file.
* analyzer/supergraph.h: New file.
---
 gcc/analyzer/supergraph.cc | 936 +
 gcc/analyzer/supergraph.h  | 560 +++
 2 files changed, 1496 insertions(+)
 create mode 100644 gcc/analyzer/supergraph.cc
 create mode 100644 gcc/analyzer/supergraph.h

diff --git a/gcc/analyzer/supergraph.cc b/gcc/analyzer/supergraph.cc
new file mode 100644
index 000..da5b13a
--- /dev/null
+++ b/gcc/analyzer/supergraph.cc
@@ -0,0 +1,936 @@
+/* "Supergraph" classes that combine CFGs and callgraph into one digraph.
+   Copyright (C) 2019 Free Software Foundation, Inc.
+   Contributed by David Malcolm .
+
+This file is part of GCC.
+
+GCC is free software; you can redistribute it and/or modify it
+under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 3, or (at your option)
+any later version.
+
+GCC is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GCC; see the file COPYING3.  If not see
+.  */
+
+#include "config.h"
+#include "gcc-plugin.h"
+#include "system.h"
+#include "coretypes.h"
+#include "tree.h"
+#include "tm.h"
+#include "toplev.h"
+#include "hash-table.h"
+#include "vec.h"
+#include "ggc.h"
+#include "basic-block.h"
+#include "gimple-fold.h"
+#include "tree-eh.h"
+#include "gimple-expr.h"
+#include "is-a.h"
+#include "timevar.h"
+#include "gimple.h"
+#include "gimple-iterator.h"
+#include "gimple-pretty-print.h"
+#include "tree-pretty-print.h"
+#include "graphviz.h"
+#include "cgraph.h"
+#include "tree-dfa.h"
+#include "analyzer/analyzer.h"
+#include "analyzer/supergraph.h"
+#include "analyzer/analyzer-logging.h"
+
+/* Get the cgraph_edge, but only if there's an underlying function body.  */
+
+cgraph_edge *
+supergraph_call_edge (function *fun, gimple *stmt)
+{
+  gcall *call = dyn_cast (stmt);
+  if (!call)
+return NULL;
+  cgraph_edge *edge = cgraph_node::get (fun->decl)->get_edge (stmt);
+  if (!edge)
+return NULL;
+  if (!edge->callee)
+return NULL; /* e.g. for a function pointer.  */
+  if (!edge->callee->get_fun ())
+return NULL;
+  return edge;
+}
+
+/* supergraph's ctor.  Walk the callgraph, building supernodes for each
+   CFG basic block, splitting the basic blocks at callsites.  Join
+   together the supernodes with interprocedural and intraprocedural
+   superedges as appropriate.  */
+
+supergraph::supergraph (logger *logger)
+{
+  auto_client_timevar tv ("building supergraph");
+
+  LOG_FUNC (logger);
+
+  /* First pass: make supernodes.  */
+  {
+/* Sort the cgraph_nodes?  */
+cgraph_node *node;
+FOR_EACH_FUNCTION_WITH_GIMPLE_BODY (node)
+{
+  function *fun = node->get_fun ();
+
+  /* Ensure that EDGE_DFS_BACK is correct for every CFG edge in
+the supergraph (by doing it per-function).  */
+  auto_cfun sentinel (fun);
+  mark_dfs_back_edges ();
+
+  const int start_idx = m_nodes.length ();
+
+  basic_block bb;
+  FOR_ALL_BB_FN (bb, fun)
+   {
+ /* The initial supernode for the BB gets the phi nodes (if any).  */
+ supernode *node_for_stmts = add_node (fun, bb, NULL, phi_nodes (bb));
+ m_bb_to_initial_node.put (bb, node_for_stmts);
+ for (gphi_iterator gpi = gsi_start_phis (bb); !gsi_end_p (gpi);
+  gsi_next ())
+   {
+ gimple *stmt = gsi_stmt (gpi);
+ m_stmt_to_node_t.put (stmt, node_for_stmts);
+   }
+
+ /* Append statements from BB to the current supernode, splitting
+them into a new supernode at each call site; such call statements
+appear in both supernodes (representing call and return).  */
+ gimple_stmt_iterator gsi;
+ for (gsi = gsi_start_bb (bb); !gsi_end_p (gsi); gsi_next ())
+   {
+ gimple *stmt = gsi_stmt (gsi);
+ node_for_stmts->m_stmts.safe_push (stmt);
+ m_stmt_to_node_t.put (stmt, node_for_stmts);
+ if (cgraph_edge *edge = supergraph_call_edge (fun, stmt))
+   {
+ m_cgraph_edge_to_caller_prev_node.put(edge, node_for_stmts);
+ node_for_stmts = add_node (fun, bb, as_a  (stmt), 
NULL);
+ m_cgraph_edge_to_caller_next_node.put (edge, node_for_stmts);
+   }
+   }
+
+ m_bb_to_final_node.put (bb, node_for_stmts);
+   }
+
+  const unsigned num_snodes = m_nodes.length () - start_idx;
+  m_function_to_num_snodes.put (fun, num_snodes);

[PATCH 29/49] analyzer: new files: tristate.{cc|h}

2019-11-15 Thread David Malcolm
gcc/ChangeLog:
* analyzer/tristate.cc: New file.
* analyzer/tristate.h: New file.
---
 gcc/analyzer/tristate.cc | 222 +++
 gcc/analyzer/tristate.h  |  82 +
 2 files changed, 304 insertions(+)
 create mode 100644 gcc/analyzer/tristate.cc
 create mode 100644 gcc/analyzer/tristate.h

diff --git a/gcc/analyzer/tristate.cc b/gcc/analyzer/tristate.cc
new file mode 100644
index 000..ac16129
--- /dev/null
+++ b/gcc/analyzer/tristate.cc
@@ -0,0 +1,222 @@
+/* "True" vs "False" vs "Unknown".
+   Copyright (C) 2019 Free Software Foundation, Inc.
+   Contributed by David Malcolm .
+
+This file is part of GCC.
+
+GCC is free software; you can redistribute it and/or modify it
+under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 3, or (at your option)
+any later version.
+
+GCC is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GCC; see the file COPYING3.  If not see
+.  */
+
+#include "config.h"
+#include "gcc-plugin.h"
+#include "system.h"
+#include "coretypes.h"
+#include "analyzer/tristate.h"
+#include "selftest.h"
+
+const char *
+tristate::as_string () const
+{
+  switch (m_value)
+{
+default:
+  gcc_unreachable ();
+case TS_UNKNOWN:
+  return "UNKNOWN";
+case TS_TRUE:
+  return "TRUE";
+case TS_FALSE:
+  return "FALSE";
+}
+}
+
+tristate
+tristate::not_ () const
+{
+  switch (m_value)
+{
+default:
+  gcc_unreachable ();
+case TS_UNKNOWN:
+  return tristate (TS_UNKNOWN);
+case TS_TRUE:
+  return tristate (TS_FALSE);
+case TS_FALSE:
+  return tristate (TS_TRUE);
+}
+}
+
+tristate
+tristate::or_ (tristate other) const
+{
+  switch (m_value)
+{
+default:
+  gcc_unreachable ();
+case TS_UNKNOWN:
+  if (other.is_true ())
+   return tristate (TS_TRUE);
+  else
+   return tristate (TS_UNKNOWN);
+case TS_FALSE:
+  return other;
+case TS_TRUE:
+  return tristate (TS_TRUE);
+}
+}
+
+tristate
+tristate::and_ (tristate other) const
+{
+  switch (m_value)
+{
+default:
+  gcc_unreachable ();
+case TS_UNKNOWN:
+  if (other.is_false ())
+   return tristate (TS_FALSE);
+  else
+   return tristate (TS_UNKNOWN);
+case TS_TRUE:
+  return other;
+case TS_FALSE:
+  return tristate (TS_FALSE);
+}
+}
+
+#if CHECKING_P
+
+namespace selftest {
+
+#define ASSERT_TRISTATE_TRUE(TRISTATE) \
+  SELFTEST_BEGIN_STMT  \
+  ASSERT_EQ (TRISTATE, tristate (tristate::TS_TRUE));  \
+  SELFTEST_END_STMT
+
+#define ASSERT_TRISTATE_FALSE(TRISTATE) \
+  SELFTEST_BEGIN_STMT  \
+  ASSERT_EQ (TRISTATE, tristate (tristate::TS_FALSE)); \
+  SELFTEST_END_STMT
+
+#define ASSERT_TRISTATE_UNKNOWN(TRISTATE) \
+  SELFTEST_BEGIN_STMT  \
+  ASSERT_EQ (TRISTATE, tristate (tristate::TS_UNKNOWN));   \
+  SELFTEST_END_STMT
+
+/* Test tristate's ctors, along with is_*, as_string, operator==, and
+   operator!=.  */
+
+static void
+test_ctors ()
+{
+  tristate u (tristate::TS_UNKNOWN);
+  ASSERT_FALSE (u.is_known ());
+  ASSERT_FALSE (u.is_true ());
+  ASSERT_FALSE (u.is_false ());
+  ASSERT_STREQ (u.as_string (), "UNKNOWN");
+
+  tristate t (tristate::TS_TRUE);
+  ASSERT_TRUE (t.is_known ());
+  ASSERT_TRUE (t.is_true ());
+  ASSERT_FALSE (t.is_false ());
+  ASSERT_STREQ (t.as_string (), "TRUE");
+
+  tristate f (tristate::TS_FALSE);
+  ASSERT_TRUE (f.is_known ());
+  ASSERT_FALSE (f.is_true ());
+  ASSERT_TRUE (f.is_false ());
+  ASSERT_STREQ (f.as_string (), "FALSE");
+
+  ASSERT_EQ (u, u);
+  ASSERT_EQ (t, t);
+  ASSERT_EQ (f, f);
+  ASSERT_NE (u, t);
+  ASSERT_NE (u, f);
+  ASSERT_NE (t, f);
+
+  tristate t2 (true);
+  ASSERT_TRUE (t2.is_true ());
+  ASSERT_EQ (t, t2);
+
+  tristate f2 (false);
+  ASSERT_TRUE (f2.is_false ());
+  ASSERT_EQ (f, f2);
+
+  tristate u2 (tristate::unknown ());
+  ASSERT_TRUE (!u2.is_known ());
+  ASSERT_EQ (u, u2);
+}
+
+/* Test && on tristate instances.  */
+
+static void
+test_and ()
+{
+  ASSERT_TRISTATE_UNKNOWN (tristate::unknown () && tristate::unknown ());
+
+  ASSERT_TRISTATE_FALSE (tristate (false) && tristate (false));
+  ASSERT_TRISTATE_FALSE (tristate (false) && tristate (true));
+  ASSERT_TRISTATE_FALSE (tristate (true) && tristate (false));
+  ASSERT_TRISTATE_TRUE (tristate (true) && tristate (true));
+
+  ASSERT_TRISTATE_UNKNOWN (tristate::unknown () && tristate (true));
+  ASSERT_TRISTATE_UNKNOWN (tristate (true) && tristate::unknown ());
+
+  ASSERT_TRISTATE_FALSE (tristate::unknown () && tristate (false));
+  

[PATCH 26/49] analyzer: new files: digraph.{cc|h} and shortest-paths.h

2019-11-15 Thread David Malcolm
This patch adds template classes for directed graphs, their nodes
and edges, and for finding the shortest path through such a graph.

gcc/ChangeLog:
* analyzer/digraph.cc: New file.
* analyzer/digraph.h: New file.
* analyzer/shortest-paths.h: New file.
---
 gcc/analyzer/digraph.cc   | 189 
 gcc/analyzer/digraph.h| 248 ++
 gcc/analyzer/shortest-paths.h | 147 +
 3 files changed, 584 insertions(+)
 create mode 100644 gcc/analyzer/digraph.cc
 create mode 100644 gcc/analyzer/digraph.h
 create mode 100644 gcc/analyzer/shortest-paths.h

diff --git a/gcc/analyzer/digraph.cc b/gcc/analyzer/digraph.cc
new file mode 100644
index 000..c1fa46e
--- /dev/null
+++ b/gcc/analyzer/digraph.cc
@@ -0,0 +1,189 @@
+/* Template classes for directed graphs.
+   Copyright (C) 2019 Free Software Foundation, Inc.
+   Contributed by David Malcolm .
+
+This file is part of GCC.
+
+GCC is free software; you can redistribute it and/or modify it
+under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 3, or (at your option)
+any later version.
+
+GCC is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GCC; see the file COPYING3.  If not see
+.  */
+
+#include "config.h"
+#include "gcc-plugin.h"
+#include "system.h"
+#include "coretypes.h"
+#include "diagnostic.h"
+#include "analyzer/graphviz.h"
+#include "analyzer/digraph.h"
+#include "analyzer/shortest-paths.h"
+#include "selftest.h"
+
+#if CHECKING_P
+
+namespace selftest {
+
+/* A family of digraph classes for writing selftests.  */
+
+struct test_node;
+struct test_edge;
+struct test_graph;
+struct test_dump_args_t {};
+struct test_cluster;
+
+struct test_graph_traits
+{
+  typedef test_node node_t;
+  typedef test_edge edge_t;
+  typedef test_graph graph_t;
+  typedef test_dump_args_t dump_args_t;
+  typedef test_cluster cluster_t;
+};
+
+struct test_node : public dnode
+{
+  test_node (const char *name, int index) : m_name (name), m_index (index) {}
+  void dump_dot (graphviz_out *, const dump_args_t &) const OVERRIDE
+  {
+  }
+
+  const char *m_name;
+  int m_index;
+};
+
+struct test_edge : public dedge
+{
+  test_edge (node_t *src, node_t *dest)
+  : dedge (src, dest)
+  {}
+
+  void dump_dot (graphviz_out *gv, const dump_args_t &) const OVERRIDE
+  {
+gv->println ("%s -> %s;", m_src->m_name, m_dest->m_name);
+  }
+};
+
+struct test_graph : public digraph
+{
+  test_node *add_test_node (const char *name)
+  {
+test_node *result = new test_node (name, m_nodes.length ());
+add_node (result);
+return result;
+  }
+
+  test_edge *add_test_edge (test_node *src, test_node *dst)
+  {
+test_edge *result = new test_edge (src, dst);
+add_edge (result);
+return result;
+  }
+};
+
+struct test_cluster : public cluster
+{
+};
+
+struct test_path
+{
+  auto_vec m_edges;
+};
+
+/* Smoketest of digraph dumping.  */
+
+static void
+test_dump_to_dot ()
+{
+  test_graph g;
+  test_node *a = g.add_test_node ("a");
+  test_node *b = g.add_test_node ("b");
+  g.add_test_edge (a, b);
+
+  pretty_printer pp;
+  pp.buffer->stream = NULL;
+  test_dump_args_t dump_args;
+  g.dump_dot_to_pp (, NULL, dump_args);
+
+  ASSERT_STR_CONTAINS (pp_formatted_text (),
+  "a -> b;\n");
+}
+
+/* Test shortest paths from A in this digraph,
+   where edges run top-to-bottom if not otherwise labeled:
+
+  A
+ / \
+B   C-->D
+|   |
+E   |
+ \ /
+  F.  */
+
+static void
+test_shortest_paths ()
+{
+  test_graph g;
+  test_node *a = g.add_test_node ("a");
+  test_node *b = g.add_test_node ("b");
+  test_node *c = g.add_test_node ("d");
+  test_node *d = g.add_test_node ("d");
+  test_node *e = g.add_test_node ("e");
+  test_node *f = g.add_test_node ("f");
+
+  test_edge *ab = g.add_test_edge (a, b);
+  test_edge *ac = g.add_test_edge (a, c);
+  test_edge *cd = g.add_test_edge (c, d);
+  test_edge *be = g.add_test_edge (b, e);
+  g.add_test_edge (e, f);
+  test_edge *cf = g.add_test_edge (c, f);
+
+  shortest_paths sp (g, a);
+
+  test_path path_to_a = sp.get_shortest_path (a);
+  ASSERT_EQ (path_to_a.m_edges.length (), 0);
+
+  test_path path_to_b = sp.get_shortest_path (b);
+  ASSERT_EQ (path_to_b.m_edges.length (), 1);
+  ASSERT_EQ (path_to_b.m_edges[0], ab);
+
+  test_path path_to_c = sp.get_shortest_path (c);
+  ASSERT_EQ (path_to_c.m_edges.length (), 1);
+  ASSERT_EQ (path_to_c.m_edges[0], ac);
+
+  test_path path_to_d = sp.get_shortest_path (d);
+  ASSERT_EQ (path_to_d.m_edges.length (), 2);
+  ASSERT_EQ (path_to_d.m_edges[0], ac);
+  ASSERT_EQ (path_to_d.m_edges[1], cd);
+
+  

[PATCH 12/49] Add diagnostic paths

2019-11-15 Thread David Malcolm
This patch adds support for associating a "diagnostic_path" with a
diagnostic: a sequence of events predicted by the compiler that leads to
the problem occurring, with their locations in the user's source,
text descriptions, and stack information (for handling interprocedural
paths).

For example, the following (hypothetical) error has a 3-event
intraprocedural path:

test.c: In function 'demo':
test.c:29:5: error: passing NULL as argument 1 to 'PyList_Append' which
  requires a non-NULL parameter
   29 | PyList_Append(list, item);
  | ^
  'demo': events 1-3
 |
 |   25 |   list = PyList_New(0);
 |  |  ^
 |  |  |
 |  |  (1) when 'PyList_New' fails, returning NULL
 |   26 |
 |   27 |   for (i = 0; i < count; i++) {
 |  |   ~~~
 |  |   |
 |  |   (2) when 'i < count'
 |   28 | item = PyLong_FromLong(random());
 |   29 | PyList_Append(list, item);
 |  | ~
 |  | |
 |  | (3) when calling 'PyList_Append', passing NULL from (1) as 
argument 1
 |

The patch adds a new "%@" format code for printing event IDs, so that
in the above, the description of event (3) mentions event (1), showing
the user where the bogus NULL value comes from (the event IDs are
colorized to draw the user's attention to them).

There is a separation between data vs presentation: the above shows how
the diagnostic-printing code has consolidated the path into a single run
of events, since all the events are near each other and within the same
function; more complicated examples (such as interprocedural paths)
might be printed as multiple runs of events.

Examples of how interprocedural paths are printed can be seen in the
test suite (which uses a plugin to exercise the code without relying
on specific warnings using this functionality).

Other output formats include
- JSON,
- printing each event as a separate "note", and
- to not emit paths.

(I have a separate script that can generate HTML from the JSON, but HTML
is not my speciality; help from a web front-end expert to make it look
good would be appreciated).

gcc/ChangeLog:
* Makefile.in (OBJS): Add tree-diagnostic-path.o.
* common.opt (fdiagnostics-path-format=): New option.
(diagnostic_path_format): New enum.
(fdiagnostics-show-path-depths): New option.
* coretypes.h (diagnostic_event_id_t): New forward decl.
* diagnostic-color.c (color_dict): Add "path".
* diagnostic-event-id.h: New file.
* diagnostic-format-json.cc (json_from_expanded_location): Make
non-static.
(json_end_diagnostic): Call context->make_json_for_path if it
exists and the diagnostic has a path.
(diagnostic_output_format_init): Clear context->print_path.
* diagnostic-path.h: New file.
* diagnostic-show-locus.c (colorizer::set_range): Special-case
when printing a run of events in a diagnostic_path so that they
all get the same color.
(layout::m_diagnostic_path_p): New field.
(layout::layout): Initialize it.
(layout::print_any_labels): Don't colorize the label text for an
event in a diagnostic_path.
(gcc_rich_location::add_location_if_nearby): Add
"restrict_to_current_line_spans" and "label" params.  Pass the
former to layout.maybe_add_location_range; pass the latter
when calling add_range.
* diagnostic.c: Include "diagnostic-path.h".
(diagnostic_initialize): Initialize context->path_format and
context->show_path_depths.
(diagnostic_show_any_path): New function.
(diagnostic_path::interprocedural_p): New function.
(diagnostic_report_diagnostic): Call diagnostic_show_any_path.
(simple_diagnostic_path::num_events): New function.
(simple_diagnostic_path::get_event): New function.
(simple_diagnostic_path::add_event): New function.
(simple_diagnostic_event::simple_diagnostic_event): New ctor.
(simple_diagnostic_event::~simple_diagnostic_event): New dtor.
(debug): New overload taking a diagnostic_path *.
* diagnostic.def (DK_DIAGNOSTIC_PATH): New.
* diagnostic.h (enum diagnostic_path_format): New enum.
(json::value): New forward decl.
(diagnostic_context::path_format): New field.
(diagnostic_context::show_path_depths): New field.
(diagnostic_context::print_path): New callback field.
(diagnostic_context::make_json_for_path): New callback field.
(diagnostic_show_any_path): New decl.
(json_from_expanded_location): New decl.
* doc/invoke.texi (-fdiagnostics-path-format=): New option.
(-fdiagnostics-show-path-depths): New option.
(-fdiagnostics-color): Add "path" to description of default
GCC_COLORS; describe it.

[PATCH 23/49] analyzer: logging support

2019-11-15 Thread David Malcolm
This patch adds a logging framework to the analyzer which handles
hierarchical messages (showing the nested structure of the calls).

This code is largely based on that in the "jit" subdirectory (with
a few changes).  An alternative would be to generalize that code
and move it to the gcc parent directory.

gcc/ChangeLog:
* analyzer/analyzer-logging.cc: New file.
* analyzer/analyzer-logging.h: New file.
---
 gcc/analyzer/analyzer-logging.cc | 220 +
 gcc/analyzer/analyzer-logging.h  | 256 +++
 2 files changed, 476 insertions(+)
 create mode 100644 gcc/analyzer/analyzer-logging.cc
 create mode 100644 gcc/analyzer/analyzer-logging.h

diff --git a/gcc/analyzer/analyzer-logging.cc b/gcc/analyzer/analyzer-logging.cc
new file mode 100644
index 000..575435c
--- /dev/null
+++ b/gcc/analyzer/analyzer-logging.cc
@@ -0,0 +1,220 @@
+/* Hierarchical log messages for the analyzer.
+   Copyright (C) 2014-2019 Free Software Foundation, Inc.
+   Contributed by David Malcolm .
+
+This file is part of GCC.
+
+GCC is free software; you can redistribute it and/or modify it
+under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 3, or (at your option)
+any later version.
+
+GCC is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GCC; see the file COPYING3.  If not see
+.  */
+
+#include "config.h"
+#include "system.h"
+#include "coretypes.h"
+#include "toplev.h" /* for print_version */
+#include "pretty-print.h" /* for print_version */
+#include "diagnostic.h"
+#include "tree-diagnostic.h"
+
+#include "analyzer/analyzer-logging.h"
+
+/* Implementation of class logger.  */
+
+/* ctor for logger.  */
+
+logger::logger (FILE *f_out,
+   int, /* flags */
+   int /* verbosity */,
+   const pretty_printer _pp) :
+  m_refcount (0),
+  m_f_out (f_out),
+  m_indent_level (0),
+  m_log_refcount_changes (false),
+  m_pp (reference_pp.clone ())
+{
+  pp_show_color (m_pp) = 0;
+  pp_buffer (m_pp)->stream = f_out;
+
+  /* %qE in logs for SSA_NAMEs should show the ssa names, rather than
+ trying to prettify things by showing the underlying var.  */
+  pp_format_decoder (m_pp) = default_tree_printer;
+
+  /* Begin the log by writing the GCC version.  */
+  print_version (f_out, "", false);
+}
+
+/* The destructor for logger, invoked via
+   the decref method when the refcount hits zero.
+   Note that we do not close the underlying FILE * (m_f_out).  */
+
+logger::~logger ()
+{
+  /* This should be the last message emitted.  */
+  log ("%s", __PRETTY_FUNCTION__);
+  gcc_assert (m_refcount == 0);
+  delete m_pp;
+}
+
+/* Increment the reference count of the logger.  */
+
+void
+logger::incref (const char *reason)
+{
+  m_refcount++;
+  if (m_log_refcount_changes)
+log ("%s: reason: %s refcount now %i ",
+__PRETTY_FUNCTION__, reason, m_refcount);
+}
+
+/* Decrement the reference count of the logger,
+   deleting it if nothing is referring to it.  */
+
+void
+logger::decref (const char *reason)
+{
+  gcc_assert (m_refcount > 0);
+  --m_refcount;
+  if (m_log_refcount_changes)
+log ("%s: reason: %s refcount now %i",
+__PRETTY_FUNCTION__, reason, m_refcount);
+  if (m_refcount == 0)
+delete this;
+}
+
+/* Write a formatted message to the log, by calling the log_va method.  */
+
+void
+logger::log (const char *fmt, ...)
+{
+  va_list ap;
+  va_start (ap, fmt);
+  log_va (fmt, );
+  va_end (ap);
+}
+
+/* Write an indented line to the log file.
+
+   We explicitly flush after each line: if something crashes the process,
+   we want the logfile/stream to contain the most up-to-date hint about the
+   last thing that was happening, without it being hidden in an in-process
+   buffer.  */
+
+void
+logger::log_va (const char *fmt, va_list *ap)
+{
+  start_log_line ();
+  log_va_partial (fmt, ap);
+  end_log_line ();
+}
+
+void
+logger::start_log_line ()
+{
+  for (int i = 0; i < m_indent_level; i++)
+fputc (' ', m_f_out);
+}
+
+void
+logger::log_partial (const char *fmt, ...)
+{
+  va_list ap;
+  va_start (ap, fmt);
+  log_va_partial (fmt, );
+  va_end (ap);
+}
+
+void
+logger::log_va_partial (const char *fmt, va_list *ap)
+{
+  text_info text;
+  text.format_spec = fmt;
+  text.args_ptr = ap;
+  text.err_no = 0;
+  pp_format (m_pp, );
+  pp_output_formatted_text (m_pp);
+}
+
+void
+logger::end_log_line ()
+{
+  pp_flush (m_pp);
+  pp_clear_output_area (m_pp);
+  fprintf (m_f_out, "\n");
+  fflush (m_f_out);
+}
+
+/* Record the entry within a particular scope, indenting subsequent
+   log lines accordingly.  */
+
+void
+logger::enter_scope (const char *scope_name)
+{

[PATCH 25/49] analyzer: new files: graphviz.{cc|h}

2019-11-15 Thread David Malcolm
This patch adds a simple wrapper class to make it easier to
write human-readable .dot files.

gcc/ChangeLog:
* analyzer/graphviz.cc: New file.
* analyzer/graphviz.h: New file.
---
 gcc/analyzer/graphviz.cc | 81 
 gcc/analyzer/graphviz.h  | 50 ++
 2 files changed, 131 insertions(+)
 create mode 100644 gcc/analyzer/graphviz.cc
 create mode 100644 gcc/analyzer/graphviz.h

diff --git a/gcc/analyzer/graphviz.cc b/gcc/analyzer/graphviz.cc
new file mode 100644
index 000..46e7194
--- /dev/null
+++ b/gcc/analyzer/graphviz.cc
@@ -0,0 +1,81 @@
+/* Helper code for graphviz output.
+   Copyright (C) 2019 Free Software Foundation, Inc.
+   Contributed by David Malcolm .
+
+This file is part of GCC.
+
+GCC is free software; you can redistribute it and/or modify it
+under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 3, or (at your option)
+any later version.
+
+GCC is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GCC; see the file COPYING3.  If not see
+.  */
+
+#include "config.h"
+#include "gcc-plugin.h"
+#include "system.h"
+#include "coretypes.h"
+#include "analyzer/graphviz.h"
+
+/* graphviz_out's ctor, wrapping PP.  */
+
+graphviz_out::graphviz_out (pretty_printer *pp)
+: m_pp (pp),
+  m_indent (0)
+{
+}
+
+/* Formatted print of FMT.  */
+
+void
+graphviz_out::print (const char *fmt, ...)
+{
+  text_info text;
+  va_list ap;
+
+  va_start (ap, fmt);
+  text.err_no = errno;
+  text.args_ptr = 
+  text.format_spec = fmt;
+  pp_format (m_pp, );
+  pp_output_formatted_text (m_pp);
+  va_end (ap);
+}
+
+/* Formatted print of FMT.  The text is indented by the current
+   indent, and a newline is added.  */
+
+void
+graphviz_out::println (const char *fmt, ...)
+{
+  text_info text;
+  va_list ap;
+
+  write_indent ();
+
+  va_start (ap, fmt);
+  text.err_no = errno;
+  text.args_ptr = 
+  text.format_spec = fmt;
+  pp_format (m_pp, );
+  pp_output_formatted_text (m_pp);
+  va_end (ap);
+
+  pp_newline (m_pp);
+}
+
+/* Print the current indent to the underlying pp.  */
+
+void
+graphviz_out::write_indent ()
+{
+  for (int i = 0; i < m_indent * 2; ++i)
+pp_space (m_pp);
+}
diff --git a/gcc/analyzer/graphviz.h b/gcc/analyzer/graphviz.h
new file mode 100644
index 000..d097834
--- /dev/null
+++ b/gcc/analyzer/graphviz.h
@@ -0,0 +1,50 @@
+/* Helper code for graphviz output.
+   Copyright (C) 2019 Free Software Foundation, Inc.
+   Contributed by David Malcolm .
+
+This file is part of GCC.
+
+GCC is free software; you can redistribute it and/or modify it
+under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 3, or (at your option)
+any later version.
+
+GCC is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GCC; see the file COPYING3.  If not see
+.  */
+
+#ifndef GCC_ANALYZER_GRAPHVIZ_H
+#define GCC_ANALYZER_GRAPHVIZ_H
+
+#include "pretty-print.h" /* for ATTRIBUTE_GCC_PPDIAG.  */
+
+/* A class for writing .dot output to a pretty_printer with
+   indentation to show nesting.  */
+
+class graphviz_out {
+ public:
+  graphviz_out (pretty_printer *pp);
+
+  void print (const char *fmt, ...)
+ATTRIBUTE_GCC_PPDIAG(2,3);
+  void println (const char *fmt, ...)
+ATTRIBUTE_GCC_PPDIAG(2,3);
+
+  void indent () { m_indent++; }
+  void outdent () { m_indent--; }
+
+  void write_indent ();
+
+  pretty_printer *get_pp () const { return m_pp; }
+
+ private:
+  pretty_printer *m_pp;
+  int m_indent;
+};
+
+#endif /* GCC_ANALYZER_GRAPHVIZ_H */
-- 
1.8.5.3



[PATCH 24/49] analyzer: new file: analyzer-pass.cc

2019-11-15 Thread David Malcolm
This patch adds the IPA pass boilerplate for the analyzer.

gcc/ChangeLog:
* analyzer/analyzer-pass.cc: New file.
---
 gcc/analyzer/analyzer-pass.cc | 103 ++
 1 file changed, 103 insertions(+)
 create mode 100644 gcc/analyzer/analyzer-pass.cc

diff --git a/gcc/analyzer/analyzer-pass.cc b/gcc/analyzer/analyzer-pass.cc
new file mode 100644
index 000..54b8a5c
--- /dev/null
+++ b/gcc/analyzer/analyzer-pass.cc
@@ -0,0 +1,103 @@
+/* Integration of the analyzer with GCC's pass manager.
+   Copyright (C) 2019 Free Software Foundation, Inc.
+   Contributed by David Malcolm .
+
+This file is part of GCC.
+
+GCC is free software; you can redistribute it and/or modify it
+under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 3, or (at your option)
+any later version.
+
+GCC is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GCC; see the file COPYING3.  If not see
+.  */
+
+#include "config.h"
+#include "gcc-plugin.h"
+#include "system.h"
+#include "coretypes.h"
+#include "context.h"
+#include "tree-pass.h"
+#include "analyzer/engine.h"
+
+namespace {
+
+/* Data for the analyzer pass.  */
+
+const pass_data pass_data_analyzer =
+{
+  IPA_PASS, /* type */
+  "analyzer", /* name */
+  OPTGROUP_NONE, /* optinfo_flags */
+  TV_NONE, /* tv_id */
+  PROP_ssa, /* properties_required */
+  0, /* properties_provided */
+  0, /* properties_destroyed */
+  0, /* todo_flags_start */
+  0, /* todo_flags_finish */
+};
+
+/* The analyzer pass.  */
+
+class pass_analyzer : public ipa_opt_pass_d
+{
+public:
+   pass_analyzer(gcc::context *ctxt)
+   : ipa_opt_pass_d (pass_data_analyzer, ctxt,
+NULL, /* generate_summary */
+NULL, /* write_summary */
+NULL, /* read_summary */
+NULL, /* write_optimization_summary */
+NULL, /* read_optimization_summary */
+NULL, /* stmt_fixup */
+0, /* function_transform_todo_flags_start */
+NULL, /* function_transform */
+NULL) /* variable_transform */
+  {}
+
+  /* opt_pass methods: */
+  unsigned int execute (function *) FINAL OVERRIDE;
+}; // class pass_analyzer
+
+/* Entrypoint for the analyzer pass.  */
+
+unsigned int
+pass_analyzer::execute (function *)
+{
+  run_checkers ();
+  return 0;
+}
+
+} // anon namespace
+
+/* Make an instance of the analyzer pass.  */
+
+static ipa_opt_pass_d *
+make_pass_analyzer (gcc::context *ctxt)
+{
+  return new pass_analyzer (ctxt);
+}
+
+/* Register the analyzer pass with GCC's pass manager.
+   Called by plugin_init.  */
+
+void
+register_analyzer_pass ()
+{
+  static struct register_pass_info pass_info;
+
+  /* IPA-LTO pass.  */
+  pass_info.pass = make_pass_analyzer (g);
+  pass_info.reference_pass_name = "whole-program";
+  pass_info.ref_pass_instance_number = 1;
+  pass_info.pos_op = PASS_POS_INSERT_BEFORE;
+
+  register_callback ("analyzer", PLUGIN_PASS_MANAGER_SETUP, NULL,
+_info);
+}
-- 
1.8.5.3



[PATCH 22/49] analyzer: params.def: new parameters

2019-11-15 Thread David Malcolm
gcc/ChangeLog:
* params.def (PARAM_ANALYZER_BB_EXPLOSION_FACTOR): New param.
(PARAM_ANALYZER_MAX_ENODES_PER_PROGRAM_POINT): New param.
(PARAM_ANALYZER_MAX_RECURSION_DEPTH): New param.
(PARAM_ANALYZER_MIN_SNODES_FOR_CALL_SUMMARY): New param.
---
 gcc/params.def | 25 +
 1 file changed, 25 insertions(+)

diff --git a/gcc/params.def b/gcc/params.def
index 4cb48d9..6715cf6 100644
--- a/gcc/params.def
+++ b/gcc/params.def
@@ -1487,6 +1487,31 @@ DEFPARAM(PARAM_SSA_NAME_DEF_CHAIN_LIMIT,
 "a value.",
 512, 0, 0)
 
+DEFPARAM(PARAM_ANALYZER_BB_EXPLOSION_FACTOR,
+"analyzer-bb-explosion-factor",
+"The maximum number of 'after supernode' exploded nodes within the "
+"analyzer per supernode, before terminating analysis.",
+5, 1, 0)
+
+DEFPARAM(PARAM_ANALYZER_MAX_ENODES_PER_PROGRAM_POINT,
+"analyzer-max-enodes-per-program-point",
+"The maximum number of exploded nodes per program point within the "
+"analyzer, before terminating analysis of that point.",
+8, 1, 0)
+
+DEFPARAM(PARAM_ANALYZER_MAX_RECURSION_DEPTH,
+"analyzer-max-recursion-depth",
+"The maximum number of times a callsite can appear in a call stack "
+" within the analyzer, before terminating analysis of a call that "
+" would recurse deeper.",
+2, 1, 0)
+
+DEFPARAM(PARAM_ANALYZER_MIN_SNODES_FOR_CALL_SUMMARY,
+"analyzer-min-snodes-for-call-summary",
+"The minimum number of supernodes within a function for the "
+"analyzer to consider summarizing its effects at call sites.",
+10, 1, 0)
+
 /*
 
 Local variables:
-- 
1.8.5.3



[PATCH 20/49] analyzer: new builtins

2019-11-15 Thread David Malcolm
gcc/ChangeLog:
* builtins.def (BUILT_IN_ANALYZER_BREAK): New builtin.
(BUILT_IN_ANALYZER_DUMP): New builtin.
(BUILT_IN_ANALYZER_DUMP_EXPLODED_NODES): New builtin.
(BUILT_IN_ANALYZER_DUMP_NUM_HEAP_REGIONS): New builtin.
(BUILT_IN_ANALYZER_DUMP_PATH): New builtin.
(BUILT_IN_ANALYZER_DUMP_REGION_MODEL): New builtin.
(BUILT_IN_ANALYZER_EVAL): New builtin.
---
 gcc/builtins.def | 33 +
 1 file changed, 33 insertions(+)

diff --git a/gcc/builtins.def b/gcc/builtins.def
index d8233f5..f34e95f 100644
--- a/gcc/builtins.def
+++ b/gcc/builtins.def
@@ -1107,4 +1107,37 @@ DEF_GCC_BUILTIN (BUILT_IN_LINE, "LINE", BT_FN_INT, 
ATTR_NOTHROW_LEAF_LIST)
 /* HSAIL/BRIG frontend builtins.  */
 #include "brig-builtins.def"
 
+
+/* Analyzer builtins.  */
+DEF_BUILTIN (BUILT_IN_ANALYZER_BREAK, "__analyzer_break",
+BUILT_IN_NORMAL, BT_FN_VOID, BT_LAST,
+false, false, false, ATTR_NULL, true, true)
+
+DEF_BUILTIN (BUILT_IN_ANALYZER_DUMP, "__analyzer_dump",
+BUILT_IN_NORMAL, BT_FN_VOID, BT_LAST,
+false, false, false, ATTR_NULL, true, true)
+
+DEF_BUILTIN (BUILT_IN_ANALYZER_DUMP_EXPLODED_NODES,
+"__analyzer_dump_exploded_nodes",
+BUILT_IN_NORMAL, BT_FN_VOID_INT, BT_LAST,
+false, false, false, ATTR_NULL, true, true)
+
+DEF_BUILTIN (BUILT_IN_ANALYZER_DUMP_NUM_HEAP_REGIONS,
+"__analyzer_dump_num_heap_regions",
+BUILT_IN_NORMAL, BT_FN_VOID, BT_LAST,
+false, false, false, ATTR_NULL, true, true)
+
+DEF_BUILTIN (BUILT_IN_ANALYZER_DUMP_PATH, "__analyzer_dump_path",
+BUILT_IN_NORMAL, BT_FN_VOID, BT_LAST,
+false, false, false, ATTR_NULL, true, true)
+
+DEF_BUILTIN (BUILT_IN_ANALYZER_DUMP_REGION_MODEL,
+"__analyzer_dump_region_model",
+BUILT_IN_NORMAL, BT_FN_VOID, BT_LAST,
+false, false, false, ATTR_NULL, true, true)
+
+DEF_BUILTIN (BUILT_IN_ANALYZER_EVAL, "__analyzer_eval",
+BUILT_IN_NORMAL, BT_FN_VOID_INT, BT_LAST,
+false, false, false, ATTR_NULL, true, true)
+
 #undef DEF_BUILTIN
-- 
1.8.5.3



[PATCH 21/49] analyzer: command-line options

2019-11-15 Thread David Malcolm
This patch contains the command-line options for the analyzer.

gcc/ChangeLog:
* analyzer/plugin.opt: New file.
* common.opt (--analyzer): New driver option.
---
 gcc/analyzer/plugin.opt | 161 
 gcc/common.opt  |   3 +
 2 files changed, 164 insertions(+)
 create mode 100644 gcc/analyzer/plugin.opt

diff --git a/gcc/analyzer/plugin.opt b/gcc/analyzer/plugin.opt
new file mode 100644
index 000..55f54bb
--- /dev/null
+++ b/gcc/analyzer/plugin.opt
@@ -0,0 +1,161 @@
+; plugin.opt -- Options for the analyzer.
+
+; Copyright (C) 2019 Free Software Foundation, Inc.
+;
+; This file is part of GCC.
+;
+; GCC is free software; you can redistribute it and/or modify it under
+; the terms of the GNU General Public License as published by the Free
+; Software Foundation; either version 3, or (at your option) any later
+; version.
+; 
+; GCC is distributed in the hope that it will be useful, but WITHOUT ANY
+; WARRANTY; without even the implied warranty of MERCHANTABILITY or
+; FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+; for more details.
+; 
+; You should have received a copy of the GNU General Public License
+; along with GCC; see the file COPYING3.  If not see
+; .
+
+; See the GCC internals manual for a description of this file's format.
+
+; Please try to keep this file in ASCII collating order.
+
+Wanalyzer-double-fclose
+Common Var(warn_analyzer_double_fclose) Init(1) Warning
+Warn about code paths in which a stdio FILE can be closed more than once.
+
+Wanalyzer-double-free
+Common Var(warn_analyzer_double_free) Init(1) Warning
+Warn about code paths in which a pointer can be freed more than once.
+
+Wanalyzer-exposure-through-output-file
+Common Var(warn_analyzer_exposure_through_output_file) Init(1) Warning
+Warn about code paths in which sensitive data is written to a file.
+
+Wanalyzer-file-leak
+Common Var(warn_analyzer_file_leak) Init(1) Warning
+Warn about code paths in which a stdio FILE is not closed.
+
+Wanalyzer-free-of-non-heap
+Common Var(warn_analyzer_free_of_non_heap) Init(1) Warning
+Warn about code paths in which a non-heap pointer is freed.
+
+Wanalyzer-malloc-leak
+Common Var(warn_analyzer_malloc_leak) Init(1) Warning
+Warn about code paths in which a heap-allocated pointer leaks.
+
+Wanalyzer-possible-null-argument
+Common Var(warn_analyzer_possible_null_argument) Init(1) Warning
+Warn about code paths in which a possibly-NULL value is passed to a 
must-not-be-NULL function argument.
+
+Wanalyzer-possible-null-dereference
+Common Var(warn_analyzer_possible_null_dereference) Init(1) Warning
+Warn about code paths in which a possibly-NULL pointer is dereferenced.
+
+Wanalyzer-null-argument
+Common Var(warn_analyzer_null_argument) Init(1) Warning
+Warn about code paths in which NULL is passed to a must-not-be-NULL function 
argument.
+
+Wanalyzer-null-dereference
+Common Var(warn_analyzer_null_dereference) Init(1) Warning
+Warn about code paths in which a NULL pointer is dereferenced.
+
+Wanalyzer-stale-setjmp-buffer
+Common Var(warn_analyzer_stale_setjmp_buffer) Init(1) Warning
+Warn about code paths in which a longjmp rewinds to a jmp_buf saved in a stack 
frame that has returned.
+
+Wanalyzer-tainted-array-index
+Common Var(warn_analyzer_tainted_array_index) Init(1) Warning
+Warn about code paths in which an unsanitized value is used as an array index.
+
+Wanalyzer-use-after-free
+Common Var(warn_analyzer_use_after_free) Init(1) Warning
+Warn about code paths in which a freed value is used.
+
+Wanalyzer-use-of-pointer-in-stale-stack-frame
+Common Var(warn_analyzer_use_of_pointer_in_stale_stack_frame) Init(1) Warning
+Warn about code paths in which a pointer to a stale stack frame is used.
+
+Wanalyzer-use-of-uninitialized-value
+Common Var(warn_analyzer_use_of_uninitialized_value) Init(1) Warning
+Warn about code paths in which an initialized value is used.
+
+Wanalyzer-too-complex
+Common Var(warn_analyzer_too_complex) Init(0) Warning
+Warn if the code is too complicated for the analyzer to fully explore.
+
+fanalyzer-checker=
+Common Joined RejectNegative Var(flag_analyzer_checker)
+Restrict the analyzer to run just the named checker.
+
+fanalyzer-fine-grained
+Common Var(flag_analyzer_fine_grained) Init(0)
+Avoid combining multiple statements into one exploded edge.
+
+fanalyzer-state-purge
+Common Var(flag_analyzer_state_purge) Init(1)
+Purge unneeded state during analysis.
+
+fanalyzer-state-merge
+Common Var(flag_analyzer_state_merge) Init(1)
+Merge similar-enough states during analysis.
+
+fanalyzer-transitivity
+Common Var(flag_analyzer_transitivity) Init(0)
+Enable transitivity of constraints during analysis.
+
+fanalyzer-call-summaries
+Common Var(flag_analyzer_call_summaries) Init(0)
+Approximate the effect of function calls to simplify analysis.
+
+fanalyzer-verbose-edges
+Common Var(flag_analyzer_verbose_edges) Init(0)
+Emit more verbose descriptions 

[PATCH 16/49] Add support for in-tree plugins

2019-11-15 Thread David Malcolm
This patch adds support for "in-tree" plugins i.e. GCC plugins that live
in the GCC source tree and are shipped as part of the GCC tarball.

The patch adds Makefile/configure machinery for handling in-tree GCC
plugins, adapted from how we support frontends.

Each in-tree plugin should provide a Make-plugin.in and config-plugin.in,
analogous to the Make-lang.in and config-lang.in provided by a frontend;
they can also supply options via a plugin.opt, analogous to a frontend's
lang.opt.

The patch adds a --enable-plugins=[LIST OF PLUGIN NAMES] configure option,
analogous to --enable-languages.  The default is for no such plugins to be
enabled.

ChangeLog:
* configure.ac: Handle --enable-plugins.

gcc/ChangeLog:
* Makefile.in (CONFIG_PLUGINS): New.
(SUBDIRS, subdirs): Generalize to cover plugins as well as
languages.
(plugin_opt_files): New.
(ALL_OPT_FILES): Add plugin_opt_files.
(ALL_HOST_PLUGIN_OBJS): New.
(ALL_HOST_OBJS): Add ALL_HOST_PLUGIN_OBJS.
(plugin_hooks): New.
(PLUGIN_MAKEFRAGS): New; include them.
(Makefile): Add dependency on PLUGIN_MAKEFRAGS.
(all.cross): Add dependency on plugin.all.cross.
(start.encap): Add plugin.start.encap.
(rest.encap): Add plugin.rest.encap.
(SELFTEST_TARGETS): Add selftest_plugins.
(info): Add dependency on lang.info.
(dvi): Add dependency on plugin.dvi.
(pdf): Add dependency on plugin.pdf.
(HTMLS_BUILD): Add plugin.html.
(man): Add plugin.man.
(mostlyclean): Add plugin.mostlyclean.
(clean): Add plugin.clean.
(distclean): Update for renaming of Make-hooks to Make-lang-hooks;
add Make-plugin-hooks.  Add plugin.distclean dependency.
(maintainer-clean): Add plugin.maintainer-clean.
(install-plugin): Add plugin.install-plugin.
(install-common): Add plugin.install-common.
(install-info): Add plugin.install-info.
(install-pdf): Add plugin.install-pdf.
(install-html): Add plugin.install-html.
(install-man): Add plugin.install-man.
(uninstall): Add plugin.uninstall.
(TAGS): Add plugin.tags.
* configure.ac (Make-hooks): Rename to Make-lang-hooks.
(plugin_opt_files): New.
(plugin_specs_files): New.
(plugin_tree_files): New.
(all_plugins): New.
(all_plugin_makefrags): New.
(all_selected_plugins): New.
(plugin_hooks): New.
("Plugin hooks"): New section.  Iterate through config-plugin.in,
analogously to config-lang.in.
(check_plugins): New.
(selftest_plugins): New.
(Make-plugin-hooks): Emit.
* doc/install.texi (--enable-plugins): New option.
---
 configure.ac |   6 ++
 gcc/Makefile.in  |  98 -
 gcc/configure.ac | 172 +--
 gcc/doc/install.texi |   9 +++
 4 files changed, 251 insertions(+), 34 deletions(-)

diff --git a/configure.ac b/configure.ac
index b8ce2ad..9b8b8ab 100644
--- a/configure.ac
+++ b/configure.ac
@@ -2188,6 +2188,12 @@ Supported languages are: ${potential_languages}])
   ac_configure_args=`echo " $ac_configure_args" | sed -e "s/ 
'--enable-languages=[[^ ]]*'//g" -e "s/$/ 
'--enable-languages="$enable_languages"'/" `
 fi
 
+# Look if the user specified --enable-plugins="..."
+if test -d ${srcdir}/gcc; then
+  enable_plugins=`echo "${enable_plugins}" | sed -e 's/[[  ,]][[   
,]]*/,/g' -e 's/,$//'`
+  ac_configure_args=`echo " $ac_configure_args" | sed -e "s/ 
'--enable-plugins=[[^ ]]*'//g" -e "s/$/ '--enable-plugins="$enable_plugins"'/" `
+fi
+
 # Handle --disable- generically.
 for dir in $configdirs $build_configdirs $target_configdirs ; do
   dirname=`echo $dir | sed -e s/target-//g -e s/build-//g -e s/-/_/g`
diff --git a/gcc/Makefile.in b/gcc/Makefile.in
index 5feef6a..c0dfbde 100644
--- a/gcc/Makefile.in
+++ b/gcc/Makefile.in
@@ -132,7 +132,7 @@ CROSS=@CROSS@
 # Variables that exist for you to override.
 # See below for how to change them for certain systems.
 
-# List of language subdirectories.
+# List of language and plugin subdirectories.
 SUBDIRS =@subdirs@ build
 
 # Selection of languages to be made.
@@ -142,6 +142,8 @@ ifeq (@enable_gcov@,yes)
 LANGUAGES += gcov$(exeext) gcov-dump$(exeext) gcov-tool$(exeext)
 endif
 
+CONFIG_PLUGINS = @all_selected_plugins@
+
 # Default values for variables overridden in Makefile fragments.
 # CFLAGS is for the user to override to, e.g., do a cross build with -O2.
 # TCFLAGS is used for compilations with the GCC just built.
@@ -570,6 +572,7 @@ lang_checks_parallelized=
 lang_opt_files=@lang_opt_files@ $(srcdir)/c-family/c.opt $(srcdir)/common.opt
 lang_specs_files=@lang_specs_files@
 lang_tree_files=@lang_tree_files@
+plugin_opt_files=@plugin_opt_files@
 target_cpu_default=@target_cpu_default@
 OBJC_BOEHM_GC=@objc_boehm_gc@
 extra_modes_file=@extra_modes_file@

[PATCH 19/49] analyzer: new files: analyzer-selftests.{cc|h}

2019-11-15 Thread David Malcolm
gcc/ChangeLog:
* analyzer/analyzer-selftests.cc: New file.
* analyzer/analyzer-selftests.h: New file.
---
 gcc/analyzer/analyzer-selftests.cc | 61 ++
 gcc/analyzer/analyzer-selftests.h  | 46 
 2 files changed, 107 insertions(+)
 create mode 100644 gcc/analyzer/analyzer-selftests.cc
 create mode 100644 gcc/analyzer/analyzer-selftests.h

diff --git a/gcc/analyzer/analyzer-selftests.cc 
b/gcc/analyzer/analyzer-selftests.cc
new file mode 100644
index 000..5696af5
--- /dev/null
+++ b/gcc/analyzer/analyzer-selftests.cc
@@ -0,0 +1,61 @@
+/* Selftest support for the analyzer.
+   Copyright (C) 2019 Free Software Foundation, Inc.
+   Contributed by David Malcolm .
+
+This file is part of GCC.
+
+GCC is free software; you can redistribute it and/or modify it
+under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 3, or (at your option)
+any later version.
+
+GCC is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GCC; see the file COPYING3.  If not see
+.  */
+
+#include "config.h"
+#include "gcc-plugin.h"
+#include "system.h"
+#include "coretypes.h"
+#include "tree.h"
+#include "stringpool.h"
+#include "analyzer/analyzer.h"
+#include "analyzer/analyzer-selftests.h"
+
+#if CHECKING_P
+
+namespace selftest {
+
+/* Build a VAR_DECL named NAME of type TYPE, simulating a file-level
+   static variable.  */
+
+tree
+build_global_decl (const char *name, tree type)
+{
+  tree decl = build_decl (UNKNOWN_LOCATION, VAR_DECL,
+ get_identifier (name), type);
+  TREE_STATIC (decl) = 1;
+  return decl;
+}
+
+/* Run all analyzer-specific selftests.  */
+
+void
+run_analyzer_selftests ()
+{
+  analyzer_constraint_manager_cc_tests ();
+  analyzer_digraph_cc_tests ();
+  analyzer_program_point_cc_tests ();
+  analyzer_program_state_cc_tests ();
+  analyzer_region_model_cc_tests ();
+  analyzer_tristate_cc_tests ();
+}
+
+} /* end of namespace selftest.  */
+
+#endif /* #if CHECKING_P */
diff --git a/gcc/analyzer/analyzer-selftests.h 
b/gcc/analyzer/analyzer-selftests.h
new file mode 100644
index 000..1c26f25
--- /dev/null
+++ b/gcc/analyzer/analyzer-selftests.h
@@ -0,0 +1,46 @@
+/* Selftests for the analyzer.
+   Copyright (C) 2019 Free Software Foundation, Inc.
+   Contributed by David Malcolm .
+
+This file is part of GCC.
+
+GCC is free software; you can redistribute it and/or modify it
+under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 3, or (at your option)
+any later version.
+
+GCC is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GCC; see the file COPYING3.  If not see
+.  */
+
+#ifndef GCC_ANALYZER_SELFTESTS_H
+#define GCC_ANALYZER_SELFTESTS_H
+
+#if CHECKING_P
+
+namespace selftest {
+
+extern tree build_global_decl (const char *name, tree type);
+
+extern void run_analyzer_selftests ();
+
+/* Declarations for specific families of tests (by source file), in
+   alphabetical order, for the checker plugin.  */
+extern void analyzer_checker_script_cc_tests ();
+extern void analyzer_constraint_manager_cc_tests ();
+extern void analyzer_digraph_cc_tests ();
+extern void analyzer_program_point_cc_tests ();
+extern void analyzer_program_state_cc_tests ();
+extern void analyzer_region_model_cc_tests ();
+extern void analyzer_tristate_cc_tests ();
+
+} /* end of namespace selftest.  */
+
+#endif /* #if CHECKING_P */
+
+#endif /* GCC_ANALYZER_SELFTESTS_H */
-- 
1.8.5.3



[PATCH 18/49] Add in-tree plugin: "analyzer"

2019-11-15 Thread David Malcolm
This patch supplies the {Make|config}-plugin.in files for the analyzer,
along with the entrypoint to the plugin, and the driver logic for
converting "--analyzer" into the option to inject the plugin.

gcc/ChangeLog:
* analyzer/Make-plugin.in: New file.
* analyzer/analyzer-plugin.cc: New file.
* analyzer/config-plugin.in: New file.
* gcc.c (driver_handle_option): Handle "--analyzer" by injecting
the plugin, if available.
---
 gcc/analyzer/Make-plugin.in | 181 
 gcc/analyzer/analyzer-plugin.cc |  63 ++
 gcc/analyzer/config-plugin.in   |  34 
 gcc/gcc.c   |  13 +++
 4 files changed, 291 insertions(+)
 create mode 100644 gcc/analyzer/Make-plugin.in
 create mode 100644 gcc/analyzer/analyzer-plugin.cc
 create mode 100644 gcc/analyzer/config-plugin.in

diff --git a/gcc/analyzer/Make-plugin.in b/gcc/analyzer/Make-plugin.in
new file mode 100644
index 000..08c96f1
--- /dev/null
+++ b/gcc/analyzer/Make-plugin.in
@@ -0,0 +1,181 @@
+# Top level -*- makefile -*- fragment for analyzer
+#   Copyright (C) 2013-2019 Free Software Foundation, Inc.
+
+#This file is part of GCC.
+
+#GCC is free software; you can redistribute it and/or modify
+#it under the terms of the GNU General Public License as published by
+#the Free Software Foundation; either version 3, or (at your option)
+#any later version.
+
+#GCC is distributed in the hope that it will be useful,
+#but WITHOUT ANY WARRANTY; without even the implied warranty of
+#MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+#GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with GCC; see the file COPYING3.  If not see
+# .
+
+# This file provides the plugin dependent support in the main Makefile.
+# Each plugin makefile fragment must provide the following targets:
+#
+# foo.all.cross, foo.start.encap, foo.rest.encap,
+# foo.install-common, foo.install-man, foo.install-info, foo.install-pdf,
+# foo.install-html, foo.info, foo.dvi, foo.pdf, foo.html, foo.uninstall,
+# foo.mostlyclean, foo.clean, foo.distclean,
+# foo.maintainer-clean, foo.stage1, foo.stage2, foo.stage3, foo.stage4
+#
+# where `foo' is the name of the plugin.
+#
+# It should also provide rules for:
+#
+# - making any compiler driver (eg: g++)
+# - the plugin proper (eg: analyzer_plugin.so)
+# - define the names for selecting the plugin in PLUGINS.
+
+#
+# Define the names for selecting analyzer in PLUGINS.
+# Note that it would be nice to move the dependency on g++
+# into the analyzer rule, but that needs a little bit of work
+# to do the right thing within all.cross.
+
+plugin_builddir = plugin
+
+ANALYZER_PLUGIN_SO = $(plugin_builddir)/analyzer_plugin.so
+
+analyzer: \
+   $(FULL_DRIVER_NAME) \
+   $(ANALYZER_PLUGIN_SO)
+
+# Tell GNU make to ignore these if they exist.
+.PHONY: analyzer
+
+# Files that are linked into analyzer plugin
+
+analyzer_OBJS = \
+   analyzer/analysis-plan.o \
+   analyzer/analyzer.o \
+   analyzer/analyzer-logging.o \
+   analyzer/analyzer-pass.o \
+   analyzer/analyzer-plugin.o \
+   analyzer/analyzer-selftests.o \
+   analyzer/call-string.o \
+   analyzer/checker-path.o \
+   analyzer/constraint-manager.o \
+   analyzer/diagnostic-manager.o \
+   analyzer/digraph.o \
+   analyzer/graphviz.o \
+   analyzer/engine.o \
+   analyzer/pending-diagnostic.o \
+   analyzer/program-point.o \
+   analyzer/program-state.o \
+   analyzer/region-model.o \
+   analyzer/sm.o \
+   analyzer/sm-file.o \
+   analyzer/sm-malloc.o \
+   analyzer/sm-pattern-test.o \
+   analyzer/sm-sensitive.o \
+   analyzer/sm-taint.o \
+   analyzer/state-purge.o \
+   analyzer/supergraph.o \
+   analyzer/tristate.o \
+
+# Use strict warnings for this plugin.
+analyzer-warn = $(STRICT_WARN)
+
+#
+# Build hooks:
+
+analyzer.all.cross:
+analyzer.start.encap:
+analyzer.rest.encap:
+
+$(plugin_builddir):
+   mkdir $@
+
+$(ANALYZER_PLUGIN_SO): $(analyzer_OBJS) $(plugin_builddir)
+   $(LINKER) $(ALL_LINKERFLAGS) $(LDFLAGS) \
+ -o $@ \
+ -shared \
+ $(analyzer_OBJS) \
+   -lpthread
+
+# If the analyzer is enabled, require the selftests to be run for it
+# at each stage of the build:
+selftest-analyzer: s-selftest-analyzer
+
+ANALYZER_SELFTEST_FLAGS = -xc $(SELFTEST_FLAGS) --analyzer
+ANALYZER_SELFTEST_DEPS = cc1$(exeext) $(SELFTEST_DEPS) $(ANALYZER_PLUGIN_SO)
+
+# Run the analyzer selftests:
+s-selftest-analyzer: $(ANALYZER_SELFTEST_DEPS)
+   $(GCC_FOR_TARGET) $(ANALYZER_SELFTEST_FLAGS)
+   $(STAMP) $@
+
+# Convenience methods for running analyzer selftests under gdb:
+.PHONY: selftest-analyzer-gdb
+selftest-analyzer-gdb: $(ANALYZER_SELFTEST_DEPS)
+   $(GCC_FOR_TARGET) $(ANALYZER_SELFTEST_FLAGS) \
+ -wrapper gdb,--args

[PATCH 15/49] Add ordered_hash_map

2019-11-15 Thread David Malcolm
This patch adds an ordered_hash_map template, which is similar to
hash_map, but preserves insertion order.

gcc/ChangeLog:
* Makefile.in (OBJS): Add ordered-hash-map-tests.o.
* ordered-hash-map-tests.cc: New file.
* ordered-hash-map.h: New file.
* selftest-run-tests.c (selftest::run_tests): Call
selftest::ordered_hash_map_tests_cc_tests.
* selftest.h (selftest::ordered_hash_map_tests_cc_tests): New
decl.
---
 gcc/Makefile.in   |   1 +
 gcc/ordered-hash-map-tests.cc | 247 ++
 gcc/ordered-hash-map.h| 184 +++
 gcc/selftest-run-tests.c  |   1 +
 gcc/selftest.h|   1 +
 5 files changed, 434 insertions(+)
 create mode 100644 gcc/ordered-hash-map-tests.cc
 create mode 100644 gcc/ordered-hash-map.h

diff --git a/gcc/Makefile.in b/gcc/Makefile.in
index c87b00f..5feef6a 100644
--- a/gcc/Makefile.in
+++ b/gcc/Makefile.in
@@ -1443,6 +1443,7 @@ OBJS = \
optinfo-emit-json.o \
options-save.o \
opts-global.o \
+   ordered-hash-map-tests.o \
passes.o \
plugin.o \
postreload-gcse.o \
diff --git a/gcc/ordered-hash-map-tests.cc b/gcc/ordered-hash-map-tests.cc
new file mode 100644
index 000..266f60c
--- /dev/null
+++ b/gcc/ordered-hash-map-tests.cc
@@ -0,0 +1,247 @@
+/* Unit tests for ordered-hash-map.h.
+   Copyright (C) 2015-2019 Free Software Foundation, Inc.
+
+This file is part of GCC.
+
+GCC is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free
+Software Foundation; either version 3, or (at your option) any later
+version.
+
+GCC is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received a copy of the GNU General Public License
+along with GCC; see the file COPYING3.  If not see
+.  */
+
+#include "config.h"
+#include "system.h"
+#include "coretypes.h"
+#include "tm.h"
+#include "opts.h"
+#include "hash-set.h"
+#include "fixed-value.h"
+#include "alias.h"
+#include "flags.h"
+#include "symtab.h"
+#include "tree-core.h"
+#include "stor-layout.h"
+#include "tree.h"
+#include "stringpool.h"
+#include "ordered-hash-map.h"
+#include "selftest.h"
+
+#if CHECKING_P
+
+namespace selftest {
+
+/* Populate *OUT_KVS with the key/value pairs of M.  */
+
+template 
+static void
+get_kv_pairs (const HashMap ,
+ auto_vec > *out_kvs)
+{
+  for (typename HashMap::iterator iter = m.begin ();
+   iter != m.end ();
+   ++iter)
+out_kvs->safe_push (std::make_pair ((*iter).first, (*iter).second));
+}
+
+/* Construct an ordered_hash_map  and verify that
+   various operations work correctly.  */
+
+static void
+test_map_of_strings_to_int ()
+{
+  ordered_hash_map  m;
+
+  const char *ostrich = "ostrich";
+  const char *elephant = "elephant";
+  const char *ant = "ant";
+  const char *spider = "spider";
+  const char *millipede = "Illacme plenipes";
+  const char *eric = "half a bee";
+
+  /* A fresh hash_map should be empty.  */
+  ASSERT_EQ (0, m.elements ());
+  ASSERT_EQ (NULL, m.get (ostrich));
+
+  /* Populate the hash_map.  */
+  ASSERT_EQ (false, m.put (ostrich, 2));
+  ASSERT_EQ (false, m.put (elephant, 4));
+  ASSERT_EQ (false, m.put (ant, 6));
+  ASSERT_EQ (false, m.put (spider, 8));
+  ASSERT_EQ (false, m.put (millipede, 750));
+  ASSERT_EQ (false, m.put (eric, 3));
+
+  /* Verify that we can recover the stored values.  */
+  ASSERT_EQ (6, m.elements ());
+  ASSERT_EQ (2, *m.get (ostrich));
+  ASSERT_EQ (4, *m.get (elephant));
+  ASSERT_EQ (6, *m.get (ant));
+  ASSERT_EQ (8, *m.get (spider));
+  ASSERT_EQ (750, *m.get (millipede));
+  ASSERT_EQ (3, *m.get (eric));
+
+  /* Verify that the order of insertion is preserved.  */
+  auto_vec > kvs;
+  get_kv_pairs (m, );
+  ASSERT_EQ (kvs.length (), 6);
+  ASSERT_EQ (kvs[0].first, ostrich);
+  ASSERT_EQ (kvs[0].second, 2);
+  ASSERT_EQ (kvs[1].first, elephant);
+  ASSERT_EQ (kvs[1].second, 4);
+  ASSERT_EQ (kvs[2].first, ant);
+  ASSERT_EQ (kvs[2].second, 6);
+  ASSERT_EQ (kvs[3].first, spider);
+  ASSERT_EQ (kvs[3].second, 8);
+  ASSERT_EQ (kvs[4].first, millipede);
+  ASSERT_EQ (kvs[4].second, 750);
+  ASSERT_EQ (kvs[5].first, eric);
+  ASSERT_EQ (kvs[5].second, 3);
+}
+
+/* Construct an ordered_hash_map using int_hash and verify that various
+   operations work correctly.  */
+
+static void
+test_map_of_int_to_strings ()
+{
+  const int EMPTY = -1;
+  const int DELETED = -2;
+  typedef int_hash  int_hash_t;
+  ordered_hash_map  m;
+
+  const char *ostrich = "ostrich";
+  const char *elephant = "elephant";
+  const char *ant = "ant";
+  const char *spider = "spider";
+  const char *millipede = "Illacme plenipes";
+  const char *eric = "half a bee";

[PATCH 17/49] Support for adding selftests via a plugin

2019-11-15 Thread David Malcolm
This patch provides a plugin callback for invoking selftests, so that a
plugin can add tests to those run by -fself-test=DIR.  The callback
invocation uses invoke_plugin_callbacks, which is a no-op if plugin
support is disabled.

gcc/ChangeLog:
* plugin.c (register_callback): Add case for PLUGIN_RUN_SELFTESTS.
(invoke_plugin_callbacks_full): Likewise.
* plugin.def (PLUGIN_RUN_SELFTESTS): New event.
* selftest-run-tests.c: Include "plugin.h".
(selftest::run_tests): Run any plugin-provided selftests.
---
 gcc/plugin.c | 2 ++
 gcc/plugin.def   | 3 +++
 gcc/selftest-run-tests.c | 4 
 3 files changed, 9 insertions(+)

diff --git a/gcc/plugin.c b/gcc/plugin.c
index a9d3171e..6a151af 100644
--- a/gcc/plugin.c
+++ b/gcc/plugin.c
@@ -497,6 +497,7 @@ register_callback (const char *plugin_name,
   case PLUGIN_EARLY_GIMPLE_PASSES_END:
   case PLUGIN_NEW_PASS:
   case PLUGIN_INCLUDE_FILE:
+  case PLUGIN_RUN_SELFTESTS:
 {
   struct callback_info *new_callback;
   if (!callback)
@@ -577,6 +578,7 @@ invoke_plugin_callbacks_full (int event, void *gcc_data)
   case PLUGIN_EARLY_GIMPLE_PASSES_END:
   case PLUGIN_NEW_PASS:
   case PLUGIN_INCLUDE_FILE:
+  case PLUGIN_RUN_SELFTESTS:
 {
   /* Iterate over every callback registered with this event and
  call it.  */
diff --git a/gcc/plugin.def b/gcc/plugin.def
index eb31f1a..e200728 100644
--- a/gcc/plugin.def
+++ b/gcc/plugin.def
@@ -99,6 +99,9 @@ DEFEVENT (PLUGIN_NEW_PASS)
as a const char* pointer.  */
 DEFEVENT (PLUGIN_INCLUDE_FILE)
 
+/* Called when running selftests.  */
+DEFEVENT (PLUGIN_RUN_SELFTESTS)
+
 /* When adding a new hard-coded plugin event, don't forget to edit in
file plugin.c the functions register_callback and
invoke_plugin_callbacks_full accordingly!  */
diff --git a/gcc/selftest-run-tests.c b/gcc/selftest-run-tests.c
index f41244b..d7fa69f 100644
--- a/gcc/selftest-run-tests.c
+++ b/gcc/selftest-run-tests.c
@@ -27,6 +27,7 @@ along with GCC; see the file COPYING3.  If not see
 #include "options.h"
 #include "stringpool.h"
 #include "attribs.h"
+#include "plugin.h"
 
 /* This function needed to be split out from selftest.c as it references
tests from the whole source tree, and so is within
@@ -114,6 +115,9 @@ selftest::run_tests ()
   /* Run any lang-specific selftests.  */
   lang_hooks.run_lang_selftests ();
 
+  /* Run any plugin-provided selftests.  */
+  invoke_plugin_callbacks (PLUGIN_RUN_SELFTESTS, NULL);
+
   /* Force a GC at the end of the selftests, to shake out GC-related
  issues.  For example, if any GC-managed items have buggy (or missing)
  finalizers, this last collection will ensure that things that were
-- 
1.8.5.3



[PATCH 09/49] gimple const-correctness fixes

2019-11-15 Thread David Malcolm
This patch converts various "gimple *" to "const gimple *" and similar
fixes for gimple subclasses, adding is_a_helper for gimple subclasses
to support the const form of as_a, and adding a few "const" overloads
of accessors.

This is enough to make pp_gimple_stmt_1's stmt const.

gcc/ChangeLog:
* gimple-predict.h (gimple_predict_predictor): Make "gs" param
const.
(gimple_predict_outcome): Likewise.
* gimple-pretty-print.c (do_niy): Likewise.
(dump_unary_rhs): Likewise.
(dump_binary_rhs): Likewise.
(dump_ternary_rhs): Likewise.
(dump_gimple_assign): Likewise.
(dump_gimple_return): Likewise.
(dump_gimple_call_args): Likewise.
(pp_points_to_solution): Make "pt" param const.
(dump_gimple_call): Make "gs" param const.
(dump_gimple_switch): Likewise.
(dump_gimple_cond): Likewise.
(dump_gimple_label): Likewise.
(dump_gimple_goto): Likewise.
(dump_gimple_bind): Likewise.
(dump_gimple_try): Likewise.
(dump_gimple_catch): Likewise.
(dump_gimple_eh_filter): Likewise.
(dump_gimple_eh_must_not_throw): Likewise.
(dump_gimple_eh_else): Likewise.
(dump_gimple_resx): Likewise.
(dump_gimple_eh_dispatch): Likewise.
(dump_gimple_debug): Likewise.
(dump_gimple_omp_for): Likewise.
(dump_gimple_omp_continue): Likewise.
(dump_gimple_omp_single): Likewise.
(dump_gimple_omp_taskgroup): Likewise.
(dump_gimple_omp_target): Likewise.
(dump_gimple_omp_teams): Likewise.
(dump_gimple_omp_sections): Likewise.
(dump_gimple_omp_block): Likewise.
(dump_gimple_omp_critical): Likewise.
(dump_gimple_omp_ordered): Likewise.
(dump_gimple_omp_scan): Likewise.
(dump_gimple_omp_return): Likewise.
(dump_gimple_transaction): Likewise.
(dump_gimple_asm): Likewise.
(dump_gimple_phi): Make "phi" param const.
(dump_gimple_omp_parallel): Make "gs" param const.
(dump_gimple_omp_task): Likewise.
(dump_gimple_omp_atomic_load): Likewise.
(dump_gimple_omp_atomic_store): Likewise.
(dump_gimple_mem_ops): Likewise.
(pp_gimple_stmt_1): Likewise.  Add "const" to the various as_a <>
casts throughout.
* gimple-pretty-print.h (gimple_stmt_1): Make gimple * param const.
* gimple.h (is_a_helper ::test): New.
(is_a_helper ::test): New.
(is_a_helper ::test): New.
(is_a_helper ::test): New.
(is_a_helper ::test): New.
(is_a_helper ::test): New.
(is_a_helper ::test): New.
(is_a_helper ::test): New.
(gimple_call_tail_p): Make param const.
(gimple_call_return_slot_opt_p): Likewise.
(gimple_call_va_arg_pack_p): Likewise.
(gimple_call_use_set): Add const overload.
(gimple_call_clobber_set): Likewise.
(gimple_has_lhs): Make param const.
(gimple_bind_body): Likewise.
(gimple_catch_handler): Likewise.
(gimple_eh_filter_failure): Likewise.
(gimple_eh_must_not_throw_fndecl): Likewise.
(gimple_eh_else_n_body): Likewise.
(gimple_eh_else_e_body): Likewise.
(gimple_try_eval): Likewise.
(gimple_try_cleanup): Likewise.
(gimple_phi_arg): Add const overload.
(gimple_phi_arg_def): Make param const.
(gimple_phi_arg_edge): Likewise.
(gimple_phi_arg_location): Likewise.
(gimple_phi_arg_has_location): Likewise.
(gimple_debug_bind_get_var): Likewise.
(gimple_debug_bind_get_value): Likewise.
(gimple_debug_source_bind_get_var): Likewise.
(gimple_debug_source_bind_get_value): Likewise.
(gimple_omp_body): Likewise.
(gimple_omp_for_collapse): Likewise.
(gimple_omp_for_pre_body): Likewise.
(gimple_transaction_body): Likewise.
* tree-eh.c (lookup_stmt_eh_lp_fn): Make param "t" const.
(lookup_stmt_eh_lp): Likewise.
* tree-eh.h (lookup_stmt_eh_lp_fn): Make param const.
(lookup_stmt_eh_lp): Likewise.
* tree-ssa-alias.h (pt_solution_empty_p): Make param const.
* tree-ssa-structalias.c (pt_solution_empty_p): Likewise.
---
 gcc/gimple-predict.h   |   4 +-
 gcc/gimple-pretty-print.c  | 159 +++--
 gcc/gimple-pretty-print.h  |   3 +-
 gcc/gimple.h   | 156 ++--
 gcc/tree-eh.c  |   6 +-
 gcc/tree-eh.h  |   4 +-
 gcc/tree-ssa-alias.h   |   2 +-
 gcc/tree-ssa-structalias.c |   2 +-
 8 files changed, 213 insertions(+), 123 deletions(-)

diff --git a/gcc/gimple-predict.h b/gcc/gimple-predict.h
index 761098b..d976317 100644
--- a/gcc/gimple-predict.h
+++ b/gcc/gimple-predict.h
@@ -26,7 +26,7 @@ along with GCC; see the file COPYING3.  If not see
 /* Return the predictor of GIMPLE_PREDICT statement GS. 

[PATCH 14/49] hash-map-tests.c: add a selftest involving int_hash

2019-11-15 Thread David Malcolm
gcc/ChangeLog:
* hash-map-tests.c (selftest::test_map_of_int_to_strings): New
selftest.
(selftest::hash_map_tests_c_tests): Call it.
---
 gcc/hash-map-tests.c | 41 +
 1 file changed, 41 insertions(+)

diff --git a/gcc/hash-map-tests.c b/gcc/hash-map-tests.c
index f3b216b..213a8da 100644
--- a/gcc/hash-map-tests.c
+++ b/gcc/hash-map-tests.c
@@ -103,6 +103,46 @@ test_map_of_strings_to_int ()
   ASSERT_EQ (1, string_map.elements ());
 }
 
+/* Construct a hash_map using int_hash and verify that
+   various operations work correctly.  */
+
+static void
+test_map_of_int_to_strings ()
+{
+  const int EMPTY = -1;
+  const int DELETED = -2;
+  typedef int_hash  int_hash_t;
+  hash_map  m;
+
+  const char *ostrich = "ostrich";
+  const char *elephant = "elephant";
+  const char *ant = "ant";
+  const char *spider = "spider";
+  const char *millipede = "Illacme plenipes";
+  const char *eric = "half a bee";
+
+  /* A fresh hash_map should be empty.  */
+  ASSERT_EQ (0, m.elements ());
+  ASSERT_EQ (NULL, m.get (2));
+
+  /* Populate the hash_map.  */
+  ASSERT_EQ (false, m.put (2, ostrich));
+  ASSERT_EQ (false, m.put (4, elephant));
+  ASSERT_EQ (false, m.put (6, ant));
+  ASSERT_EQ (false, m.put (8, spider));
+  ASSERT_EQ (false, m.put (750, millipede));
+  ASSERT_EQ (false, m.put (3, eric));
+
+  /* Verify that we can recover the stored values.  */
+  ASSERT_EQ (6, m.elements ());
+  ASSERT_EQ (*m.get (2), ostrich);
+  ASSERT_EQ (*m.get (4), elephant);
+  ASSERT_EQ (*m.get (6), ant);
+  ASSERT_EQ (*m.get (8), spider);
+  ASSERT_EQ (*m.get (750), millipede);
+  ASSERT_EQ (*m.get (3), eric);
+}
+
 typedef class hash_map_test_val_t
 {
 public:
@@ -243,6 +283,7 @@ void
 hash_map_tests_c_tests ()
 {
   test_map_of_strings_to_int ();
+  test_map_of_int_to_strings ();
   test_map_of_type_with_ctor_and_dtor ();
 }
 
-- 
1.8.5.3



[PATCH 11/49] Add diagnostic_metadata and CWE support

2019-11-15 Thread David Malcolm
This patch adds support for associating a diagnostic with an optional
diagnostic_metadata object, so that plugins can add extra data to their
diagnostics (e.g. mapping a diagnostic to a taxonomy or coding standard
such as from CERT or MISRA).

Currently this only supports associating a CWE identifier with a
diagnostic (which is what I'm using for the analyzer warnings later in
the patch kit), but adding a diagnostic_metadata class allows for future
growth in this area without an explosion of further "warning_at" overloads
for all of the different kinds of custom data that a plugin might want to
add.

gcc/ChangeLog:
* common.opt (fdiagnostics-show-metadata): New option.
* diagnostic-core.h (class diagnostic_metadata): New forward decl.
(warning_at): Add overload taking a const diagnostic_metadata &.
(emit_diagnostic_valist): Add overload taking a
const diagnostic_metadata *.
* diagnostic-format-json.cc: Include "diagnostic-metadata.h".
(json_from_metadata): New function.
(json_end_diagnostic): Call it to add "metadata" child for
diagnostics with metadata.
(diagnostic_output_format_init): Clear context->show_metadata.
* diagnostic-metadata.h: New file.
* diagnostic.c: Include "diagnostic-metadata.h".
(diagnostic_impl): Add const diagnostic_metadata * param.
(diagnostic_n_impl): Likewise.
(diagnostic_initialize): Initialize context->show_metadata.
(diagnostic_set_info_translated): Initialize diagnostic->metadata.
(get_cwe_url): New function.
(print_any_metadata): New function.
(diagnostic_report_diagnostic): Call print_any_metadata if the
diagnostic has non-NULL metadata.
(emit_diagnostic): Pass NULL as the metadata in the call to
diagnostic_impl.
(emit_diagnostic_valist): Likewise.
(emit_diagnostic_valist): New overload taking a
const diagnostic_metadata *.
(inform): Pass NULL as the metadata in the call to
diagnostic_impl.
(inform_n): Likewise for diagnostic_n_impl.
(warning): Likewise.
(warning_at): Likewise.  Add overload that takes a
const diagnostic_metadata &.
(warning_n): Pass NULL as the metadata in the call to
diagnostic_n_impl.
(pedwarn): Likewise for diagnostic_impl.
(permerror): Likewise.
(error): Likewise.
(error_n): Likewise.
(error_at): Likewise.
(sorry): Likewise.
(sorry_at): Likewise.
(fatal_error): Likewise.
(internal_error): Likewise.
(internal_error_no_backtrace): Likewise.
* diagnostic.h (diagnostic_info::metadata): New field.
(diagnostic_context::show_metadata): New field.
* doc/invoke.texi (-fno-diagnostics-show-metadata): New option.
* opts.c (common_handle_option): Handle
OPT_fdiagnostics_show_metadata.
* toplev.c (general_init): Initialize global_dc->show_metadata.
---
 gcc/common.opt|   4 ++
 gcc/diagnostic-core.h |  10 +++
 gcc/diagnostic-format-json.cc |  23 +++
 gcc/diagnostic-metadata.h |  42 +
 gcc/diagnostic.c  | 142 +-
 gcc/diagnostic.h  |   7 +++
 gcc/doc/invoke.texi   |   8 +++
 gcc/opts.c|   4 ++
 gcc/toplev.c  |   2 +
 9 files changed, 211 insertions(+), 31 deletions(-)
 create mode 100644 gcc/diagnostic-metadata.h

diff --git a/gcc/common.opt b/gcc/common.opt
index 3c024b3..228df32 100644
--- a/gcc/common.opt
+++ b/gcc/common.opt
@@ -1334,6 +1334,10 @@ fdiagnostics-show-option
 Common Var(flag_diagnostics_show_option) Init(1)
 Amend appropriate diagnostic messages with the command line option that 
controls them.
 
+fdiagnostics-show-metadata
+Common Var(flag_diagnostics_show_metadata) Init(1)
+Print additional metadata for diagnostic messages, where available.
+
 fdiagnostics-minimum-margin-width=
 Common Joined UInteger Var(diagnostics_minimum_margin_width) Init(6)
 Set minimum width of left margin of source code when showing source.
diff --git a/gcc/diagnostic-core.h b/gcc/diagnostic-core.h
index efafde4..2e7f120 100644
--- a/gcc/diagnostic-core.h
+++ b/gcc/diagnostic-core.h
@@ -45,6 +45,9 @@ class auto_diagnostic_group
   ~auto_diagnostic_group ();
 };
 
+/* Forward decl.  */
+class diagnostic_metadata; /* See diagnostic-metadata.h.  */
+
 extern const char *progname;
 
 extern const char *trim_filename (const char *);
@@ -78,6 +81,9 @@ extern bool warning_at (location_t, int, const char *, ...)
 ATTRIBUTE_GCC_DIAG(3,4);
 extern bool warning_at (rich_location *, int, const char *, ...)
 ATTRIBUTE_GCC_DIAG(3,4);
+extern bool warning_at (rich_location *, const diagnostic_metadata &, int,
+   const char *, ...)
+ATTRIBUTE_GCC_DIAG(4,5);
 extern void error (const char *, ...) ATTRIBUTE_GCC_DIAG(1,2);
 

[PATCH 08/49] Introduce pretty_printer::clone vfunc

2019-11-15 Thread David Malcolm
This patch provides a way to clone a pretty_printer.

This is needed so that we can capture text in a label_text and make
layout decisions based on it, using the policy of global_dc's printer,
whilst within a call to diagnostic_show_locus.  We can't print with
the pretty_printer itself within a call to diagnostic_show_locus since
it has partly-buffered content.

gcc/c-family/ChangeLog:
* c-pretty-print.c (c_pretty_printer::clone): New vfunc
implementation.
* c-pretty-print.h (c_pretty_printer::clone): New vfunc decl.

gcc/cp/ChangeLog:
* cxx-pretty-print.c (cxx_pretty_printer::clone): New vfunc
implementation.
* cxx-pretty-print.h (cxx_pretty_printer::clone): New vfunc decl.
* error.c (cxx_format_postprocessor::clone): New vfunc.

gcc/ChangeLog:
* pretty-print.c (pretty_printer::pretty_printer): New copy-ctor.
(pretty_printer::clone): New vfunc implementation.
* pretty-print.h (format_postprocessor::clone): New pure vfunc
decl.
(pretty_printer::pretty_printer): New copy-ctor decl.
(pretty_printer::clone): New vfunc decl.
---
 gcc/c-family/c-pretty-print.c |  7 +++
 gcc/c-family/c-pretty-print.h |  1 +
 gcc/cp/cxx-pretty-print.c |  8 
 gcc/cp/cxx-pretty-print.h |  2 ++
 gcc/cp/error.c|  5 +
 gcc/pretty-print.c| 34 ++
 gcc/pretty-print.h|  4 
 7 files changed, 61 insertions(+)

diff --git a/gcc/c-family/c-pretty-print.c b/gcc/c-family/c-pretty-print.c
index 1b06cc2..9f73d23 100644
--- a/gcc/c-family/c-pretty-print.c
+++ b/gcc/c-family/c-pretty-print.c
@@ -2368,6 +2368,13 @@ c_pretty_printer::c_pretty_printer ()
   parameter_list= pp_c_parameter_type_list;
 }
 
+/* c_pretty_printer's implementation of pretty_printer::clone vfunc.  */
+
+pretty_printer *
+c_pretty_printer::clone () const
+{
+  return new c_pretty_printer (*this);
+}
 
 /* Print the tree T in full, on file FILE.  */
 
diff --git a/gcc/c-family/c-pretty-print.h b/gcc/c-family/c-pretty-print.h
index 8d69620..df21e21 100644
--- a/gcc/c-family/c-pretty-print.h
+++ b/gcc/c-family/c-pretty-print.h
@@ -51,6 +51,7 @@ class c_pretty_printer : public pretty_printer
 {
 public:
   c_pretty_printer ();
+  pretty_printer *clone () const OVERRIDE;
 
   // Format string, possibly translated.
   void translate_string (const char *);
diff --git a/gcc/cp/cxx-pretty-print.c b/gcc/cp/cxx-pretty-print.c
index 2a129a3..d9d57be 100644
--- a/gcc/cp/cxx-pretty-print.c
+++ b/gcc/cp/cxx-pretty-print.c
@@ -3012,3 +3012,11 @@ cxx_pretty_printer::cxx_pretty_printer ()
   type_specifier_seq = (pp_fun) pp_cxx_type_specifier_seq;
   parameter_list = (pp_fun) pp_cxx_parameter_declaration_clause;
 }
+
+/* cxx_pretty_printer's implementation of pretty_printer::clone vfunc.  */
+
+pretty_printer *
+cxx_pretty_printer::clone () const
+{
+  return new cxx_pretty_printer (*this);
+}
diff --git a/gcc/cp/cxx-pretty-print.h b/gcc/cp/cxx-pretty-print.h
index 347811f..dd96226 100644
--- a/gcc/cp/cxx-pretty-print.h
+++ b/gcc/cp/cxx-pretty-print.h
@@ -34,6 +34,8 @@ class cxx_pretty_printer : public c_pretty_printer
 public:
   cxx_pretty_printer ();
 
+  pretty_printer *clone () const OVERRIDE;
+
   void constant (tree);
   void id_expression (tree);
   void primary_expression (tree);
diff --git a/gcc/cp/error.c b/gcc/cp/error.c
index f40b90d..bc8c9dc 100644
--- a/gcc/cp/error.c
+++ b/gcc/cp/error.c
@@ -143,6 +143,11 @@ class cxx_format_postprocessor : public 
format_postprocessor
   : m_type_a (), m_type_b ()
   {}
 
+  format_postprocessor *clone() const FINAL OVERRIDE
+  {
+return new cxx_format_postprocessor ();
+  }
+
   void handle (pretty_printer *pp) FINAL OVERRIDE;
 
   deferred_printed_type m_type_a;
diff --git a/gcc/pretty-print.c b/gcc/pretty-print.c
index c57a3db..89242ed 100644
--- a/gcc/pretty-print.c
+++ b/gcc/pretty-print.c
@@ -1588,6 +1588,32 @@ pretty_printer::pretty_printer (int maximum_length)
   pp_set_prefix (this, NULL);
 }
 
+/* Copy constructor for pretty_printer.  */
+
+pretty_printer::pretty_printer (const pretty_printer )
+: buffer (new (XCNEW (output_buffer)) output_buffer ()),
+  prefix (),
+  padding (other.padding),
+  maximum_length (other.maximum_length),
+  indent_skip (other.indent_skip),
+  wrapping (other.wrapping),
+  format_decoder (other.format_decoder),
+  m_format_postprocessor (NULL),
+  emitted_prefix (other.emitted_prefix),
+  need_newline (other.need_newline),
+  translate_identifiers (other.translate_identifiers),
+  show_color (other.show_color),
+  show_urls (other.show_urls)
+{
+  pp_line_cutoff (this) = maximum_length;
+  /* By default, we emit prefixes once per message.  */
+  pp_prefixing_rule (this) = pp_prefixing_rule ();
+  pp_set_prefix (this, NULL);
+
+  if (other.m_format_postprocessor)
+m_format_postprocessor = other.m_format_postprocessor->clone ();
+}
+
 pretty_printer::~pretty_printer ()
 {
   if 

[PATCH 13/49] function-tests.c: expose selftest::make_fndecl for use elsewhere

2019-11-15 Thread David Malcolm
This is used by new selftests later on in the patch kit.

gcc/ChangeLog:
* function-tests.c (selftest::make_fndecl): Make non-static.
* selftest.h (selftest::make_fndecl): New decl.
---
 gcc/function-tests.c | 4 ++--
 gcc/selftest.h   | 7 +++
 2 files changed, 9 insertions(+), 2 deletions(-)

diff --git a/gcc/function-tests.c b/gcc/function-tests.c
index 2440dd6..f3406c4 100644
--- a/gcc/function-tests.c
+++ b/gcc/function-tests.c
@@ -82,11 +82,11 @@ namespace selftest {
 
 /* Helper function for selftests of function-creation.  */
 
-static tree
+tree
 make_fndecl (tree return_type,
 const char *name,
 vec  _types,
-bool is_variadic = false)
+bool is_variadic)
 {
   tree fn_type;
   if (is_variadic)
diff --git a/gcc/selftest.h b/gcc/selftest.h
index 165dfff..c67b688 100644
--- a/gcc/selftest.h
+++ b/gcc/selftest.h
@@ -171,6 +171,13 @@ class line_table_test
   ~line_table_test ();
 };
 
+/* Helper function for selftests that need a function decl.  */
+
+extern tree make_fndecl (tree return_type,
+const char *name,
+vec  _types,
+bool is_variadic = false);
+
 /* Run TESTCASE multiple times, once for each case in our test matrix.  */
 
 extern void
-- 
1.8.5.3



[PATCH 07/49] Replace label_text ctor with "borrow" and "take"

2019-11-15 Thread David Malcolm
libcpp's label_text class wraps a text buffer, along with a flag to
determine if it "owns" the buffer.

The existing ctor exposed this directly, but I found it difficult
to remember the sense of flag, so this patch hides the ctor, in
favor of static member functions "borrow" and "take", to make
the effect on ownership explicit in the name.

gcc/c-family/ChangeLog:
* c-format.c (range_label_for_format_type_mismatch::get_text):
Replace label_text ctor called with true with label_text::take.

gcc/c/ChangeLog:
* c-objc-common.c (range_label_for_type_mismatch::get_text):
Replace label_text ctor calls.

gcc/cp/ChangeLog:
* error.c (range_label_for_type_mismatch::get_text): Replace
label_text ctor calls with label_text::borrow.

gcc/ChangeLog:
* gcc-rich-location.c
(maybe_range_label_for_tree_type_mismatch::get_text): Replace
label_text ctor call with label_text::borrow.
* gcc-rich-location.h (text_range_label::get_text): Replace
label_text ctor called with false with label_text::borrow.

libcpp/ChangeLog:
* include/line-map.h (label_text::label_text): Make private.
(label_text::borrow): New.
(label_text::take): New.
(label_text::take_or_copy): New.
---
 gcc/c-family/c-format.c   |  2 +-
 gcc/c/c-objc-common.c |  4 ++--
 gcc/cp/error.c|  4 ++--
 gcc/gcc-rich-location.c   |  2 +-
 gcc/gcc-rich-location.h   |  2 +-
 libcpp/include/line-map.h | 31 +++
 6 files changed, 34 insertions(+), 11 deletions(-)

diff --git a/gcc/c-family/c-format.c b/gcc/c-family/c-format.c
index 7ddf064..84475db 100644
--- a/gcc/c-family/c-format.c
+++ b/gcc/c-family/c-format.c
@@ -4629,7 +4629,7 @@ class range_label_for_format_type_mismatch
 
 char *result = concat (text.m_buffer, p, NULL);
 text.maybe_free ();
-return label_text (result, true);
+return label_text::take (result);
   }
 
  private:
diff --git a/gcc/c/c-objc-common.c b/gcc/c/c-objc-common.c
index 10d72c5..665c7a6 100644
--- a/gcc/c/c-objc-common.c
+++ b/gcc/c/c-objc-common.c
@@ -340,12 +340,12 @@ label_text
 range_label_for_type_mismatch::get_text (unsigned /*range_idx*/) const
 {
   if (m_labelled_type == NULL_TREE)
-return label_text (NULL, false);
+return label_text::borrow (NULL);
 
   c_pretty_printer cpp;
   bool quoted = false;
   print_type (, m_labelled_type, );
-  return label_text (xstrdup (pp_formatted_text ()), true);
+  return label_text::take (xstrdup (pp_formatted_text ()));
 }
 
 
diff --git a/gcc/cp/error.c b/gcc/cp/error.c
index 1fd87d2..f40b90d 100644
--- a/gcc/cp/error.c
+++ b/gcc/cp/error.c
@@ -4521,7 +4521,7 @@ label_text
 range_label_for_type_mismatch::get_text (unsigned /*range_idx*/) const
 {
   if (m_labelled_type == NULL_TREE)
-return label_text (NULL, false);
+return label_text::borrow (NULL);
 
   const bool verbose = false;
   const bool show_color = false;
@@ -4536,5 +4536,5 @@ range_label_for_type_mismatch::get_text (unsigned 
/*range_idx*/) const
 
   /* Both of the above return GC-allocated buffers, so the caller mustn't
  free them.  */
-  return label_text (const_cast  (result), false);
+  return label_text::borrow (result);
 }
diff --git a/gcc/gcc-rich-location.c b/gcc/gcc-rich-location.c
index 82d4f52..071463e 100644
--- a/gcc/gcc-rich-location.c
+++ b/gcc/gcc-rich-location.c
@@ -196,7 +196,7 @@ maybe_range_label_for_tree_type_mismatch::get_text 
(unsigned range_idx) const
 {
   if (m_expr == NULL_TREE
   || !EXPR_P (m_expr))
-return label_text (NULL, false);
+return label_text::borrow (NULL);
   tree expr_type = TREE_TYPE (m_expr);
 
   tree other_type = NULL_TREE;
diff --git a/gcc/gcc-rich-location.h b/gcc/gcc-rich-location.h
index 3bee2e8..71f4f3d 100644
--- a/gcc/gcc-rich-location.h
+++ b/gcc/gcc-rich-location.h
@@ -111,7 +111,7 @@ class text_range_label : public range_label
 
   label_text get_text (unsigned /*range_idx*/) const FINAL OVERRIDE
   {
-return label_text (const_cast  (m_text), false);
+return label_text::borrow (m_text);
   }
 
  private:
diff --git a/libcpp/include/line-map.h b/libcpp/include/line-map.h
index bde5e53..e4c7952 100644
--- a/libcpp/include/line-map.h
+++ b/libcpp/include/line-map.h
@@ -1791,18 +1791,41 @@ public:
   : m_buffer (NULL), m_caller_owned (false)
   {}
 
-  label_text (char *buffer, bool caller_owned)
-  : m_buffer (buffer), m_caller_owned (caller_owned)
-  {}
-
   void maybe_free ()
   {
 if (m_caller_owned)
   free (m_buffer);
   }
 
+  /* Create a label_text instance that borrows BUFFER from a
+ longer-lived owner.  */
+  static label_text borrow (const char *buffer)
+  {
+return label_text (const_cast  (buffer), false);
+  }
+
+  /* Create a label_text instance that takes ownership of BUFFER.  */
+  static label_text take (char *buffer)
+  {
+return label_text (buffer, true);
+  }
+
+  /* Take ownership of the buffer, copying if necessary.  */
+  char 

[PATCH 02/49] analyzer: internal documentation

2019-11-15 Thread David Malcolm
gcc/ChangeLog:
* Makefile.in (TEXI_GCCINT_FILES): Add analyzer.texi.
* doc/analyzer.texi: New file.
* doc/gccint.texi ("Static Analyzer") New menu item.
(analyzer.texi): Include it.
---
 gcc/Makefile.in   |   2 +-
 gcc/doc/analyzer.texi | 470 ++
 gcc/doc/gccint.texi   |   2 +
 3 files changed, 473 insertions(+), 1 deletion(-)
 create mode 100644 gcc/doc/analyzer.texi

diff --git a/gcc/Makefile.in b/gcc/Makefile.in
index c82858f..53d74e2 100644
--- a/gcc/Makefile.in
+++ b/gcc/Makefile.in
@@ -3182,7 +3182,7 @@ TEXI_GCCINT_FILES = gccint.texi gcc-common.texi 
gcc-vers.texi \
 gnu.texi gpl_v3.texi fdl.texi contrib.texi languages.texi  \
 sourcebuild.texi gty.texi libgcc.texi cfg.texi tree-ssa.texi   \
 loop.texi generic.texi gimple.texi plugins.texi optinfo.texi   \
-match-and-simplify.texi ux.texi poly-int.texi
+match-and-simplify.texi analyzer.texi ux.texi poly-int.texi
 
 TEXI_GCCINSTALL_FILES = install.texi install-old.texi fdl.texi \
 gcc-common.texi gcc-vers.texi
diff --git a/gcc/doc/analyzer.texi b/gcc/doc/analyzer.texi
new file mode 100644
index 000..8e7b26f
--- /dev/null
+++ b/gcc/doc/analyzer.texi
@@ -0,0 +1,470 @@
+@c Copyright (C) 2019 Free Software Foundation, Inc.
+@c This is part of the GCC manual.
+@c For copying conditions, see the file gcc.texi.
+@c Contributed by David Malcolm .
+
+@node Static Analyzer
+@chapter Static Analyzer
+@cindex analyzer
+@cindex static analysis
+@cindex static analyzer
+
+@menu
+* Analyzer Internals::   Analyzer Internals
+* Debugging the Analyzer::   Useful debugging tips
+@end menu
+
+@node Analyzer Internals
+@section Analyzer Internals
+@cindex analyzer, internals
+@cindex static analyzer, internals
+
+@subsection Overview
+
+The analyzer implementation works on the gimple-SSA representation.
+(I chose this in the hopes of making it easy to work with LTO to
+do whole-program analysis).
+
+The implementation is read-only: it doesn't attempt to change anything,
+just emit warnings.
+
+First, we build a @code{supergraph} which combines the callgraph and all
+of the CFGs into a single directed graph, with both interprocedural and
+intraprocedural edges.  The nodes and edges in the supergraph are called
+``supernodes'' and ``superedges'', and often referred to in code as
+@code{snodes} and @code{sedges}.  Basic blocks in the CFGs are split at
+interprocedural calls, so there can be more than one supernode per
+basic block.  Most statements will be in just one supernode, but a call
+statement can appear in two supernodes: at the end of one for the call,
+and again at the start of another for the return.
+
+The supergraph can be seen using @option{-fdump-analyzer-supergraph}.
+
+We then build an @code{analysis_plan} which walks the callgraph to
+determine which calls might be suitable for being summarized (rather
+than fully explored) and thus in what order to explore the functions.
+
+Next is the heart of the analyzer: we use a worklist to explore state
+within the supergraph, building an "exploded graph".
+Nodes in the exploded graph correspond to  pairs, as in
+ "Precise Interprocedural Dataflow Analysis via Graph Reachability"
+ (Thomas Reps, Susan Horwitz and Mooly Sagiv).
+
+We reuse nodes for  pairs we've already seen, and avoid
+tracking state too closely, so that (hopefully) we rapidly converge
+on a final exploded graph, and terminate the analysis.  We also bail
+out if the number of exploded  nodes gets
+larger than a particular multiple of the total number of basic blocks
+(to ensure termination in the face of pathological state-explosion
+cases, or bugs).  We also stop exploring a point once we hit a limit
+of states for that point.
+
+We can identify problems directly when processing a 
+instance.  For example, if we're finding the successors of
+
+@smallexample
+   
+@end smallexample
+
+then we can detect a double-free of "ptr".  We can then emit a path
+to reach the problem by finding the simplest route through the graph.
+
+Program points in the analysis are much more fine-grained than in the
+CFG and supergraph, with points (and thus potentially exploded nodes)
+for various events, including before individual statements.
+By default the exploded graph merges multiple consecutive statements
+in a supernode into one exploded edge to minimize the size of the
+exploded graph.  This can be suppressed via
+@option{-fanalyzer-fine-grained}.
+The fine-grained approach seems to make things simpler and more debuggable
+that other approaches I tried, in that each point is responsible for one
+thing.
+
+Program points in the analysis also have a "call string" identifying the
+stack of callsites below them, so that paths in the exploded graph
+correspond to interprocedurally valid paths: we always return to the
+correct call site, propagating state information accordingly.
+We avoid infinite 

[PATCH 10/49] Add -fdiagnostics-nn-line-numbers

2019-11-15 Thread David Malcolm
This patch implements -fdiagnostics-nn-line-numbers, a new option
which makes diagnostic_show_locus print "NN" rather than specific
line numbers when printing the left margin.

This is intended purely to make it easier to write certain kinds of
DejaGnu test; various integration tests for diagnostic paths later
in the patch kit make use of it.

gcc/ChangeLog:
* common.opt (fdiagnostics-nn-line-numbers): New option.
* diagnostic-show-locus.c (layout::m_use_nn_for_line_numbers_p):
New field.
(layout::layout): Initialize it and use it when computing
m_linenum_width.
(layout::print_source_line): Implement printing "NN" rather than
the line number.
(selftest::test_line_numbers_multiline_range): Add a test of "NN"
printing.
* diagnostic.c (diagnostic_initialize): Initialize
use_nn_for_line_numbers_p.
(num_digits): Add "use_nn_p" param.
(selftest::test_num_digits): Add a test for use_nn_p==true.
* diagnostic.h (diagnostic_context::use_nn_for_line_numbers_p):
New field.
(num_digits): Add optional "use_nn_p" param.
* doc/invoke.texi (-fdiagnostics-nn-line-numbers): New option.
* dwarf2out.c (gen_producer_string): Ignore
OPT_fdiagnostics_nn_line_numbers.
* lto-wrapper.c (merge_and_complain): Handle
OPT_fdiagnostics_nn_line_numbers.
(append_compiler_options): Likewise.
(append_diag_options): Likewise.
* opts.c (common_handle_option): Likewise.
* toplev.c (general_init): Initialize
global_dc->use_nn_for_line_numbers_p.
---
 gcc/common.opt  |  4 
 gcc/diagnostic-show-locus.c | 51 -
 gcc/diagnostic.c| 13 ++--
 gcc/diagnostic.h|  6 +-
 gcc/doc/invoke.texi |  7 +++
 gcc/dwarf2out.c |  1 +
 gcc/lto-wrapper.c   |  3 +++
 gcc/opts.c  |  4 
 gcc/toplev.c|  2 ++
 9 files changed, 73 insertions(+), 18 deletions(-)

diff --git a/gcc/common.opt b/gcc/common.opt
index 124e8cf..3c024b3 100644
--- a/gcc/common.opt
+++ b/gcc/common.opt
@@ -1257,6 +1257,10 @@ fdiagnostics-show-line-numbers
 Common Var(flag_diagnostics_show_line_numbers) Init(1)
 Show line numbers in the left margin when showing source.
 
+fdiagnostics-nn-line-numbers
+Common Var(flag_diagnostics_nn_line_numbers) Init(0)
+Replace line numbers with 'NN' when showing source.
+
 fdiagnostics-color
 Common Alias(fdiagnostics-color=,always,never)
 ;
diff --git a/gcc/diagnostic-show-locus.c b/gcc/diagnostic-show-locus.c
index 412b0d4..ec5fdc0 100644
--- a/gcc/diagnostic-show-locus.c
+++ b/gcc/diagnostic-show-locus.c
@@ -303,6 +303,7 @@ class layout
   bool m_colorize_source_p;
   bool m_show_labels_p;
   bool m_show_line_numbers_p;
+  bool m_use_nn_for_line_numbers_p;
   auto_vec  m_layout_ranges;
   auto_vec  m_fixit_hints;
   auto_vec  m_line_spans;
@@ -849,6 +850,7 @@ layout::layout (diagnostic_context * context,
   m_colorize_source_p (context->colorize_source_p),
   m_show_labels_p (context->show_labels_p),
   m_show_line_numbers_p (context->show_line_numbers_p),
+  m_use_nn_for_line_numbers_p (context->use_nn_for_line_numbers_p),
   m_layout_ranges (richloc->get_num_locations ()),
   m_fixit_hints (richloc->get_num_fixit_hints ()),
   m_line_spans (1 + richloc->get_num_locations ()),
@@ -884,7 +886,7 @@ layout::layout (diagnostic_context * context,
   int highest_line = last_span->m_last_line;
   if (highest_line < 0)
 highest_line = 0;
-  m_linenum_width = num_digits (highest_line);
+  m_linenum_width = num_digits (highest_line, m_use_nn_for_line_numbers_p);
   /* If we're showing jumps in the line-numbering, allow at least 3 chars.  */
   if (m_line_spans.length () > 1)
 m_linenum_width = MAX (m_linenum_width, 3);
@@ -1272,10 +1274,13 @@ layout::print_source_line (linenum_type row, const char 
*line, int line_width,
 
   if (m_show_line_numbers_p)
 {
-  int width = num_digits (row);
+  int width = num_digits (row, m_use_nn_for_line_numbers_p);
   for (int i = 0; i < m_linenum_width - width; i++)
pp_space (m_pp);
-  pp_printf (m_pp, "%i | ", row);
+  if (m_use_nn_for_line_numbers_p)
+   pp_printf (m_pp, "%s | ", "NN");
+  else
+   pp_printf (m_pp, "%i | ", row);
 }
   else
 pp_space (m_pp);
@@ -3778,18 +3783,34 @@ test_line_numbers_multiline_range ()
 = linemap_position_for_line_and_column (line_table, ord_map, 11, 4);
   location_t loc = make_location (caret, start, finish);
 
-  test_diagnostic_context dc;
-  dc.show_line_numbers_p = true;
-  dc.min_margin_width = 0;
-  gcc_rich_location richloc (loc);
-  diagnostic_show_locus (, , DK_ERROR);
-  ASSERT_STREQ (" 9 | this is line 9\n"
-   "   | ~~\n"
-   "10 | this is line 10\n"
-   "   | ~^~\n"
-   "11 | this is line 

[PATCH 00/49] RFC: Add a static analysis framework to GCC

2019-11-15 Thread David Malcolm
This patch kit introduces a static analysis pass for GCC that can diagnose
various kinds of problems in C code at compile-time (e.g. double-free,
use-after-free, etc).

The analyzer runs as an IPA pass on the gimple SSA representation.
It associates state machines with data, with transitions at certain
statements and edges.  It finds "interesting" interprocedural paths
through the user's code, in which bogus state transitions happen.

For example, given:

   free (ptr);
   free (ptr);

at the first call, "ptr" transitions to the "freed" state, and
at the second call the analyzer complains, since "ptr" is already in
the "freed" state (unless "ptr" is NULL, in which case it stays in
the NULL state for both calls).

Specific state machines include:
- a checker for malloc/free, for detecting double-free, resource leaks,
  use-after-free, etc (sm-malloc.cc), and
- a checker for stdio's FILE stream API (sm-file.cc)

There are also two state-machine-based checkers that are just
proof-of-concept at this stage:
- a checker for tracking exposure of sensitive data (e.g.
  writing passwords to log files aka CWE-532), and
- a checker for tracking "taint", where data potentially under an
  attacker's control is used without sanitization for things like
  array indices (CWE-129).

There's a separation between the state machines and the analysis
engine, so it ought to be relatively easy to add new warnings.

For any given diagnostic emitted by a state machine, the analysis engine
generates the simplest feasible interprocedural path of control flow for
triggering the diagnostic.


Diagnostic paths


The patch kit adds support to GCC's diagnostic subsystem for optionally
associating a "diagnostic_path" with a diagnostic.  A diagnostic path
describes a sequence of events predicted by the compiler that leads to the
problem occurring, with their locations in the user's source, and text
descriptions.

For example, the following warning has a 6-event interprocedural path:

malloc-ipa-8-unchecked.c: In function 'make_boxed_int':
malloc-ipa-8-unchecked.c:21:13: warning: dereference of possibly-NULL 'result' 
[CWE-690] [-Wanalyzer-possible-null-dereference]
   21 |   result->i = i;
  |   ~~^~~
  'make_boxed_int': events 1-2
|
|   18 | make_boxed_int (int i)
|  | ^~
|  | |
|  | (1) entry to 'make_boxed_int'
|   19 | {
|   20 |   boxed_int *result = (boxed_int *)wrapped_malloc (sizeof 
(boxed_int));
|  |
~~~
|  ||
|  |(2) calling 'wrapped_malloc' 
from 'make_boxed_int'
|
+--> 'wrapped_malloc': events 3-4
   |
   |7 | void *wrapped_malloc (size_t size)
   |  |   ^~
   |  |   |
   |  |   (3) entry to 'wrapped_malloc'
   |8 | {
   |9 |   return malloc (size);
   |  |  ~
   |  |  |
   |  |  (4) this call could return NULL
   |
<--+
|
  'make_boxed_int': events 5-6
|
|   20 |   boxed_int *result = (boxed_int *)wrapped_malloc (sizeof 
(boxed_int));
|  |
^~~
|  ||
|  |(5) possible return of NULL to 
'make_boxed_int' from 'wrapped_malloc'
|   21 |   result->i = i;
|  |   ~
|  | |
|  | (6) 'result' could be NULL: unchecked value from (4)
|

The diagnostic-printing code has consolidated the path into 3 runs of events
(where the events are near each other and within the same function), using
ASCII art to show the interprocedural call and return.

A colorized version of the above can be seen at:
  https://dmalcolm.fedorapeople.org/gcc/2019-11-13/test.html

Other examples can be seen at:
  https://dmalcolm.fedorapeople.org/gcc/2019-11-13/malloc-1.c.html
  https://dmalcolm.fedorapeople.org/gcc/2019-11-13/setjmp-4.c.html

An example of detecting a historical double-free CVE can be seen at:
  https://dmalcolm.fedorapeople.org/gcc/2019-11-13/CVE-2005-1689.html
(there are also some false positives in this report)


Diagnostic metadata
===

The patch kit also adds the ability to associate additional metadata with
a diagnostic. The only such metadata added by the patch kit are CWE
classifications (for the new warnings), such as the CWE-690 in the warning
above, or CWE-401 in this example:

malloc-1.c: In function 'test_42a':
malloc-1.c:466:1: warning: leak of 'p' [CWE-401] [-Wanalyzer-malloc-leak]
  466 | }
  | ^
  'test_42a': events 1-2
   |
   |  463 |   void *p = malloc (1024);
   |  | ^
   |  | 

[PATCH 06/49] timevar.h: add auto_client_timevar class

2019-11-15 Thread David Malcolm
This patch adds a class "auto_client_timevar", similar to auto_timevar,
but for plugins to use on their own timing items that aren't in
timevar.def

gcc/ChangeLog:
* timevar.h (class auto_client_timevar): New class.
---
 gcc/timevar.h | 33 +
 1 file changed, 33 insertions(+)

diff --git a/gcc/timevar.h b/gcc/timevar.h
index ef404d0..d053ab7 100644
--- a/gcc/timevar.h
+++ b/gcc/timevar.h
@@ -256,6 +256,39 @@ class auto_timevar
   timevar_id_t m_tv;
 };
 
+/* An RAII class analogous to auto_timevar, but for a client item,
+   for use by plugins.  */
+
+class auto_client_timevar
+{
+ public:
+  auto_client_timevar (timer *t, const char *item_name)
+: m_timer (t)
+  {
+if (m_timer)
+  m_timer->push_client_item (item_name);
+  }
+
+  explicit auto_client_timevar (const char *item_name)
+: m_timer (g_timer)
+  {
+if (m_timer)
+  m_timer->push_client_item (item_name);
+  }
+
+  ~auto_client_timevar ()
+  {
+if (m_timer)
+  m_timer->pop_client_item ();
+  }
+
+ private:
+  // Private to disallow copies.
+  auto_client_timevar (const auto_client_timevar &);
+
+  timer *m_timer;
+};
+
 extern void print_time (const char *, long);
 
 #endif /* ! GCC_TIMEVAR_H */
-- 
1.8.5.3



[PATCH 05/49] vec.h: add auto_delete_vec

2019-11-15 Thread David Malcolm
This patch adds a class auto_delete_vec, a subclass of auto_vec 
that deletes all of its elements on destruction; it's used in many
places later in the kit.

This is a crude way for a vec to "own" the objects it points to
and clean up automatically (essentially a workaround for not being able
to use unique_ptr, due to C++98).

gcc/ChangeLog:
* vec.c (class selftest::count_dtor): New class.
(selftest::test_auto_delete_vec): New test.
(selftest::vec_c_tests): Call it.
* vec.h (class auto_delete_vec): New class template.
(auto_delete_vec::~auto_delete_vec): New dtor.
---
 gcc/vec.c | 27 +++
 gcc/vec.h | 35 +++
 2 files changed, 62 insertions(+)

diff --git a/gcc/vec.c b/gcc/vec.c
index bac5eb7..a9c840d 100644
--- a/gcc/vec.c
+++ b/gcc/vec.c
@@ -516,6 +516,32 @@ test_reverse ()
   }
 }
 
+/* A test class that increments a counter every time its dtor is called.  */
+
+class count_dtor
+{
+ public:
+  count_dtor (int *counter) : m_counter (counter) {}
+  ~count_dtor () { (*m_counter)++; }
+
+ private:
+  int *m_counter;
+};
+
+/* Verify that auto_delete_vec deletes the elements within it.  */
+
+static void
+test_auto_delete_vec ()
+{
+  int dtor_count = 0;
+  {
+auto_delete_vec  v;
+v.safe_push (new count_dtor (_count));
+v.safe_push (new count_dtor (_count));
+  }
+  ASSERT_EQ (dtor_count, 2);
+}
+
 /* Run all of the selftests within this file.  */
 
 void
@@ -533,6 +559,7 @@ vec_c_tests ()
   test_block_remove ();
   test_qsort ();
   test_reverse ();
+  test_auto_delete_vec ();
 }
 
 } // namespace selftest
diff --git a/gcc/vec.h b/gcc/vec.h
index 091056b..1957739 100644
--- a/gcc/vec.h
+++ b/gcc/vec.h
@@ -1539,6 +1539,28 @@ class auto_string_vec : public auto_vec 
   ~auto_string_vec ();
 };
 
+/* A subclass of auto_vec  that deletes all of its elements on
+   destruction.
+
+   This is a crude way for a vec to "own" the objects it points to
+   and clean up automatically.
+
+   For example, no attempt is made to delete elements when an item
+   within the vec is overwritten.
+
+   We can't rely on gnu::unique_ptr within a container,
+   since we can't rely on move semantics in C++98.  */
+
+template 
+class auto_delete_vec : public auto_vec 
+{
+ public:
+  auto_delete_vec () {}
+  auto_delete_vec (size_t s) : auto_vec  (s) {}
+
+  ~auto_delete_vec ();
+};
+
 /* Conditionally allocate heap memory for VEC and its internal vector.  */
 
 template
@@ -1643,6 +1665,19 @@ auto_string_vec::~auto_string_vec ()
 free (str);
 }
 
+/* auto_delete_vec's dtor, deleting all contained items, automatically
+   chaining up to ~auto_vec , which frees the internal buffer.  */
+
+template 
+inline
+auto_delete_vec::~auto_delete_vec ()
+{
+  int i;
+  T *item;
+  FOR_EACH_VEC_ELT (*this, i, item)
+delete item;
+}
+
 
 /* Return a copy of this vector.  */
 
-- 
1.8.5.3



[PATCH 01/49] analyzer: user-facing documentation

2019-11-15 Thread David Malcolm
gcc/ChangeLog:
* doc/invoke.texi ("Static Analyzer Options"): New list and new section.
("Warning Options"): Add static analysis warnings to the list.
(-Wno-analyzer-double-fclose): New option.
(-Wno-analyzer-double-free): New option.
(-Wno-analyzer-exposure-through-output-file): New option.
(-Wno-analyzer-file-leak): New option.
(-Wno-analyzer-free-of-non-heap): New option.
(-Wno-analyzer-malloc-leak): New option.
(-Wno-analyzer-possible-null-argument): New option.
(-Wno-analyzer-possible-null-dereference): New option.
(-Wno-analyzer-null-argument): New option.
(-Wno-analyzer-null-dereference): New option.
(-Wno-analyzer-stale-setjmp-buffer): New option.
(-Wno-analyzer-tainted-array-index): New option.
(-Wno-analyzer-use-after-free): New option.
(-Wno-analyzer-use-of-pointer-in-stale-stack-frame): New option.
(-Wno-analyzer-use-of-uninitialized-value): New option.
(-Wanalyzer-too-complex): New option.
(-fanalyzer-call-summaries): New warning.
(-fanalyzer-checker=): New warning.
(-fanalyzer-fine-grained): New warning.
(-fno-analyzer-state-merge): New warning.
(-fno-analyzer-state-purge): New warning.
(-fanalyzer-transitivity): New warning.
(-fanalyzer-verbose-edges): New warning.
(-fanalyzer-verbose-state-changes): New warning.
(-fanalyzer-verbosity=): New warning.
(-fdump-analyzer): New warning.
(-fdump-analyzer-callgraph): New warning.
(-fdump-analyzer-exploded-graph): New warning.
(-fdump-analyzer-exploded-nodes): New warning.
(-fdump-analyzer-exploded-nodes-2): New warning.
(-fdump-analyzer-exploded-nodes-3): New warning.
(-fdump-analyzer-supergraph): New warning.
---
 gcc/doc/invoke.texi | 420 +++-
 1 file changed, 418 insertions(+), 2 deletions(-)

diff --git a/gcc/doc/invoke.texi b/gcc/doc/invoke.texi
index 085e8b0..384848a 100644
--- a/gcc/doc/invoke.texi
+++ b/gcc/doc/invoke.texi
@@ -153,6 +153,7 @@ listing and explanation of the binary and decimal byte size 
prefixes.
 * Diagnostic Message Formatting Options:: Controlling how diagnostics should
 be formatted.
 * Warning Options:: How picky should the compiler be?
+* Static Analyzer Options:: More expensive warnings.
 * Debugging Options::   Producing debuggable code.
 * Optimize Options::How much optimization?
 * Instrumentation Options:: Enabling profiling and extra run-time error 
checking.
@@ -284,13 +285,30 @@ Objective-C and Objective-C++ Dialects}.
 
 @item Warning Options
 @xref{Warning Options,,Options to Request or Suppress Warnings}.
-@gccoptlist{-fsyntax-only  -fmax-errors=@var{n}  -Wpedantic @gol
+@gccoptlist{--analyzer -fsyntax-only  -fmax-errors=@var{n}  -Wpedantic @gol
 -pedantic-errors @gol
 -w  -Wextra  -Wall  -Waddress  -Waddress-of-packed-member @gol
 -Waggregate-return  -Waligned-new @gol
 -Walloc-zero  -Walloc-size-larger-than=@var{byte-size} @gol
 -Walloca  -Walloca-larger-than=@var{byte-size} @gol
--Wno-aggressive-loop-optimizations  -Warray-bounds  -Warray-bounds=@var{n} @gol
+-Wno-aggressive-loop-optimizations @gol
+-Wno-analyzer-double-fclose @gol
+-Wno-analyzer-double-free @gol
+-Wno-analyzer-exposure-through-output-file @gol
+-Wno-analyzer-file-leak @gol
+-Wno-analyzer-free-of-non-heap @gol
+-Wno-analyzer-malloc-leak @gol
+-Wno-analyzer-possible-null-argument @gol
+-Wno-analyzer-possible-null-dereference @gol
+-Wno-analyzer-null-argument @gol
+-Wno-analyzer-null-dereference @gol
+-Wno-analyzer-stale-setjmp-buffer @gol
+-Wno-analyzer-tainted-array-index @gol
+-Wno-analyzer-use-after-free @gol
+-Wno-analyzer-use-of-pointer-in-stale-stack-frame @gol
+-Wno-analyzer-use-of-uninitialized-value @gol
+-Wanalyzer-too-complex @gol
+-Warray-bounds  -Warray-bounds=@var{n} @gol
 -Wno-attributes  -Wattribute-alias=@var{n}  @gol
 -Wbool-compare  -Wbool-operation @gol
 -Wno-builtin-declaration-mismatch @gol
@@ -370,6 +388,43 @@ Objective-C and Objective-C++ Dialects}.
 -Wwrite-strings @gol
 -Wzero-as-null-pointer-constant}
 
+@item Static Analyzer Options
+@gccoptlist{-Wanalyzer-double-fclose @gol
+-Wanalyzer-double-free @gol
+-Wanalyzer-exposure-through-output-file @gol
+-Wanalyzer-file-leak @gol
+-Wanalyzer-free-of-non-heap @gol
+-Wanalyzer-malloc-leak @gol
+-Wanalyzer-null-argument @gol
+-Wanalyzer-null-dereference @gol
+-Wanalyzer-possible-null-argument @gol
+-Wanalyzer-possible-null-dereference @gol
+-Wanalyzer-stale-setjmp-buffer @gol
+-Wanalyzer-tainted-array-index @gol
+-Wanalyzer-use-after-free @gol
+-Wanalyzer-use-of-pointer-in-stale-stack-frame @gol
+-Wanalyzer-use-of-uninitialized-value @gol
+-Wanalyzer-too-complex  @gol
+-fanalyzer-call-summaries @gol
+-fanalyzer-checker=@var{name} @gol
+-fanalyzer-fine-grained @gol
+-fanalyzer-state-merge @gol
+-fanalyzer-state-purge @gol

[PATCH 03/49] diagnostic_show_locus: move initial newline to callers

2019-11-15 Thread David Malcolm
diagnostic_show_locus adds a newline before doing anything (including
the do-nothing-else case).

This patch removes this initial newline, adding it to all callers
of diagnostic_show_locus instead.

Doing so makes diagnostic_show_locus more flexible, allowing it to be
used later in this patch kit when printing diagnostic paths.

gcc/c-family/ChangeLog:
* c-format.c (test_type_mismatch_range_labels): Remove initial
newline from expected outputs.
* c-opts.c (c_diagnostic_finalizer): Add pp_newline call before
call to diagnostic_show_locus.

gcc/ChangeLog:
* diagnostic-show-locus.c (diagnostic_show_locus): Remove initial
newline.
(selftest::test_diagnostic_show_locus_unknown_location): Remove
initial newline from expected output.
(selftest::test_one_liner_simple_caret): Likewise.
(selftest::test_one_liner_caret_and_range): Likewise.
(selftest::test_one_liner_multiple_carets_and_ranges): Likewise.
(selftest::test_one_liner_fixit_insert_before): Likewise.
(selftest::test_one_liner_fixit_insert_after): Likewise.
(selftest::test_one_liner_fixit_remove): Likewise.
(selftest::test_one_liner_fixit_replace): Likewise.
(selftest::test_one_liner_fixit_replace_non_equal_range):
Likewise.
(selftest::test_one_liner_fixit_replace_equal_secondary_range):
Likewise.
(selftest::test_one_liner_fixit_validation_adhoc_locations):
Likewise.
(selftest::test_one_liner_many_fixits_1): Likewise.
(selftest::test_one_liner_many_fixits_2): Likewise.
(selftest::test_one_liner_labels): Likewise.
(selftest::test_add_location_if_nearby): Likewise.
(selftest::test_diagnostic_show_locus_fixit_lines): Likewise.
(selftest::test_overlapped_fixit_printing): Likewise.
(selftest::test_overlapped_fixit_printing_2): Likewise.
(selftest::test_fixit_insert_containing_newline): Likewise.
(selftest::test_fixit_insert_containing_newline_2): Likewise.
(selftest::test_fixit_replace_containing_newline): Likewise.
(selftest::test_fixit_deletion_affecting_newline): Likewise.
(selftest::test_line_numbers_multiline_range): Likewise.
* diagnostic.c (default_diagnostic_finalizer): Add pp_newline call
before call to diagnostic_show_locus.
(diagnostic_append_note): Likewise.

gcc/fortran/ChangeLog:
* error.c (gfc_diagnostic_starter): Add pp_newline call
before call to diagnostic_show_locus.

gcc/testsuite/ChangeLog:
* gcc.dg/plugin/diagnostic_plugin_test_show_locus.c
(custom_diagnostic_finalizer): Add pp_newline call before call to
diagnostic_show_locus.
---
 gcc/c-family/c-format.c|   6 +-
 gcc/c-family/c-opts.c  |   1 +
 gcc/diagnostic-show-locus.c| 142 +++--
 gcc/diagnostic.c   |   2 +
 gcc/fortran/error.c|   1 +
 .../plugin/diagnostic_plugin_test_show_locus.c |   1 +
 6 files changed, 54 insertions(+), 99 deletions(-)

diff --git a/gcc/c-family/c-format.c b/gcc/c-family/c-format.c
index 3c291ca..7ddf064 100644
--- a/gcc/c-family/c-format.c
+++ b/gcc/c-family/c-format.c
@@ -5390,16 +5390,14 @@ test_type_mismatch_range_labels ()
   diagnostic_show_locus (, , DK_ERROR);
   if (c_dialect_cxx ())
 /* "char*", without a space.  */
-ASSERT_STREQ ("\n"
- "   printf (\"msg: %i\\n\", msg);\n"
+ASSERT_STREQ ("   printf (\"msg: %i\\n\", msg);\n"
  " ~^ ~~~\n"
  "  | |\n"
  "  char* int\n",
  pp_formatted_text (dc.printer));
   else
 /* "char *", with a space.  */
-ASSERT_STREQ ("\n"
- "   printf (\"msg: %i\\n\", msg);\n"
+ASSERT_STREQ ("   printf (\"msg: %i\\n\", msg);\n"
  " ~^ ~~~\n"
  "  | |\n"
  "  | int\n"
diff --git a/gcc/c-family/c-opts.c b/gcc/c-family/c-opts.c
index 0fffe60..d752328 100644
--- a/gcc/c-family/c-opts.c
+++ b/gcc/c-family/c-opts.c
@@ -170,6 +170,7 @@ c_diagnostic_finalizer (diagnostic_context *context,
 {
   char *saved_prefix = pp_take_prefix (context->printer);
   pp_set_prefix (context->printer, NULL);
+  pp_newline (context->printer);
   diagnostic_show_locus (context, diagnostic->richloc, diagnostic->kind);
   /* By default print macro expansion contexts in the diagnostic
  finalizer -- for tokens resulting from macro expansion.  */
diff --git a/gcc/diagnostic-show-locus.c b/gcc/diagnostic-show-locus.c
index cb920f6..412b0d4 100644
--- a/gcc/diagnostic-show-locus.c
+++ b/gcc/diagnostic-show-locus.c
@@ -2283,8 +2283,6 @@ diagnostic_show_locus (diagnostic_context * context,
  

[PATCH 04/49] sbitmap.h: add operator const sbitmap & to auto_sbitmap

2019-11-15 Thread David Malcolm
gcc/ChangeLog:
* sbitmap.h (auto_sbitmap): Add operator const sbitmap &.
---
 gcc/sbitmap.h | 1 +
 1 file changed, 1 insertion(+)

diff --git a/gcc/sbitmap.h b/gcc/sbitmap.h
index a33175d..3c5b0a4 100644
--- a/gcc/sbitmap.h
+++ b/gcc/sbitmap.h
@@ -295,6 +295,7 @@ public:
 
   /* Allow calling sbitmap functions on our bitmap.  */
   operator sbitmap () { return m_bitmap; }
+  operator const sbitmap &() const { return m_bitmap; }
 
 private:
   /* Prevent making a copy that refers to our sbitmap.  */
-- 
1.8.5.3



[PATCH], V9, #4 of 4, Add PCREL_OPT tests

2019-11-15 Thread Michael Meissner
This patch adds the tests for PCREL_OPT.

These tests all pass with the compiler using the previous 3 patches.  Can I
check these tests in once the previous patches have been checked in?

2019-11-15  Michael Meissner  

* gcc.target/powerpc/pcrel-opt-inc-di.c: New PCREL_OPT test.
* gcc.target/powerpc/pcrel-opt-ld-df.c: New PCREL_OPT test.
* gcc.target/powerpc/pcrel-opt-ld-di.c: New PCREL_OPT test.
* gcc.target/powerpc/pcrel-opt-ld-hi.c: New PCREL_OPT test.
* gcc.target/powerpc/pcrel-opt-ld-qi.c: New PCREL_OPT test.
* gcc.target/powerpc/pcrel-opt-ld-sf.c: New PCREL_OPT test.
* gcc.target/powerpc/pcrel-opt-ld-si.c: New PCREL_OPT test.
* gcc.target/powerpc/pcrel-opt-ld-vector.c: New PCREL_OPT test.
* gcc.target/powerpc/pcrel-opt-st-df.c: New PCREL_OPT test.
* gcc.target/powerpc/pcrel-opt-st-di.c: New PCREL_OPT test.
* gcc.target/powerpc/pcrel-opt-st-hi.c: New PCREL_OPT test.
* gcc.target/powerpc/pcrel-opt-st-qi.c: New PCREL_OPT test.
* gcc.target/powerpc/pcrel-opt-st-sf.c: New PCREL_OPT test.
* gcc.target/powerpc/pcrel-opt-st-si.c: New PCREL_OPT test.
* gcc.target/powerpc/pcrel-opt-st-vector.c: New PCREL_OPT test.

--- /tmp/fBLTFi_pcrel-opt-inc-di.c  2019-11-15 18:10:20.758267583 -0500
+++ gcc/testsuite/gcc.target/powerpc/pcrel-opt-inc-di.c 2019-11-15 
18:08:33.582546070 -0500
@@ -0,0 +1,19 @@
+/* { dg-do compile } */
+/* { dg-require-effective-target powerpc_pcrel_ok } */
+/* { dg-require-effective-target lp64 } */
+/* { dg-options "-O2 -mdejagnu-cpu=future" } */
+
+#define TYPE   long long
+#define LARGE  0x2
+
+/* Test whether using an external variable twice (doing an increment) prevents
+   the PCREL_OPT optimization.  */
+extern TYPE ext;
+
+void
+inc (void)
+{
+  ext++;   /* No PCREL_OPT (use address twice).  */
+}
+
+/* { dg-final { scan-assembler-none "R_PPC64_PCREL_OPT" } } */
--- /tmp/hYjgYx_pcrel-opt-ld-df.c   2019-11-15 18:10:20.766267711 -0500
+++ gcc/testsuite/gcc.target/powerpc/pcrel-opt-ld-df.c  2019-11-15 
18:01:37.758866894 -0500
@@ -0,0 +1,36 @@
+/* { dg-do compile } */
+/* { dg-require-effective-target powerpc_pcrel_ok } */
+/* { dg-options "-O2 -mdejagnu-cpu=future" } */
+
+#define TYPE   double
+#define LARGE  0x2
+
+/* Test whether we get the right number of PCREL_OPT optimizations for
+   double.  */
+extern TYPE ext[];
+
+TYPE
+get (void)
+{
+  return ext[0];   /* PCREL_OPT relocation.  */
+}
+
+TYPE
+get2 (void)
+{
+  return ext[2];   /* PCREL_OPT relocation.  */
+}
+
+TYPE
+get_large (void)
+{
+  return ext[LARGE];   /* No PCREL_OPT (load is  prefixed).  */
+}
+
+TYPE
+get_variable (unsigned long n)
+{
+  return ext[n];   /* No PCREL_OPT (load is indexed).  */
+}
+
+/* { dg-final { scan-assembler-times "R_PPC64_PCREL_OPT"  2 } } */
--- /tmp/ZUc4hN_pcrel-opt-ld-di.c   2019-11-15 18:10:20.774267840 -0500
+++ gcc/testsuite/gcc.target/powerpc/pcrel-opt-ld-di.c  2019-11-15 
17:59:49.062120950 -0500
@@ -0,0 +1,43 @@
+/* { dg-do compile } */
+/* { dg-require-effective-target powerpc_pcrel_ok } */
+/* { dg-require-effective-target lp64 } */
+/* { dg-options "-O2 -mdejagnu-cpu=future" } */
+
+#define TYPE   long long
+#define LARGE  0x2
+
+/* Test whether we get the right number of PCREL_OPT optimizations for long
+   long.  */
+extern TYPE ext[];
+
+TYPE
+get (void)
+{
+  return ext[0];   /* PCREL_OPT relocation.  */
+}
+
+TYPE
+get2 (void)
+{
+  return ext[2];   /* PCREL_OPT relocation.  */
+}
+
+TYPE
+get_large (void)
+{
+  return ext[LARGE];   /* No PCREL_OPT (load is  prefixed).  */
+}
+
+TYPE
+get_variable (unsigned long n)
+{
+  return ext[n];   /* No PCREL_OPT (load is indexed).  */
+}
+
+double
+get_double (void)
+{
+  return (double) ext[0];  /* PCREL_OPT relocation.  */
+}
+
+/* { dg-final { scan-assembler-times "R_PPC64_PCREL_OPT"  3 } } */
--- /tmp/HWjfD2_pcrel-opt-ld-hi.c   2019-11-15 18:10:20.781267952 -0500
+++ gcc/testsuite/gcc.target/powerpc/pcrel-opt-ld-hi.c  2019-11-15 
17:56:55.055325962 -0500
@@ -0,0 +1,42 @@
+/* { dg-do compile } */
+/* { dg-require-effective-target powerpc_pcrel_ok } */
+/* { dg-options "-O2 -mdejagnu-cpu=future" } */
+
+#define TYPE   unsigned short
+#define LARGE  0x2
+
+/* Test whether we get the right number of PCREL_OPT optimizations for unsigned
+   short.  */
+extern TYPE ext[];
+
+TYPE
+get (void)
+{
+  return ext[0];   /* PCREL_OPT relocation.  */
+}
+
+TYPE
+get2 (void)
+{
+  return ext[2];   /* PCREL_OPT relocation.  */
+}
+
+TYPE
+get_large (void)
+{
+  return ext[LARGE];   /* No PCREL_OPT (load is  prefixed).  */
+}
+
+TYPE
+get_variable (unsigned long n)
+{
+  return ext[n];   /* No PCREL_OPT (load is indexed).  */
+}
+
+double
+get_double (void)
+{
+  return (double) ext[0];  /* No PCREL_OPT (LXSIHZX is indexed).  */
+}
+
+/* { dg-final 

[PATCH], V9, #3 of 4, Add PCREL_OPT store support

2019-11-15 Thread Michael Meissner
This patch adds support for the PCREL_OPT optimization with stores.

I have built a bootstrap compiler with these changes on a little endian power8
system, and there were no regressions in the test suite.  Can I check this
patch in after the preceeding 3 patches have been checked in?

2019-11-15  Michael Meissner  

* config/rs6000/pcrel-opt.c: Update comments saying we support the
PCREL_OPT optimization for both loads and stores.
(class pcrel_opt): Add do_pcrel_opt_store declaration.  Add
counters for the # of PCREL_OPT stores.
(pcrel_opt::do_pcrel_opt_store): New function to support doing the
PCREL_OPT optimization on stores.
(pcrel_opt::do_pcrel_opt_got_addr): Add support for doing the
PCREL_OPT optimization on stores.
(pcrel_opt::do_pcrel_opt_pass): Print out the statistics for the
number of PCREL_OPT stores.
* config/rs6000/rs6000.c (rs6000_delegitimize_address): Convert
PCREL_OPT load GOT address for store back into a SYMBOL_REF.
* config/rs6000/rs6000.md (UNSPEC_PCREL_OPT_ST_GOT): New unspec.
(UNSPEC_PCREL_OPT_ST_RELOC): New unspec.
(pcrel_opt_st_got): New insns for optimizing the load
address of an external variable combine with stores to with the
PCREL_OPT optimization.
(pcrel_opt_st, QHSI iterator): New insns to optimize the
store to an external variable with the PCREL_OPT optimization.
(pcrel_opt_stdi): New insn to optimize DImode stores to an
external variable with the PCREL_OPT optimization.
(pcrel_opt_stsf): New insn to optimize SFmode stores to an
external variable with the PCREL_OPT optimization.
(pcrel_opt_stdf): New insn to optimize DFmode stores to an
external variable with the PCREL_OPT optimization.

Index: gcc/config/rs6000/pcrel-opt.c
===
--- gcc/config/rs6000/pcrel-opt.c   (revision 278319)
+++ gcc/config/rs6000/pcrel-opt.c   (working copy)
@@ -19,8 +19,8 @@
 
 /* This file implements a RTL pass that looks for pc-relative loads of the
address of an external variable using the PCREL_GOT relocation and a single
-   load that uses that GOT pointer.  If that is found we create the PCREL_OPT
-   relocation to possibly convert:
+   load/store that uses that GOT pointer.  If that is found we create the
+   PCREL_OPT relocation to possibly convert:
 
pld b,var@pcrel@got(0),1
 
@@ -98,8 +98,8 @@ const pass_data pass_data_pcrel_opt =
   TODO_df_finish,  // todo_flags_finish
 };
 
-// Maximum number of insns to scan between the load address and the load that
-// uses that address.
+// Maximum number of insns to scan between the load address and the load or
+// store that uses that address.
 const int MAX_PCREL_OPT_INSNS  = 10;
 
 /* Next PCREL_OPT label number.  */
@@ -119,11 +119,16 @@ private:
   // Optimize a particular PC-relative load
   bool do_pcrel_opt_load (rtx_insn *, rtx_insn *);
 
+  // Optimize a particular PC-relative store
+  bool do_pcrel_opt_store (rtx_insn *, rtx_insn *);
+
   // Various counters
   struct {
 unsigned long gots;
 unsigned long loads;
 unsigned long load_separation[MAX_PCREL_OPT_INSNS+1];
+unsigned long stores;
+unsigned long store_separation[MAX_PCREL_OPT_INSNS+1];
   } counters;
 
 public:
@@ -340,6 +345,154 @@ pcrel_opt::do_pcrel_opt_load (rtx_insn *
 }
 
 
+// Optimize a PC-relative load address to be used in a store.
+
+// If the sequence of insns is safe to use the PCREL_OPT optimization (i.e. no
+// additional references to the address register, the address register dies at
+// the load, and no references to the load), convert insns of the form:
+//
+// (set (reg:DI addr)
+//  (symbol_ref:DI "ext_symbol"))
+//
+// ...
+//
+// (set (mem: (reg:DI addr))
+//  (reg: value))
+//
+// into:
+//
+// (parallel [(set (reg:DI addr)
+//  (unspec:DI [(symbol_ref:DI "ext_symbol")
+//  (const_int label_num)]
+// UNSPEC_PCREL_OPT_ST_GOT))
+// (use (reg: value))])
+//
+// ...
+//
+// (parallel [(set (mem: (reg:DI addr))
+//  (unspec: [(reg:)
+//  (const_int label_num)]
+// UNSPEC_PCREL_OPT_ST_RELOC))
+// (clobber (reg:DI addr))])
+//
+//
+// The UNSPEC_PCREL_OPT_ST_GOT insn will generate the load address plus a
+// definition of a label (.Lpcrel), while the UNSPEC_PCREL_OPT_ST_RELOC insn
+// will generate the .reloc to tell the linker to tie the load address and load
+// using that address together.
+//
+// pld b,ext_symbol@got@pcrel(0),1
+// .Lpcrel1:
+//
+// ...
+//
+// .reloc .Lpcrel1-8,R_PPC64_PCREL_OPT,.-(.Lpcrel1-8)
+// stw r,0(b)
+//
+// If ext_symbol is defined in another object file in the 

[C++ PATCH] Fix up spaceship diagnostics

2019-11-15 Thread Jakub Jelinek
Hi!

While working on the __builtin_source_location patch, I've noticed that
these two messages are weird:
spaceship-err3.C:11:12: error: ‘std::std::strong_ordering’ is not a type
spaceship-err3.C:11:12: note: forming type of ‘operator<=>’
spaceship-err3.C:13:14: error: 
‘std::partial_ordering::std::partial_ordering::equivalent()’ is not a static 
data member
spaceship-err3.C:13:14: note: determining value of ‘operator<=>’
Note the doubled std:: in the first case and std::partial_ordering:: in the
second case.  Most of the code that uses %<%T::%D%> elsewhere prints
DECL_NAME rather than the actual decl, but in this case when it is a decl,
there is no need to prefix it with anything.

Bootstrapped/regtested on x86_64-linux and i686-linux, ok for trunk?

2019-11-16  Jakub Jelinek  

* method.c (lookup_comparison_result): Use %qD instead of %<%T::%D%>
to print the decl.
(lookup_comparison_category): Use %qD instead of % to print
the decl.

* g++.dg/cpp2a/spaceship-err3.C: New test.

--- gcc/cp/method.c.jj  2019-11-13 19:13:12.059100901 +0100
+++ gcc/cp/method.c 2019-11-16 00:07:56.080097451 +0100
@@ -924,7 +924,7 @@ lookup_comparison_result (tree type, con
  if (decl == error_mark_node || TREE_CODE (decl) == TREE_LIST)
qualified_name_lookup_error (type, name, decl, input_location);
  else
-   error ("%<%T::%D%> is not a static data member", type, decl);
+   error ("%qD is not a static data member", decl);
  inform (input_location, "determining value of %qs", "operator<=>");
}
   return error_mark_node;
@@ -951,7 +951,7 @@ lookup_comparison_category (comp_cat_tag
  if (decl == error_mark_node || TREE_CODE (decl) == TREE_LIST)
qualified_name_lookup_error (std_node, name, decl, input_location);
  else
-   error ("% is not a type", decl);
+   error ("%qD is not a type", decl);
  inform (input_location, "forming type of %qs", "operator<=>");
}
   return error_mark_node;
--- gcc/testsuite/g++.dg/cpp2a/spaceship-err3.C.jj  2019-11-16 
00:11:19.105048135 +0100
+++ gcc/testsuite/g++.dg/cpp2a/spaceship-err3.C 2019-11-16 00:12:21.637108940 
+0100
@@ -0,0 +1,14 @@
+// { dg-do compile { target c++2a } }
+
+namespace std
+{
+  int strong_ordering;
+  struct partial_ordering {
+static int equivalent ();
+  };
+}
+
+auto a = 1 <=> 2;  // { dg-error "'std::strong_ordering' is not a type" }
+   // { dg-message "forming type of 'operator<=>'" "" { 
target *-*-* } .-1 }
+auto b = 3.0 <=> 4.0;  // { dg-error 
"'std::partial_ordering::equivalent\\(\\)' is not a static data member" }
+   // { dg-message "determining value of 'operator<=>'" "" 
{ target *-*-* } .-1 }

Jakub



[PATCH], V9, #2 of 4, Add PCREL_OPT for sign, zero, and float extend

2019-11-15 Thread Michael Meissner
This patch builds on the previous patch, and it adds the PCREL_OPT optimization
for loads of external variables that involve sign extension, zero extension, or
float extension as part of the load.

I have built a bootstrap compiler on a little endian power8 system and it
caused no regressions in the test suite.  Can I check this in once the previous
patch has been checked in?

2019-11-15  Michael Meissner  

* config/rs6000/pcrel-opt.c (pcrel_opt::do_pcrel_opt_load): Add
support to do the PCREL_OPT optimization with sign, zero, and
float extension.
* config/rs6000/rs6000.md (pcrel_opt_ldsi_sext): New insns
for applying the PCREL_OPT optimization to SImode sign extension.
(pcrel_opt_ldhi_sext): New insns for applying the PCREL_OPT
optimization to HImode sign extension.
(pcrel_opt_ldsi_zext): New insns for applying the PCREL_OPT
optimization to SImode zero extension.
(pcrel_opt_ldhi_zext): New insns for applying the PCREL_OPT
optimization to HImode zero extension.
(pcrel_opt_ldqi_zext): New insns for applying the PCREL_OPT
optimization to QImode zero extension.
(pcrel_opt_ldsf_extend): New insns for applying the PCREL_OPT
optimization to SFmode float extension.

Index: gcc/config/rs6000/pcrel-opt.c
===
--- gcc/config/rs6000/pcrel-opt.c   (revision 278315)
+++ gcc/config/rs6000/pcrel-opt.c   (working copy)
@@ -223,6 +223,27 @@ pcrel_opt::do_pcrel_opt_load (rtx_insn *
   rtx mem_inner = mem;
   unsigned int reg_regno = reg_or_subregno (reg);
 
+  // LWA is a DS format instruction, but LWZ is a D format instruction.  We use
+  // DImode for the mode to force checking whether the bottom 2 bits are 0.
+  // However FPR and vector registers uses the LFIWAX instruction which is
+  // indexed only.
+  if (GET_CODE (mem) == SIGN_EXTEND && GET_MODE (XEXP (mem, 0)) == SImode)
+{
+  if (!INT_REGNO_P (reg_regno))
+   return false;
+
+  mem_inner = XEXP (mem, 0);
+  mem_mode = DImode;
+}
+
+  else if (GET_CODE (mem) == SIGN_EXTEND
+  || GET_CODE (mem) == ZERO_EXTEND
+  || GET_CODE (mem) == FLOAT_EXTEND)
+{
+  mem_inner = XEXP (mem, 0);
+  mem_mode = GET_MODE (mem_inner);
+}
+
   if (!MEM_P (mem_inner))
 return false;
 
@@ -275,8 +296,9 @@ pcrel_opt::do_pcrel_opt_load (rtx_insn *
   return false;
 }
 
-  // Update the load insn.  Add an explicit clobber of the GOT register just in
-  // case something runs after this pass.
+  // Update the load insn.  If the mem had a sign/zero/float extend, add that
+  // also after doing the UNSPEC.  Add an explicit clobber of the GOT register
+  // just in case something runs after this pass.
   //
   // (parallel [(set (reg)
   // (unspec: [(mem (got)
@@ -288,6 +310,9 @@ pcrel_opt::do_pcrel_opt_load (rtx_insn *
   rtx new_load = gen_rtx_UNSPEC (GET_MODE (mem_inner), v_load,
 UNSPEC_PCREL_OPT_LD_RELOC);
 
+  if (GET_CODE (mem) != GET_CODE (mem_inner))
+new_load = gen_rtx_fmt_e (GET_CODE (mem), reg_mode, new_load);
+
   rtx old_load_set = PATTERN (load_insn);
   rtx new_load_set = gen_rtx_SET (reg, new_load);
   rtx load_clobber = gen_rtx_CLOBBER (VOIDmode,
@@ -484,11 +509,21 @@ pcrel_opt::do_pcrel_opt_got_addr (rtx_in
 {
   reg = SET_DEST (load_set);
   mem = SET_SRC (load_set);
-  if (!MEM_P (mem))
-   return;
+  switch (GET_CODE (mem))
+   {
+   case MEM:
+ break;
 
-  if (!REG_P (reg) && !SUBREG_P (reg))
-   return;
+   case SIGN_EXTEND:
+   case ZERO_EXTEND:
+   case FLOAT_EXTEND:
+ if (!MEM_P (XEXP (mem, 0)))
+   return;
+ break;
+
+   default:
+ return;
+   }
 
   // If there were any stores in the insns between loading the GOT address
   // and doing the load, turn off the optimization.
@@ -499,6 +534,9 @@ pcrel_opt::do_pcrel_opt_got_addr (rtx_in
   else
 return;
 
+  if (!REG_P (reg) && !SUBREG_P (reg))
+return;
+
   machine_mode mode = GET_MODE (reg);
   unsigned int regno = reg_or_subregno (reg);
   unsigned int size = GET_MODE_SIZE (mode);
Index: gcc/config/rs6000/rs6000.md
===
--- gcc/config/rs6000/rs6000.md (revision 278315)
+++ gcc/config/rs6000/rs6000.md (working copy)
@@ -14813,6 +14813,61 @@ (define_insn "*pcrel_opt_ld"
   "%r2lz %0,%1"
   [(set_attr "type" "load")])
 
+(define_insn "*pcrel_opt_ldsi_sext"
+  [(set (match_operand:EXTSI 0 "gpc_reg_operand" "=r")
+   (sign_extend:EXTSI
+(unspec:SI [(match_operand:SI 1 "non_prefixed_memory" "o")
+(match_operand 2 "const_int_operand" "n")]
+   UNSPEC_PCREL_OPT_LD_RELOC)))
+   (clobber (match_scratch:DI 3 "=bX"))]
+  "TARGET_PCREL_OPT"
+  "%r2lwa %0,%1"
+  [(set_attr "type" "load")])
+

[PATCH], V9, #1 of 4, Add basic PCREL_OPT support for loads

2019-11-15 Thread Michael Meissner
This patch adds the basic support for the PCREL_OPT optimization for loads.  It
is on the long side, because I needed to create the infrastructure for the
support.  It creates a new pass that is run just before final to see if it can
find appropriate load external addresses and a single load/store using that
address.

I have bootstrapped a compiler with this a little endian power8 system, and
there were no regressions in the test suite.  Can I check this into the FSF
trunk once the patches it depends on from the V7 series have been checked in?

2019-11-15  Michael Meissner  

* config/rs6000/pcrel-opt.c: New file to implement the PCREL_OPT
optimization as a new pass.
* config/rs6000/rs6000-passes.def: Add comment for the analyze
swaps pass.  Add new pass to do the PCREL_OPT optimization.
* config/rs6000/rs6000-protos.h (enum non_prefixed_form): Add a
new case to recognize memory that meets PCREL_OPT requirements.
(reg_to_non_prefixed): New declaration.
(make_pass_pcrel_opt): New declaration.
* config/rs6000/rs6000.c (rs6000_option_override_internal): Add
support for -mpcrel-opt.
(rs6000_delegitimize_address): Convert PCREL_OPT unspec for GOT
load back into a normal SYMBOL_REF.
(print_operand): Add %r to print the .reloc for PCREL_OPT.
(rs6000_opt_masks): Add -mpcrel-opt.
(address_to_insn_form): For addresses used with PCREL_OPT, only
recognize addresses that can be used in a non-prefixed
instruction.
(reg_to_non_prefixed): Make global.
* config/rs6000/rs6000.md (UNSPEC_PCREL_OPT_LD_GOT): New unspec.
(UNSPEC_PCREL_OPT_LD_RELOC): New unspec.
(pcrel_extern_addr): Make it a global insn.
(PO mode iterator): New mode iterator for the PCREL_OPT
optimization.
(POV mode iterator): New mode iterator for the PCREL_OPT
optimization.
(pcrel_opt_ld_got, PO iterator): New insns for the PCREL_OPT
optimization to load the address of an external symbol.
(pcrel_opt_ld, QHSI iterator): New insns for the PCREL_OPT
optimization to load the value of an external variable.
(pcrel_opt_lddi): New insn for the PCREL_OPT optimization to load
a DImode external variable.
(pcrel_opt_ldsf): New insn for the PCREL_OPT optimization to load
a SFmode external variable.
(pcrel_opt_lddf): New insn for the PCREL_OPT optimization to load
a DFmode external variable.
(pcrel_opt_ld): New insns for the PCREL_OPT optimization to
load external vector variables.
* config/rs6000/rs6000.opt (-mpcrel-opt): New undocumented
switch.
* config/rs6000/t-rs6000 (pcrel-opt.o): Add build rules.
* config.gcc (powerpc*-*-*): Add pcrel-opt.o.
(rs6000*-*-*): Add pcrel-opt.o.

Index: gcc/config/rs6000/pcrel-opt.c
===
--- gcc/config/rs6000/pcrel-opt.c   (revision 278311)
+++ gcc/config/rs6000/pcrel-opt.c   (working copy)
@@ -0,0 +1,623 @@
+/* Subroutines used support the pc-relative linker optimization.
+   Copyright (C) 2019 Free Software Foundation, Inc.
+
+   This file is part of GCC.
+
+   GCC is free software; you can redistribute it and/or modify it
+   under the terms of the GNU General Public License as published
+   by the Free Software Foundation; either version 3, or (at your
+   option) any later version.
+
+   GCC is distributed in the hope that it will be useful, but WITHOUT
+   ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+   or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public
+   License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with GCC; see the file COPYING3.  If not see
+   .  */
+
+/* This file implements a RTL pass that looks for pc-relative loads of the
+   address of an external variable using the PCREL_GOT relocation and a single
+   load that uses that GOT pointer.  If that is found we create the PCREL_OPT
+   relocation to possibly convert:
+
+   pld b,var@pcrel@got(0),1
+
+   # possibly other instructions that do not use the base register 'b' or
+# the result register 'r'.
+
+   lwz r,0(b)
+
+   into:
+
+   plwz r,var@pcrel(0),1
+
+   # possibly other instructions that do not use the base register 'b' or
+# the result register 'r'.
+
+   nop
+
+   If the variable is not defined in the main program or the code using it is
+   not in the main program, the linker put the address in the .got section and
+   do:
+
+   .section .got
+   .Lvar_got:  .dword var
+
+   .section .text
+   pld b,.Lvar_got@pcrel(0),1
+
+   # possibly other instructions that do not use the base register 'b' or
+# the result register 'r'.
+
+   lwz r,0(b)
+   
+   We only 

PowerPC V9 patches, Add the PCREL_OPT optimization

2019-11-15 Thread Michael Meissner
This series of patches adds the PCREL_OPT optimization for the PC-relative
support in the PowerPC compiler.

This optimization convert a single load or store of an external variable to use
the R_PPC64_PCREL_OPT relocation.

For example, a normal load of an external int variable (with -mcpu=future)
would generate:

PLD 9,ext_symbol@got@pcrel(0),1
LWA 10,0(9)

That is, load the address of 'ext_symbol' into register 9.  If 'ext_symbol' is
defined in another module in the main program, and the current module is also
in the main program, the linker will optimize this to:

PADDI 9,ext_symbol(0),1
LWZ 10,0(9)

If either the definition is not in the main program or we are linking for a
shared library, the linker will create an address in the .got section and do a
PLD of it:

.section .got
.got.ext_symbol:
.quad ext_symbol

.section .text
PLD 9,.got.ext_symbol(0),1
LWZ 10,0(9)

If the only use of the GOT address is a single load and store, we can optimize
this further:

PLD 9,ext_symbol@got@pcrel(0),1
.Lpcrel1:
.reloc .Lpcrel1-8,R_PPC64_PCREL_OPT,.-(.Lpcrel1-8)
LWZ 10,0(9)

In this case, if the variable is defined in another module for the main
program, and we are linking for the main program, the linker will transform
this to:

PLWZ 10,ext_symbol@pcrel(0),1
NOP

There can be arbitrary instructions between the PLD and the LWA (or STW).

For either loads or store, register 9 must only be used in the load or store,
and must die at that point.

For loads, there must be no reference to register 10 between the PLD and the
LWZ.  For a store, register 10 must be live at the PLD instruction, and must
not be modified between the PLD and the STW instructions.

There are 4 patches in this patch set.

The first patch adds the basic PCREL_OPT for loads.

The second patch adds support for loads involving sign, zero, and float
extension to PCREL_OPT.

The third patch adds support for optimizing stores with PCREL_OPT.

The fourth patch is a series of tests to test whether the right number of
PCREL_OPT relocations are generated.

-- 
Michael Meissner, IBM
IBM, M/S 2506R, 550 King Street, Littleton, MA 01460-6245, USA
email: meiss...@linux.ibm.com, phone: +1 (978) 899-4797


Re: [PATCH 0/4] Eliminate cc0 from m68k

2019-11-15 Thread Bernd Schmidt
On 11/15/19 11:50 PM, Andreas Schwab wrote:
> On Nov 15 2019, Bernd Schmidt wrote:
> 
>> I meant the compiler command line of course... for any -mcpu flags that
>> might differ from my test run.
> 
> There are none.

Well, there has to be some difference between what you are doing and
what I am doing, because:

Running /local/src/egcs/git/gcc/testsuite/g++.old-deja/old-deja.exp ...

=== g++ Summary ===

# of expected passes26826
# of expected failures  82
# of unsupported tests  157
/local/src/egcs/bm68k-test/gcc/xg++  version 10.0.0 20191101
(experimental) (GCC)

Is there anything you think you can give me to help reproduce this?
Before/after assembly files, generated with -fverbose-asm?


Bernd


Re: [PATCH 0/2] Introduce a new GCC option, --record-gcc-command-line

2019-11-15 Thread Jeff Law
On 11/14/19 2:15 AM, Martin Liška wrote:
> On 11/13/19 8:23 PM, Jeff Law wrote:
>> On 11/13/19 2:37 AM, Martin Liška wrote:

 As Nick also mentioned many times, -grecord-gcc-switches is in DWARF
 and this causes a great disadvantage: it gets stripped out.
>>>
>>> Well, that's still something I disagree. I bet RedHat is similarly to
>>> openSUSE also building all packages with a debug info, which
>>> is later stripped and put into a foo-devel package. That's why one can
>>> easily read the compile options from these sub-packages.
>>> My motivation is to write a rpm linter check that will verify that all
>>> object files really used flags that we expect.
> 
> Hi.
> 
>> Right.  We inject -g into the default build flags.  We extract the
>> resultant debug info into a .debuginfo RPM.
> 
> Which means it can be possible to you to process a rpm check on the
> .debuginfo
> RPM packages. Right?
Yea, but there was a forward looking requirement that we also be able to
query a binary/DSO without debuginfo.

> 
>>
>> The original motivation behind annobin was to verify how well the
>> injection mechanism worked.
> 
> I thought the original motivation was to provide a sanity check on RPM
> level
> which will verify that all object files use the proper $Optflags
> (mainly security hardening ones like -D_FORTIFY_SOURCE=1,
> -fstack-protector-strong, -fstack-clash-protection, ..)?
> And so that you can guarantee that the packages are "safe" :)
In my mind those are the same problem.

If your flags injection sucks, then you'll get lousy coverage for things
like stack protector, fortification, etc.  annobin lets us find gaps in
coverage easily and fix them.

When you get gaps for something like cf-protection, then all the work
for cf-protection is wasted.  So identifying these gaps is critical.

Jeff



Re: [PATCH] Add support for C++2a stop_token

2019-11-15 Thread Jonathan Wakely

On 15/11/19 14:40 +, Jonathan Wakely wrote:

On 15/11/19 14:38 +, Jonathan Wakely wrote:

On 13/11/19 17:59 -0800, Thomas Rodgers wrote:

+  // TODO verify the standard requires this
+#if 0
+  // register another callback
+  bool cb3called{false};
+  std::stop_callback scb3{stok, [&]
+{
+  cb3called = true;
+}};
+  VERIFY(ssrc.stop_possible());
+  VERIFY(ssrc.stop_requested());
+  VERIFY(stok.stop_possible());
+  VERIFY(stok.stop_requested());
+  VERIFY(!cb1called);
+  VERIFY(cb2called);
+  VERIFY(cb3called);
+#endif


The working draft definitely requires this:

Effects: Initializes callback with std::forward(cb). If st.stop_requested() 
is true, then
std::forward(callback)() is evaluated in the current thread before 
the constructor
returns.


I've committed this fix to the nostopstate initializer, so it defines
a variable, instead of declaring a function. I've also added a test
that uses the stop_source(nostopstate_t) constructor, and a few other
tweaks to include the new header where it's needed.


This fixes some other issues I noticed, and should fix the failues for
the single-threaded multilib on AIX.

Tested powerpc64le-linux, committed to trunk.


commit 9c9f5a4bd84b924190551b65d4b5aaa3fbe6
Author: Jonathan Wakely 
Date:   Fri Nov 15 21:27:26 2019 +

libstdc++: Fix  and improve tests

* include/std/stop_token: Reduce header dependencies by including
internal headers.
(stop_token::swap(stop_token&), swap(stop_token&, stop_token&)):
Define.
(operator!=(const stop_token&, const stop_token&)): Fix return value.
(stop_token::_Stop_cb::_Stop_cb(Cb&&)): Use std::forward instead of
(stop_token::_Stop_state_t) [_GLIBCXX_HAS_GTHREADS]: Use lock_guard
instead of unique_lock.
[!_GLIBCXX_HAS_GTHREADS]: Do not use mutex.
(stop_token::stop_token(_Stop_state)): Change parameter to lvalue
reference.
(stop_source): Remove unnecessary using-declarations for names only
used once.
(swap(stop_source&, stop_source&)): Define.
(stop_callback(const stop_token&, _Cb&&))
(stop_callback(stop_token&&, _Cb&&)): Replace lambdas with a named
function. Use std::forward instead of std::move. Run callbacks if a
stop request has already been made.
(stop_source::_M_execute()): Remove.
(stop_source::_S_execute(_Stop_cb*)): Define.
* include/std/version (__cpp_lib_jthread): Define conditionally.
* testsuite/30_threads/stop_token/stop_callback.cc: New test.
* testsuite/30_threads/stop_token/stop_source.cc: New test.
* testsuite/30_threads/stop_token/stop_token.cc: Enable test for
immediate execution of callback.

diff --git a/libstdc++-v3/include/std/stop_token b/libstdc++-v3/include/std/stop_token
index f96c267f22e..bb082431d7f 100644
--- a/libstdc++-v3/include/std/stop_token
+++ b/libstdc++-v3/include/std/stop_token
@@ -31,24 +31,25 @@
 
 #if __cplusplus > 201703L
 
-#include 
-#include 
-#include 
 #include 
+#include 
+#include 
+#include 
+#include 
 
-#define __cpp_lib_jthread 201907L
+#ifdef _GLIBCXX_HAS_GTHREADS
+# define __cpp_lib_jthread 201907L
+#endif
 
 namespace std _GLIBCXX_VISIBILITY(default)
 {
 _GLIBCXX_BEGIN_NAMESPACE_VERSION
 
-  class stop_source;
-  template
-  class stop_callback;
-
+  /// Tag type indicating a stop_source should have no shared-stop-state.
   struct nostopstate_t { explicit nostopstate_t() = default; };
   inline constexpr nostopstate_t nostopstate{};
 
+  /// Allow testing whether a stop request has been made on a `stop_source`.
   class stop_token
   {
   public:
@@ -63,7 +64,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
 operator=(const stop_token& __rhs) noexcept = default;
 
 stop_token&
-operator=(stop_token&& __rhs) noexcept;
+operator=(stop_token&& __rhs) noexcept = default;
 
 [[nodiscard]]
 bool
@@ -79,6 +80,10 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
   return stop_possible() && _M_state->_M_stop_requested();
 }
 
+void
+swap(stop_token& __rhs) noexcept
+{ _M_state.swap(__rhs._M_state); }
+
 [[nodiscard]]
 friend bool
 operator==(const stop_token& __a, const stop_token& __b)
@@ -90,26 +95,31 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
 friend bool
 operator!=(const stop_token& __a, const stop_token& __b)
 {
-  return __a._M_state == __b._M_state;
+  return __a._M_state != __b._M_state;
 }
 
-  private:
-friend stop_source;
-template
-friend class stop_callback;
+friend void
+swap(stop_token& __lhs, stop_token& __rhs) noexcept
+{ __lhs.swap(__rhs); }
 
-struct _Stop_cb {
+  private:
+friend class stop_source;
+template
+  friend class stop_callback;
+
+struct _Stop_cb
+

Re: [PATCH] [MIPS] Prevent MSA branches from being put into delay slots

2019-11-15 Thread Jeff Law
On 11/15/19 10:27 AM, Dragan Mladjenovic wrote:
> From: "Dragan Mladjenovic" 
> 
>  This patch tightens the instruction definitions to make sure
>  that MSA branch instructions cannot be put into delay slots and have their
>  delay slots eligible for being filled. Also, MSA *div*3 patterns use MSA
>  branches for zero checks but are not marked as being multi instruction and
>  thus could be put into delay slots. This patch fixes that.
> 
>  Testcase only covers if MSA branch delay slot is being filled.
> 
> gcc/ChangeLog:
> 
> 2019-11-15  Zoran Jovanovic 
>   Dragan Mladjenovic  
> 
>   * config/mips/mips-msa.md (msa__, 
> msa__v_):
>   Mark as not having "likely" version.
>   * config/mips/mips.md (insn_count): The simd_div instruction with
>   TARGET_CHECK_ZERO_DIV consists of 3 instructions.
>   (can_delay): Exclude simd_branch.
>   (defile_delay *): Add simd_branch instructions.
>   They have one regular delay slot.
OK
jeff



Re: [PATCH] Remove vestiges of MODIFY_JNI_METHOD_CALL

2019-11-15 Thread Jeff Law
On 11/13/19 2:50 PM, Tom Tromey wrote:
> I happened to notice that MODIFY_JNI_METHOD_CALL was defined in
> cygming.h and documented in tm.texi.  However, because it was only
> needed for gcj, it is obsolete.  This patch removes the vestiges.
> 
> Tested by grep, and rebuilding the documentation.
> 
> gcc/ChangeLog
> 2019-11-13  Tom Tromey  
> 
>   * doc/tm.texi: Rebuild.
>   * doc/tm.texi.in (Misc): Don't document MODIFY_JNI_METHOD_CALL.
>   * config/i386/cygming.h (MODIFY_JNI_METHOD_CALL): Don't define.
THanks.  And FWIW removal of this kind of missed stuff shouldn't require
explicit approvals.

jeff



[PATCH] Proposal for IPA init() constant propagation

2019-11-15 Thread erick . ochoa

Hello,

we've been working on an lto optimization and would like to receive some 
feedback on this candidate patch.

At the moment the patch compiles correctly when applied to master.
We have some initial test cases in a separate repository and have 
compiled and ran a small subset of CPU 2017 benchmarks with comparable 
results.


The proposed transformation (ipa-initcall-cp) is a variant of 
interprocedural constant propagation.
ip-initcall-cp collects all variables with static lifetime that contain 
only a single write (like in the cases of initialization functions) and 
propagates it to reads across the whole link unit.


In order to run, apply the patch and compile with `-lto -finitcall-cp`.

In order for this transformation to be sound
* writes that can be reached from a function pointer,
* writes that can be reached from a function with outside visibility, 
and

* writes that may happen after any read
are not taken into account.

In order to determine that no read happens before the write, we have to:
* find the main function
* find the function and basic block of the write
*   for each read in another function
* make sure that call to write dominates all callees of the read 
function

*   for each read in the same function
* make sure that write dominates read

Some initial drawbacks:
* We've noticed that we have to disable ipa-cp in order for 
ipa-initcall-cp to run successfully.
This is most likely due to some issue with clones and we will need to 
make some design changes.

The function materialize all clones fails after ipa-initcall-cp.
Suggestions are welcomed.
* At the moment, I still need to clean the code a bit, since it doesn't 
pass the standards.
* I still need to add tests using the testsuite as opposed to running 
them myself.


Some future work:
* At the moment, ipa-initcall-cp only propagates values from a single 
write.
However, we could conceivably improve this work to propagate the first 
n-writes and specialize functions based on the constants.


Here is a link to the bugzilla ticket: 
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=92538


2019-11-15  Erick Ochoa 

Proposal for IPA init() constant propagation
* gcc/Makefile.in: Add pass to the build process
* gcc/cgraph.c: Add assertion.
* gcc/common.opt: Add pass
* gcc/ipa-initcall-cp.c: new
* gcc/passes.def: Place pass in opt plan
* gcc/tree-pass.h: Add pass

diff --git a/gcc/Makefile.in b/gcc/Makefile.in
index 597dc01..f6b11f7 100644
--- a/gcc/Makefile.in
+++ b/gcc/Makefile.in
@@ -1369,6 +1369,7 @@ OBJS = \
init-regs.o \
internal-fn.o \
ipa-cp.o \
+   ipa-initcall-cp.o \
ipa-devirt.o \
ipa-fnsummary.o \
ipa-polymorphic-call.o \
diff --git a/gcc/cgraph.c b/gcc/cgraph.c
index ea8ab38..e7aa63f 100644
--- a/gcc/cgraph.c
+++ b/gcc/cgraph.c
@@ -3602,6 +3602,8 @@ cgraph_node::get_untransformed_body (void)
   struct lto_in_decl_state *decl_state
 = lto_get_function_in_decl_state (file_data, decl);

+  gcc_assert (decl_state != NULL);
+
   data = lto_get_section_data (file_data, LTO_section_function_body,
   name, , decl_state->compressed);
   if (!data)
diff --git a/gcc/common.opt b/gcc/common.opt
index c160538..31c98f7 100644
--- a/gcc/common.opt
+++ b/gcc/common.opt
@@ -3320,4 +3320,7 @@ fipa-ra
 Common Report Var(flag_ipa_ra) Optimization
 Use caller save register across calls if possible.

+finitcall-cp
+Common Report Var(flag_initcall_cp) TBD.
+
 ; This comment is to ensure we retain the blank line above.
diff --git a/gcc/ipa-initcall-cp.c b/gcc/ipa-initcall-cp.c
new file mode 100644
index 000..b3f8e0a
--- /dev/null
+++ b/gcc/ipa-initcall-cp.c
@@ -0,0 +1,1149 @@
+/* Initcall constant propagation pass.  */
+
+#include "config.h"
+#include "system.h"
+#include "coretypes.h"
+#include "backend.h"
+#include "tree.h"
+#include "gimple.h"
+#include "gimple-expr.h"
+#include "gimple-iterator.h"
+#include "predict.h"
+#include "alloc-pool.h"
+#include "tree-pass.h"
+#include "cgraph.h"
+#include "diagnostic.h"
+#include "fold-const.h"
+#include "gimple-fold.h"
+#include "symbol-summary.h"
+#include "tree-vrp.h"
+#include "ipa-prop.h"
+#include "tree-pretty-print.h"
+#include "tree-inline.h"
+#include "params.h"
+#include "ipa-fnsummary.h"
+#include "ipa-utils.h"
+#include "tree-ssa-ccp.h"
+#include "stringpool.h"
+#include "attribs.h"
+#include "gimple-pretty-print.h"
+#include "ssa.h"
+
+static bool bb1_dominates_bb2 (basic_block bb1, basic_block bb2, 
cgraph_node *cnode);
+static bool write_before_call (struct ipa_ref *write, struct ipa_ref 
*read);
+static bool call_before_read(struct ipa_ref *write, struct ipa_ref 
*read);

+
+static bool
+comdat_can_be_unshared_p_1 (symtab_node *node)
+{
+  if (!node->externally_visible)
+return true;
+  if (node->address_can_be_compared_p ())
+{
+  struct ipa_ref *ref;
+
+  for (unsigned int i = 0; node->iterate_referring (i, 

Re: [PATCH] Split X86_TUNE_AVX128_OPTIMAL into X86_TUNE_AVX256_SPLIT_REGS and X86_TUNE_AVX128_OPTIMAL

2019-11-15 Thread Jeff Law
On 11/14/19 5:21 AM, Richard Biener wrote:
> On Tue, Nov 12, 2019 at 11:35 AM Hongtao Liu  wrote:
>>
>> Hi:
>>   As mentioned in https://gcc.gnu.org/ml/gcc-patches/2019-11/msg00832.html
>>> So yes, it's poorly named.  A preparatory patch to clean this up
>>> (and maybe split it into TARGET_AVX256_SPLIT_REGS and TARGET_AVX128_OPTIMAL)
>>> would be nice.
>>
>>   Bootstrap and regression test for i386 backend is ok.
>>   Ok for trunk?
> 
> It looks OK to me, please let x86 maintainers a day to comment, otherwise OK
I think this fine to go in now.  Uros largely leaves the AVX bits to others.


jeff



Diagnose duplicate C2x standard attributes

2019-11-15 Thread Joseph Myers
For each of the attributes currently included in C2x, it has a
constraint that the attribute shall appear at most once in each
attribute list (attribute-list being what appear between a single [[
and ]]).

This patch implements that check.  As the corresponding check in the
C++ front end (cp_parser_check_std_attribute) makes violations into
errors, I made them into errors, with the same wording, for C as well.

There is an existing check in the case of the fallthrough attribute,
with a warning rather than an error, in attribute_fallthrough_p.  That
is more general, as it also covers __attribute__ ((fallthrough)) and
the case of [[fallthrough]] [[fallthrough]] (multiple attribute-lists
in a single attribute-specifier-sequence), which is not a constraint
violation.  To avoid some [[fallthrough, fallthrough]] being diagnosed
twice, the check I added avoids adding duplicate attributes to the
list.

Bootstrapped with no regressions on x86_64-pc-linux-gnu.  Applied to 
mainline.

gcc/c:
2019-11-15  Joseph Myers  

* c-parser.c (c_parser_std_attribute_specifier): Diagnose
duplicate standard attributes.

gcc/testsuite:
2019-11-15  Joseph Myers  

* gcc.dg/c2x-attr-deprecated-4.c, gcc.dg/c2x-attr-fallthrough-4.c,
gcc.dg/c2x-attr-maybe_unused-4.c: New tests.

Index: gcc/c/c-parser.c
===
--- gcc/c/c-parser.c(revision 278310)
+++ gcc/c/c-parser.c(working copy)
@@ -4873,6 +4873,9 @@ c_parser_std_attribute (c_parser *parser)
 static tree
 c_parser_std_attribute_specifier (c_parser *parser, bool for_tm)
 {
+  bool seen_deprecated = false;
+  bool seen_fallthrough = false;
+  bool seen_maybe_unused = false;
   location_t loc = c_parser_peek_token (parser)->location;
   if (!c_parser_require (parser, CPP_OPEN_SQUARE, "expected %<[%>"))
 return NULL_TREE;
@@ -4898,8 +4901,55 @@ c_parser_std_attribute_specifier (c_parser *parser
   tree attribute = c_parser_std_attribute (parser);
   if (attribute != error_mark_node)
{
- TREE_CHAIN (attribute) = attributes;
- attributes = attribute;
+ bool duplicate = false;
+ tree name = get_attribute_name (attribute);
+ tree ns = get_attribute_namespace (attribute);
+ if (ns == NULL_TREE)
+   {
+ /* Some standard attributes may appear at most once in
+each attribute list.  Diagnose duplicates and remove
+them from the list to avoid subsequent diagnostics
+such as the more general one for multiple
+"fallthrough" attributes in the same place (including
+in separate attribute lists in the same attribute
+specifier sequence, which is not a constraint
+violation).  */
+ if (is_attribute_p ("deprecated", name))
+   {
+ if (seen_deprecated)
+   {
+ error ("attribute % can appear at most "
+"once in an attribute-list");
+ duplicate = true;
+   }
+ seen_deprecated = true;
+   }
+ else if (is_attribute_p ("fallthrough", name))
+   {
+ if (seen_fallthrough)
+   {
+ error ("attribute % can appear at most "
+"once in an attribute-list");
+ duplicate = true;
+   }
+ seen_fallthrough = true;
+   }
+ else if (is_attribute_p ("maybe_unused", name))
+   {
+ if (seen_maybe_unused)
+   {
+ error ("attribute % can appear at most "
+"once in an attribute-list");
+ duplicate = true;
+   }
+ seen_maybe_unused = true;
+   }
+   }
+ if (!duplicate)
+   {
+ TREE_CHAIN (attribute) = attributes;
+ attributes = attribute;
+   }
}
   if (c_parser_next_token_is_not (parser, CPP_COMMA))
break;
Index: gcc/testsuite/gcc.dg/c2x-attr-deprecated-4.c
===
--- gcc/testsuite/gcc.dg/c2x-attr-deprecated-4.c(nonexistent)
+++ gcc/testsuite/gcc.dg/c2x-attr-deprecated-4.c(working copy)
@@ -0,0 +1,13 @@
+/* Test C2x deprecated attribute: duplicates.  */
+/* { dg-do compile } */
+/* { dg-options "-std=c2x -pedantic-errors" } */
+
+[[deprecated, __deprecated__]] int a; /* { dg-error "can appear at most once" 
} */
+[[__deprecated__, deprecated("message")]] int b; /* { dg-error "can appear at 
most once" } */
+int c [[deprecated("message"), deprecated]]; /* { dg-error "can appear at most 
once" } */
+[[deprecated, deprecated]]; /* { dg-error "can appear at most once" } */
+/* { dg-warning 

[PATCH] Only warn for maybe-uninitialized SRAed bits in -Wextra (PR 80635)

2019-11-15 Thread Martin Jambor
Hi,

On Fri, Nov 08 2019, Martin Jambor wrote:
> Hi,
>
> this patch is an attempt to implement my idea from a previous thread
> about moving -Wmaybe-uninitialized to -Wextra:
>
> https://gcc.gnu.org/ml/gcc-patches/2019-02/msg00220.html
>
> Specifically, it attempts to split -Wmaybe-uninitialized into those that
> are about SRA DECLs and those which are not, and move to -Wextra only
> the former ones.  The main idea is that false -Wmaybe-uninitialized
> warings about values that are scalar in user's code are easy to silence
> by initializing them to zero or something, as opposed to bits of
> aggregates such as a value in std::optional which are not.  Therefore,
> the warnings about user-scalars can remain in -Wall but warnings about
> SRAed pieces should be moved to -Wextra.
>

I have not seen any opposition to the idea in principle and so I'd like
to propose it as a patch (as opposed to an RFC) while this stage 1
lasts.

I have also re-based the patch and tried to bootstrap it... and it
failed because of PR 91825.  That bug was fixed by adding

#pragma GCC diagnostic warning "-Wmaybe-uninitialized"

to expmed.c by Jason in r277864 and I of course had to change that to:

#pragma GCC diagnostic warning "-Wmaybe-uninitialized-aggregates"

This episode only reinforced my opinion that maybe-uninitialized
warnings for aggregates are nasty - if even we have to work around them
they should not be part of -Wall.  I would not oppose moving the whole
-Wmaybe-uninitialized as it is now to -Wextra but if we want it to stay
for scalars, I think we need something like the below, which is a
version that did survive a round of bootstrap and testing.

Thanks,

Martin


2019-11-15  Martin Jambor  

* common.opt (Wmaybe-uninitialized-aggregates): New.
* tree-ssa-uninit.c (gate_warn_uninitialized): Also run if
warn_maybe_uninitialized_aggregates is set.
(warn_uninit): Warn for artificial DECLs only if
warn_maybe_uninitialized_aggregates is set.
* doc/invoke.texi (Warning Options): Add
-Wmaybe-uninitialized-aggregates to the list.
(-Wextra): Likewise.
(-Wmaybe-uninitialized): Document that it only works on scalars.
(-Wmaybe-uninitialized-aggregates): Document.
* expmed.c: Change GCC diagnostic warning to
-Wmaybe-uninitialized-aggregates

testsuite/
* gcc.dg/pr45083.c: Add Wmaybe-uninitialized-aggregates to options.
* gcc.dg/ubsan/pr81981.c: Likewise.
* gfortran.dg/pr25923.f90: Likewise.
* g++.dg/warn/pr80635.C: New.
---
 gcc/common.opt|  4 +++
 gcc/doc/invoke.texi   | 18 +--
 gcc/expmed.c  |  2 +-
 gcc/testsuite/g++.dg/warn/pr80635.C   | 45 +++
 gcc/testsuite/gcc.dg/pr45083.c|  2 +-
 gcc/testsuite/gcc.dg/ubsan/pr81981.c  |  2 +-
 gcc/testsuite/gfortran.dg/pr25923.f90 |  2 +-
 gcc/tree-ssa-uninit.c | 14 -
 8 files changed, 82 insertions(+), 7 deletions(-)
 create mode 100644 gcc/testsuite/g++.dg/warn/pr80635.C

diff --git a/gcc/common.opt b/gcc/common.opt
index 12c0083964e..212e55f88c7 100644
--- a/gcc/common.opt
+++ b/gcc/common.opt
@@ -783,6 +783,10 @@ Wmaybe-uninitialized
 Common Var(warn_maybe_uninitialized) Warning EnabledBy(Wuninitialized)
 Warn about maybe uninitialized automatic variables.
 
+Wmaybe-uninitialized-aggregates
+Common Var(warn_maybe_uninitialized_aggregates) Warning EnabledBy(Wextra)
+Warn about maybe uninitialized automatic parts of aggregates.
+
 Wunreachable-code
 Common Ignore Warning
 Does nothing. Preserved for backward compatibility.
diff --git a/gcc/doc/invoke.texi b/gcc/doc/invoke.texi
index 00eb7e77808..60612271eed 100644
--- a/gcc/doc/invoke.texi
+++ b/gcc/doc/invoke.texi
@@ -328,7 +328,8 @@ Objective-C and Objective-C++ Dialects}.
 -Wzero-length-bounds @gol
 -Winvalid-pch  -Wlarger-than=@var{byte-size} @gol
 -Wlogical-op  -Wlogical-not-parentheses  -Wlong-long @gol
--Wmain  -Wmaybe-uninitialized  -Wmemset-elt-size  -Wmemset-transposed-args @gol
+-Wmain  -Wmaybe-uninitialized -Wmaybe-uninitialized-aggregates @gol
+-Wmemset-elt-size  -Wmemset-transposed-args @gol
 -Wmisleading-indentation  -Wmissing-attributes  -Wmissing-braces @gol
 -Wmissing-field-initializers  -Wmissing-format-attribute @gol
 -Wmissing-include-dirs  -Wmissing-noreturn  -Wmissing-profile @gol
@@ -4503,6 +4504,7 @@ name is still supported, but the newer name is more 
descriptive.)
 -Wempty-body  @gol
 -Wignored-qualifiers @gol
 -Wimplicit-fallthrough=3 @gol
+-Wmaybe-uninitialized-aggregates @gol
 -Wmissing-field-initializers  @gol
 -Wmissing-parameter-type @r{(C only)}  @gol
 -Wold-style-declaration @r{(C only)}  @gol
@@ -5695,10 +5697,22 @@ in fact be called at the place that would cause a 
problem.
 
 Some spurious warnings can be avoided if you declare all the functions
 you use that never return as @code{noreturn}.  @xref{Function
-Attributes}.
+Attributes}.  This 

[RFC PATCH] cgraph support for late declare variant resolution

2019-11-15 Thread Jakub Jelinek
Hi!

The following patch is a so far non-working attempt at
#pragma omp declare variant
late resolution.
To sum up, during gimplification we resolve direct calls to their
variants whenever possible.
There can be some cases that can't be resolved at that point yet,
e.g. whether some context depends on if the function will be
a declare simd clone or not (only created during IPA), or if
it depends on whether it will be offloaded or not (also split
during IPA).
This patch creates a dummy static function that is made noipa,
has error_mark_node body so we don't try to do anything with it
and attaches to it control structures that contain the possible
variants together with their scores, has node->declare_variant_alt
flag set on it and rebuilding of cgraph edges sets
caller->declare_variant_alt for anything that calls such functions,
so that post IPA we can decide.
LTO streaming of this isn't implemented yet.
As discussed on IRC, the extra payload, which is quite rare, is not added to
cgraph_node, only 2 bits are actually used there, the rest is in an on the
side hash table.  I haven't used function_summary for that, because a
simple hash table looked simpler.

I was hoping that the
   (*slot)->node->create_reference (varentry->variant, IPA_REF_ADDR);
calls would make sure that the variant cgraph_nodes are considered needed,
but apparently they are removed.

The structures could be perhaps moved to cgraph.h and omp-general.c
could have a function to look it up in the hash table, if cgraph code would
need to access the variants for some reason.

Testcase I was using (-O2 -fopenmp -mno-sse3):
/* { dg-do compile { target vect_simd_clones } } */
/* { dg-additional-options "-mno-sse3" { target { i?86-*-* x86_64-*-* } } } */

int f01 (int);
int f02 (int);
int f03 (int);
#pragma omp declare variant (f01) match (device={isa("avx512f")}) /* 4 or 8 */
#pragma omp declare variant (f02) match 
(implementation={vendor(score(3):gnu)},device={kind(cpu)}) /* (1 or 2) + 3 */
#pragma omp declare variant (f03) match 
(implementation={vendor(score(5):gnu)},device={kind(host)}) /* (1 or 2) + 5 */
int f04 (int x) { return x; }

#pragma omp declare simd
int
test1 (int x)
{
  int a = f04 (x);
  int b = f04 (x);
  return a + b;
}
where I'd like to see test1 calling f03 with score 1 + 5 + 1, most of the
test1.simdclone.* (the non-avx512f ones) also f03 with score 2 + 5 + 1
and the last two test1.simdclone.* (avx512f ones) f01 (score 8 + 1).
But the f01/f02/f03 cgraph_nodes are removed and in their place there are
test1.simdclone.* cgraph nodes.

Though on this?  Any other comments?

--- gcc/cgraph.c.jj 2019-11-13 10:54:45.283048134 +0100
+++ gcc/cgraph.c2019-11-15 22:10:58.845671689 +0100
@@ -890,6 +890,7 @@ symbol_table::create_edge (cgraph_node *
  caller->decl);
   else
 edge->in_polymorphic_cdtor = caller->thunk.thunk_p;
+  caller->calls_declare_variant_alt |= callee->declare_variant_alt;
 
   return edge;
 }
--- gcc/Makefile.in.jj  2019-11-14 01:20:24.735562492 +0100
+++ gcc/Makefile.in 2019-11-15 15:41:59.908723643 +0100
@@ -2577,6 +2577,7 @@ GTFILES = $(CPPLIB_H) $(srcdir)/input.h
   $(srcdir)/omp-offload.h \
   $(srcdir)/omp-offload.c \
   $(srcdir)/omp-expand.c \
+  $(srcdir)/omp-general.c \
   $(srcdir)/omp-low.c \
   $(srcdir)/targhooks.c $(out_file) $(srcdir)/passes.c $(srcdir)/cgraphunit.c \
   $(srcdir)/cgraphclones.c \
--- gcc/omp-offload.c.jj2019-09-26 22:02:53.737255157 +0200
+++ gcc/omp-offload.c   2019-11-15 22:44:07.925718820 +0100
@@ -1893,12 +1893,28 @@ execute_omp_device_lower ()
   bool regimplify = false;
   basic_block bb;
   gimple_stmt_iterator gsi;
+  bool calls_declare_variant_alt
+= cgraph_node::get (cfun->decl)->calls_declare_variant_alt;
   FOR_EACH_BB_FN (bb, cfun)
 for (gsi = gsi_start_bb (bb); !gsi_end_p (gsi); gsi_next ())
   {
gimple *stmt = gsi_stmt (gsi);
-   if (!is_gimple_call (stmt) || !gimple_call_internal_p (stmt))
+   if (!is_gimple_call (stmt))
  continue;
+   if (!gimple_call_internal_p (stmt))
+ {
+   if (calls_declare_variant_alt)
+ if (tree fndecl = gimple_call_fndecl (stmt))
+   {
+ tree new_fndecl = omp_resolve_declare_variant (fndecl);
+ if (new_fndecl != fndecl)
+   {
+ gimple_call_set_fndecl (stmt, new_fndecl);
+ update_stmt (stmt);
+   }
+   }
+   continue;
+ }
tree lhs = gimple_call_lhs (stmt), rhs = NULL_TREE;
tree type = lhs ? TREE_TYPE (lhs) : integer_type_node;
switch (gimple_call_internal_fn (stmt))
@@ -1992,7 +2008,9 @@ public:
   /* opt_pass methods: */
   virtual bool gate (function *fun)
 {
-  return !(fun->curr_properties & PROP_gimple_lomp_dev);
+  return (!(fun->curr_properties & PROP_gimple_lomp_dev)
+ || (flag_openmp
+ && 

Re: [PATCH 0/4] Eliminate cc0 from m68k

2019-11-15 Thread Andreas Schwab
On Nov 15 2019, Bernd Schmidt wrote:

> I meant the compiler command line of course... for any -mcpu flags that
> might differ from my test run.

There are none.

Andreas.

-- 
Andreas Schwab, sch...@linux-m68k.org
GPG Key fingerprint = 7578 EB47 D4E5 4D69 2510  2552 DF73 E780 A9DA AEC1
"And now for something completely different."


Re: introduce -fcallgraph-info option

2019-11-15 Thread Alexandre Oliva
On Nov 15, 2019, Richard Biener  wrote:

> Hmm, -dwo-base-name to the rescue? ;)

I'd rather have less rather than more complexity.  I.e., make the
objcopy command match the dumpdir location, that defaults to the output
location.  The more such options we have, the harder it is to document,
understand, and implement correctly.

> so all that is needed is to keep that consistent?

*nod*

-- 
Alexandre Oliva, freedom fighter   he/him   https://FSFLA.org/blogs/lxo
Free Software Evangelist   Stallman was right, but he's left :(
GNU Toolchain EngineerFSMatrix: It was he who freed the first of us
FSF & FSFLA board memberThe Savior shall return (true);


Re: [PATCH 0/4] Eliminate cc0 from m68k

2019-11-15 Thread Bernd Schmidt
On 11/15/19 10:58 PM, Andreas Schwab wrote:
> On Nov 15 2019, Bernd Schmidt wrote:
> 
>> Any chance you could show the command lines from the log files or some
>> other way of reproducing the issue?
> 
> Executing on aranym: OMP_NUM_THREADS=2 
> LD_LIBRARY_PATH=.:/daten/aranym/gcc/gcc-20191115/Build/m68k-linux/./libstdc++-v3/src/.libs:/daten/aranym/gcc/gcc-20191115/Build/m68k-linux/./libstdc++-v3/src/.libs:/daten/aranym/gcc/gcc-20191115/Build/gcc:/daten/aranym/gcc/gcc-20191115/Build/gcc
>  timeout 1200 ./dyncast1.exe (timeout = 300)
> Executed ./dyncast1.exe, status 1
> Output: Error 25
> child process exited abnormally
> FAIL: g++.old-deja/g++.other/dyncast1.C  -std=c++17 execution test

I meant the compiler command line of course... for any -mcpu flags that
might differ from my test run.


Bernd


Re: [PATCH 0/4] Eliminate cc0 from m68k

2019-11-15 Thread Andreas Schwab
On Nov 15 2019, Bernd Schmidt wrote:

> Any chance you could show the command lines from the log files or some
> other way of reproducing the issue?

Executing on aranym: OMP_NUM_THREADS=2 
LD_LIBRARY_PATH=.:/daten/aranym/gcc/gcc-20191115/Build/m68k-linux/./libstdc++-v3/src/.libs:/daten/aranym/gcc/gcc-20191115/Build/m68k-linux/./libstdc++-v3/src/.libs:/daten/aranym/gcc/gcc-20191115/Build/gcc:/daten/aranym/gcc/gcc-20191115/Build/gcc
 timeout 1200 ./dyncast1.exe (timeout = 300)
Executed ./dyncast1.exe, status 1
Output: Error 25
child process exited abnormally
FAIL: g++.old-deja/g++.other/dyncast1.C  -std=c++17 execution test

Andreas.

-- 
Andreas Schwab, sch...@linux-m68k.org
GPG Key fingerprint = 7578 EB47 D4E5 4D69 2510  2552 DF73 E780 A9DA AEC1
"And now for something completely different."


[PATCH 13/13] Enable worker partitioning for AMD GCN

2019-11-15 Thread Julian Brown
This patch flips the switch to enable worker partitioning on AMD GCN.

OK?

Thanks,

Julian

ChangeLog

gcc/
* config/gcn/gcn.c (gcn_goacc_validate_dims): Remove
no-flag_worker-partitioning assertion.
(TARGET_GOACC_WORKER_PARTITIONING): Define target hook to true.
* config/gcn/gcn.opt (flag_worker_partitioning): Change default to 1.

libgomp/
* plugin/plugin-gcn.c (gcn_exec): Change default number of workers to
16.
---
 gcc/config/gcn/gcn.c| 4 ++--
 gcc/config/gcn/gcn.opt  | 2 +-
 libgomp/plugin/plugin-gcn.c | 4 +---
 3 files changed, 4 insertions(+), 6 deletions(-)

diff --git a/gcc/config/gcn/gcn.c b/gcc/config/gcn/gcn.c
index 3584ac85021..6e45032ea3a 100644
--- a/gcc/config/gcn/gcn.c
+++ b/gcc/config/gcn/gcn.c
@@ -4692,8 +4692,6 @@ gcn_goacc_validate_dims (tree decl, int dims[], int 
fn_level,
   /* FIXME: remove -facc-experimental-workers when they're ready.  */
   int max_workers = flag_worker_partitioning ? 16 : 1;
 
-  gcc_assert (!flag_worker_partitioning);
-
   /* The vector size must appear to be 64, to the user, unless this is a
  SEQ routine.  The real, internal value is always 1, which means use
  autovectorization, but the user should not see that.  */
@@ -6072,6 +6070,8 @@ print_operand (FILE *file, rtx x, int code)
 #define TARGET_GOACC_REDUCTION gcn_goacc_reduction
 #undef  TARGET_GOACC_VALIDATE_DIMS
 #define TARGET_GOACC_VALIDATE_DIMS gcn_goacc_validate_dims
+#undef  TARGET_GOACC_WORKER_PARTITIONING
+#define TARGET_GOACC_WORKER_PARTITIONING true
 #undef  TARGET_HARD_REGNO_MODE_OK
 #define TARGET_HARD_REGNO_MODE_OK gcn_hard_regno_mode_ok
 #undef  TARGET_HARD_REGNO_NREGS
diff --git a/gcc/config/gcn/gcn.opt b/gcc/config/gcn/gcn.opt
index 402deb625bd..bdc878f35ad 100644
--- a/gcc/config/gcn/gcn.opt
+++ b/gcc/config/gcn/gcn.opt
@@ -65,7 +65,7 @@ Target Report RejectNegative Var(flag_bypass_init_error)
 bool flag_worker_partitioning = false
 
 macc-experimental-workers
-Target Report Var(flag_worker_partitioning) Init(0)
+Target Report Var(flag_worker_partitioning) Init(1)
 
 int stack_size_opt = -1
 
diff --git a/libgomp/plugin/plugin-gcn.c b/libgomp/plugin/plugin-gcn.c
index c4347dfa45d..3368d7e261a 100644
--- a/libgomp/plugin/plugin-gcn.c
+++ b/libgomp/plugin/plugin-gcn.c
@@ -3097,10 +3097,8 @@ gcn_exec (struct kernel_info *kernel, size_t mapnum, 
void **hostaddrs,
  problem size, so let's do a reasonable number of single-worker gangs.
  64 gangs matches a typical Fiji device.  */
 
-  /* NOTE: Until support for middle-end worker partitioning is merged, use 1
- for the default number of workers.  */
   if (dims[0] == 0) dims[0] = get_cu_count (kernel->agent); /* Gangs.  */
-  if (dims[1] == 0) dims[1] = 1;  /* Workers.  */
+  if (dims[1] == 0) dims[1] = 16;  /* Workers.  */
 
   /* The incoming dimensions are expressed in terms of gangs, workers, and
  vectors.  The HSA dimensions are expressed in terms of "work-items",
-- 
2.23.0



[PATCH 12/13] Fix parallel-dims.f90 for AMD GCN

2019-11-15 Thread Julian Brown
This patch provides AMD GCN support for the parallel-dims.f90 test's
parallel-dims-aux.c helper.

OK?

Thanks,

Julian

ChangeLog

libgomp/
* testsuite/libgomp.oacc-fortran/parallel-dims-aux.c: Support AMD GCN.
---
 .../testsuite/libgomp.oacc-fortran/parallel-dims-aux.c   | 9 ++---
 1 file changed, 6 insertions(+), 3 deletions(-)

diff --git a/libgomp/testsuite/libgomp.oacc-fortran/parallel-dims-aux.c 
b/libgomp/testsuite/libgomp.oacc-fortran/parallel-dims-aux.c
index b5986f4afef..0778081860f 100644
--- a/libgomp/testsuite/libgomp.oacc-fortran/parallel-dims-aux.c
+++ b/libgomp/testsuite/libgomp.oacc-fortran/parallel-dims-aux.c
@@ -16,7 +16,8 @@
 {
   if (acc_on_device ((int) acc_device_host))
 return 0;
-  else if (acc_on_device ((int) acc_device_nvidia))
+  else if (acc_on_device ((int) acc_device_nvidia)
+  || acc_on_device ((int) acc_device_gcn))
 return __builtin_goacc_parlevel_id (GOMP_DIM_GANG);
   else
 __builtin_abort ();
@@ -27,7 +28,8 @@
 {
   if (acc_on_device ((int) acc_device_host))
 return 0;
-  else if (acc_on_device ((int) acc_device_nvidia))
+  else if (acc_on_device ((int) acc_device_nvidia)
+  || acc_on_device ((int) acc_device_gcn))
 return __builtin_goacc_parlevel_id (GOMP_DIM_WORKER);
   else
 __builtin_abort ();
@@ -38,7 +40,8 @@
 {
   if (acc_on_device ((int) acc_device_host))
 return 0;
-  else if (acc_on_device ((int) acc_device_nvidia))
+  else if (acc_on_device ((int) acc_device_nvidia)
+  || acc_on_device ((int) acc_device_gcn))
 return __builtin_goacc_parlevel_id (GOMP_DIM_VECTOR);
   else
 __builtin_abort ();
-- 
2.23.0



[PATCH 11/13] AMD GCN symbol output with null cfun

2019-11-15 Thread Julian Brown
This patch checks that cfun is valid in the gcn_asm_output_symbol_ref
function. This prevents a crash when that function is called with NULL
cfun, i.e. when outputting debug symbols.

OK?

Thanks,

Julian

ChangeLog

gcc/
* config/gcn/gcn.c (gcn_asm_output_symbol_ref): Handle null cfun.
---
 gcc/config/gcn/gcn.c | 6 --
 1 file changed, 4 insertions(+), 2 deletions(-)

diff --git a/gcc/config/gcn/gcn.c b/gcc/config/gcn/gcn.c
index 2f758ef3ddc..3584ac85021 100644
--- a/gcc/config/gcn/gcn.c
+++ b/gcc/config/gcn/gcn.c
@@ -5199,7 +5199,8 @@ void
 gcn_asm_output_symbol_ref (FILE *file, rtx x)
 {
   tree decl;
-  if ((decl = SYMBOL_REF_DECL (x)) != 0
+  if (cfun
+  && (decl = SYMBOL_REF_DECL (x)) != 0
   && TREE_CODE (decl) == VAR_DECL
   && AS_LDS_P (TYPE_ADDR_SPACE (TREE_TYPE (decl
 {
@@ -5214,7 +5215,8 @@ gcn_asm_output_symbol_ref (FILE *file, rtx x)
 {
   assemble_name (file, XSTR (x, 0));
   /* FIXME: See above -- this condition is unreachable.  */
-  if ((decl = SYMBOL_REF_DECL (x)) != 0
+  if (cfun
+ && (decl = SYMBOL_REF_DECL (x)) != 0
  && TREE_CODE (decl) == VAR_DECL
  && AS_LDS_P (TYPE_ADDR_SPACE (TREE_TYPE (decl
fputs ("@abs32", file);
-- 
2.23.0



[PATCH 10/13] Race conditions in OpenACC async tests

2019-11-15 Thread Julian Brown
This patch provides some race-condition fixes for tests that broke
for AMD GCN.

OK?

Thanks,

Julian

ChangeLog

libgomp/
* testsuite/libgomp.oacc-c-c++-common/lib-94.c: Fix race condition.
* testsuite/libgomp.oacc-fortran/lib-16-2.f90: Likewise.
---
 libgomp/testsuite/libgomp.oacc-c-c++-common/lib-94.c | 4 ++--
 libgomp/testsuite/libgomp.oacc-fortran/lib-16-2.f90  | 5 +
 2 files changed, 7 insertions(+), 2 deletions(-)

diff --git a/libgomp/testsuite/libgomp.oacc-c-c++-common/lib-94.c 
b/libgomp/testsuite/libgomp.oacc-c-c++-common/lib-94.c
index 54497237b0c..baa3ac83f04 100644
--- a/libgomp/testsuite/libgomp.oacc-c-c++-common/lib-94.c
+++ b/libgomp/testsuite/libgomp.oacc-c-c++-common/lib-94.c
@@ -22,10 +22,10 @@ main (int argc, char **argv)
 
   acc_copyin_async (h, N, async);
 
-  memset (h, 0, N);
-
   acc_wait (async);
 
+  memset (h, 0, N);
+
   acc_copyout_async (h, N, async + 1);
 
   acc_wait (async + 1);
diff --git a/libgomp/testsuite/libgomp.oacc-fortran/lib-16-2.f90 
b/libgomp/testsuite/libgomp.oacc-fortran/lib-16-2.f90
index ddd557d3be0..e2e47c967fa 100644
--- a/libgomp/testsuite/libgomp.oacc-fortran/lib-16-2.f90
+++ b/libgomp/testsuite/libgomp.oacc-fortran/lib-16-2.f90
@@ -27,6 +27,9 @@ program main
 
   if (acc_is_present (h) .neqv. .TRUE.) stop 1
 
+  ! We must wait for the update to be done.
+  call acc_wait (async)
+
   h(:) = 0
 
   call acc_copyout_async (h, sizeof (h), async)
@@ -45,6 +48,8 @@ program main
   
   if (acc_is_present (h) .neqv. .TRUE.) stop 3
 
+  call acc_wait (async)
+
   do i = 1, N
 if (h(i) /= i + i) stop 4
   end do 
-- 
2.23.0



[PATCH 09/13] AMD GCN libgomp plugin queue-full condition locking fix

2019-11-15 Thread Julian Brown
This patch corrects a possible race condition in locking for the
asynchronous queue-full condition check in the AMD GCN libgomp plugin.

OK?

Julian

ChangeLog

libgomp/
* plugin/plugin-gcn.c (wait_for_queue_nonfull): Don't lock/unlock
aq->mutex here.
(queue_push_launch): Lock aq->mutex before calling
wait_for_queue_nonfull.
(queue_push_callback): Likewise.
(queue_push_asyncwait): Likewise.
(queue_push_placeholder): Likewise.
---
 libgomp/plugin/plugin-gcn.c | 20 
 1 file changed, 8 insertions(+), 12 deletions(-)

diff --git a/libgomp/plugin/plugin-gcn.c b/libgomp/plugin/plugin-gcn.c
index eb016e3fcd6..c4347dfa45d 100644
--- a/libgomp/plugin/plugin-gcn.c
+++ b/libgomp/plugin/plugin-gcn.c
@@ -2732,13 +2732,9 @@ wait_for_queue_nonfull (struct goacc_asyncqueue *aq)
 {
   if (aq->queue_n == ASYNC_QUEUE_SIZE)
 {
-  pthread_mutex_lock (>mutex);
-
   /* Queue is full.  Wait for it to not be full.  */
   while (aq->queue_n == ASYNC_QUEUE_SIZE)
pthread_cond_wait (>queue_cond_out, >mutex);
-
-  pthread_mutex_unlock (>mutex);
 }
 }
 
@@ -2752,10 +2748,10 @@ queue_push_launch (struct goacc_asyncqueue *aq, struct 
kernel_info *kernel,
 {
   assert (aq->agent == kernel->agent);
 
-  wait_for_queue_nonfull (aq);
-
   pthread_mutex_lock (>mutex);
 
+  wait_for_queue_nonfull (aq);
+
   int queue_last = ((aq->queue_first + aq->queue_n)
% ASYNC_QUEUE_SIZE);
   if (DEBUG_QUEUES)
@@ -2785,10 +2781,10 @@ static void
 queue_push_callback (struct goacc_asyncqueue *aq, void (*fn)(void *),
 void *data)
 {
-  wait_for_queue_nonfull (aq);
-
   pthread_mutex_lock (>mutex);
 
+  wait_for_queue_nonfull (aq);
+
   int queue_last = ((aq->queue_first + aq->queue_n)
% ASYNC_QUEUE_SIZE);
   if (DEBUG_QUEUES)
@@ -2818,10 +2814,10 @@ static void
 queue_push_asyncwait (struct goacc_asyncqueue *aq,
  struct placeholder *placeholderp)
 {
-  wait_for_queue_nonfull (aq);
-
   pthread_mutex_lock (>mutex);
 
+  wait_for_queue_nonfull (aq);
+
   int queue_last = ((aq->queue_first + aq->queue_n) % ASYNC_QUEUE_SIZE);
   if (DEBUG_QUEUES)
 GCN_DEBUG ("queue_push_asyncwait %d:%d: at %i\n", aq->agent->device_id,
@@ -2849,10 +2845,10 @@ queue_push_placeholder (struct goacc_asyncqueue *aq)
 {
   struct placeholder *placeholderp;
 
-  wait_for_queue_nonfull (aq);
-
   pthread_mutex_lock (>mutex);
 
+  wait_for_queue_nonfull (aq);
+
   int queue_last = ((aq->queue_first + aq->queue_n) % ASYNC_QUEUE_SIZE);
   if (DEBUG_QUEUES)
 GCN_DEBUG ("queue_push_placeholder %d:%d: at %i\n", aq->agent->device_id,
-- 
2.23.0



[PATCH 08/13] Fix host-to-device copies from rodata for AMD GCN

2019-11-15 Thread Julian Brown
It appears that the hsa_memory_copy API routine
has problems copying from read-only data: in the
libgomp/testsuite/libgomp.oacc-c-c++-common/reduction-8.c test, a "const"
variable cannot be successfully copied to the target. I think the problem
is with read-only page mappings (in the HSA runtime). Luckily (?), if
the copy fails, the API call fails with a HSA_STATUS_ERROR return code,
which we can detect and use to trigger a workaround.

I've also added return-code checks to several other uses of the
hsa_memory_copy API routine, in an attempt to avoid silent runtime
failures. (A previous fix for a similar problem, removed before upstream
submission, does not appear to apply to this exact situation.)

OK?

Julian

ChangeLog

libgomp/
* plugin/plugin-gcn.c (hsa_memory_copy_wrapper): New.
(copy_data, GOMP_OFFLOAD_host2dev): Use above function.
(GOMP_OFFLOAD_dev2host, GOMP_OFFLOAD_dev2dev): Check hsa_memory_copy
return code.
---
 libgomp/plugin/plugin-gcn.c | 35 +++
 1 file changed, 31 insertions(+), 4 deletions(-)

diff --git a/libgomp/plugin/plugin-gcn.c b/libgomp/plugin/plugin-gcn.c
index 7b95a4cef8f..eb016e3fcd6 100644
--- a/libgomp/plugin/plugin-gcn.c
+++ b/libgomp/plugin/plugin-gcn.c
@@ -2940,6 +2940,29 @@ maybe_init_omp_async (struct agent_info *agent)
   = GOMP_OFFLOAD_openacc_async_construct (agent->device_id);
 }
 
+/* A wrapper that works around an issue in the HSA runtime with host-to-device
+   copies from read-only pages.  */
+
+static void
+hsa_memory_copy_wrapper (void *dst, const void *src, size_t len)
+{
+  hsa_status_t status = hsa_fns.hsa_memory_copy_fn (dst, src, len);
+
+  if (status == HSA_STATUS_SUCCESS)
+return;
+
+  /* It appears that the copy fails if the source data is in a read-only page.
+ We can't detect that easily, so try copying the data to a temporary buffer
+ and doing the copy again if we got an error above.  */
+
+  void *src_copy = malloc (len);
+  memcpy (src_copy, src, len);
+  status = hsa_fns.hsa_memory_copy_fn (dst, (const void *) src_copy, len);
+  free (src_copy);
+  if (status != HSA_STATUS_SUCCESS)
+GOMP_PLUGIN_error ("memory copy failed");
+}
+
 /* Copy data to or from a device.  This is intended for use as an async
callback event.  */
 
@@ -2950,7 +2973,7 @@ copy_data (void *data_)
   GCN_DEBUG ("Async thread %d:%d: Copying %zu bytes from (%p) to (%p)\n",
 data->aq->agent->device_id, data->aq->id, data->len, data->src,
 data->dst);
-  hsa_fns.hsa_memory_copy_fn (data->dst, data->src, data->len);
+  hsa_memory_copy_wrapper (data->dst, data->src, data->len);
   if (data->free_src)
 free ((void *) data->src);
   free (data);
@@ -3643,7 +3666,9 @@ GOMP_OFFLOAD_dev2host (int device, void *dst, const void 
*src, size_t n)
 {
   GCN_DEBUG ("Copying %zu bytes from device %d (%p) to host (%p)\n", n, device,
 src, dst);
-  hsa_fns.hsa_memory_copy_fn (dst, src, n);
+  hsa_status_t status = hsa_fns.hsa_memory_copy_fn (dst, src, n);
+  if (status != HSA_STATUS_SUCCESS)
+GOMP_PLUGIN_error ("memory copy failed");
   return true;
 }
 
@@ -3654,7 +3679,7 @@ GOMP_OFFLOAD_host2dev (int device, void *dst, const void 
*src, size_t n)
 {
   GCN_DEBUG ("Copying %zu bytes from host (%p) to device %d (%p)\n", n, src,
 device, dst);
-  hsa_fns.hsa_memory_copy_fn (dst, src, n);
+  hsa_memory_copy_wrapper (dst, src, n);
   return true;
 }
 
@@ -3675,7 +3700,9 @@ GOMP_OFFLOAD_dev2dev (int device, void *dst, const void 
*src, size_t n)
 
   GCN_DEBUG ("Copying %zu bytes from device %d (%p) to device %d (%p)\n", n,
 device, src, device, dst);
-  hsa_fns.hsa_memory_copy_fn (dst, src, n);
+  hsa_status_t status = hsa_fns.hsa_memory_copy_fn (dst, src, n);
+  if (status != HSA_STATUS_SUCCESS)
+GOMP_PLUGIN_error ("memory copy failed");
   return true;
 }
 
-- 
2.23.0



[PATCH 07/13] Fix OpenACC "ephemeral" asynchronous host-to-device copies

2019-11-15 Thread Julian Brown
The AMD GCN runtime support appears to exercise asynchronous operations
more heavily than other offload targets. As such, latent problems with
asynchronous host-to-device copies have come to light with GCN. This
patch provides a solution to those.

Previously posted for the og9 branch (with some rationale) here:

https://gcc.gnu.org/ml/gcc-patches/2019-09/msg01026.html

This patch implies an ABI change for
GOMP_OFFLOAD_openacc_async_host2dev. I'm not sure what our policy is
there: do we need to introduce a new "v2" plugin entry point?

OK?

Julian

ChangeLog

libgomp/
* libgomp-plugin.h (GOMP_OFFLOAD_openacc_async_host2dev): Update
prototype.
* libgomp.h (gomp_copy_host2dev): Update prototype.
* oacc-host.c (host_openacc_async_host2dev): Add ephemeral parameter.
* oacc-mem.c (memcpy_tofrom_device): Update call to gomp_copy_host2dev.
(update_dev_host): Likewise.
* plugin/plugin-gcn.c (GOMP_OFFLOAD_openacc_async_host2dev): Handle
ephemeral host-to-device copies.
* plugin/plugin-nvptx.c (GOMP_OFFLOAD_openacc_async_host2dev):
Add EPHEMERAL parameter, and FIXME function comment.
* target.c (goacc_device_copy_async): Remove.
(gomp_copy_host2dev): Add ephemeral parameter. Update function comment.
Call async host2dev plugin hook directly.
(gomp_copy_dev2host): Call async dev2host plugin hook directly.
(gomp_map_vars_existing, gomp_map_pointer): Update calls to
gomp_copy_host2dev.
(gomp_map_vars_internal): Don't use coalescing buffer for asynchronous
copies. Update calls to gomp_copy_host2dev.
(gomp_update): Update calls to gomp_copy_host2dev.
---
 libgomp/libgomp-plugin.h  |  3 +-
 libgomp/libgomp.h |  2 +-
 libgomp/oacc-host.c   |  1 +
 libgomp/oacc-mem.c|  4 +-
 libgomp/plugin/plugin-gcn.c   | 23 +
 libgomp/plugin/plugin-nvptx.c | 13 -
 libgomp/target.c  | 92 +++
 7 files changed, 82 insertions(+), 56 deletions(-)

diff --git a/libgomp/libgomp-plugin.h b/libgomp/libgomp-plugin.h
index 037558c43f5..200f3b594ee 100644
--- a/libgomp/libgomp-plugin.h
+++ b/libgomp/libgomp-plugin.h
@@ -126,7 +126,8 @@ extern void GOMP_OFFLOAD_openacc_async_exec (void (*) (void 
*), size_t, void **,
 struct goacc_asyncqueue *);
 extern bool GOMP_OFFLOAD_openacc_async_dev2host (int, void *, const void *, 
size_t,
 struct goacc_asyncqueue *);
-extern bool GOMP_OFFLOAD_openacc_async_host2dev (int, void *, const void *, 
size_t,
+extern bool GOMP_OFFLOAD_openacc_async_host2dev (int, void *, const void *,
+size_t, bool,
 struct goacc_asyncqueue *);
 extern void *GOMP_OFFLOAD_openacc_cuda_get_current_device (void);
 extern void *GOMP_OFFLOAD_openacc_cuda_get_current_context (void);
diff --git a/libgomp/libgomp.h b/libgomp/libgomp.h
index 7b46e0a494d..65fa390f4a5 100644
--- a/libgomp/libgomp.h
+++ b/libgomp/libgomp.h
@@ -1153,7 +1153,7 @@ extern void gomp_acc_declare_allocate (bool, size_t, void 
**, size_t *,
 struct gomp_coalesce_buf;
 extern void gomp_copy_host2dev (struct gomp_device_descr *,
struct goacc_asyncqueue *, void *, const void *,
-   size_t, struct gomp_coalesce_buf *);
+   size_t, bool, struct gomp_coalesce_buf *);
 extern void gomp_copy_dev2host (struct gomp_device_descr *,
struct goacc_asyncqueue *, void *, const void *,
size_t);
diff --git a/libgomp/oacc-host.c b/libgomp/oacc-host.c
index cbcac9bf7b3..bc11770725d 100644
--- a/libgomp/oacc-host.c
+++ b/libgomp/oacc-host.c
@@ -184,6 +184,7 @@ host_openacc_async_host2dev (int ord __attribute__ 
((unused)),
 void *dst __attribute__ ((unused)),
 const void *src __attribute__ ((unused)),
 size_t n __attribute__ ((unused)),
+bool eph __attribute__ ((unused)),
 struct goacc_asyncqueue *aq
 __attribute__ ((unused)))
 {
diff --git a/libgomp/oacc-mem.c b/libgomp/oacc-mem.c
index 2f271009fb8..240ebc5c865 100644
--- a/libgomp/oacc-mem.c
+++ b/libgomp/oacc-mem.c
@@ -205,7 +205,7 @@ memcpy_tofrom_device (bool from, void *d, void *h, size_t 
s, int async,
   if (from)
 gomp_copy_dev2host (thr->dev, aq, h, d, s);
   else
-gomp_copy_host2dev (thr->dev, aq, d, h, s, /* TODO: cbuf? */ NULL);
+gomp_copy_host2dev (thr->dev, aq, d, h, s, false, /* TODO: cbuf? */ NULL);
 
   if (profiling_p)
 {
@@ -856,7 +856,7 @@ update_dev_host (int is_dev, void *h, size_t s, int async)
   goacc_aq aq = get_goacc_asyncqueue (async);
 
   if (is_dev)

[PATCH 04/13] OpenACC middle-end worker-partitioning support

2019-11-15 Thread Julian Brown
This is the main patch implementing worker-partitioning support on AMD
GCN. The following description is taken from the version of the patch
submitted on the openacc-gcc-9-branch:

This patch implements worker-partitioning support in the middle end,
by rewriting gimple. The OpenACC execution model requires that code can
run in either "worker single" mode where only a single worker per gang
is active, or "worker partitioned" mode, where multiple workers per gang
are active. This means we need to do something equivalent to
spawning additional workers when transitioning from worker-single to
worker-partitioned mode. However, GPUs typically fix the number of threads
of invoked kernels at launch time, so we need to do something with the
"extra" threads when they are not wanted.

The scheme used is -- very briefly! -- to conditionalise each basic block
that executes in "worker single" mode for worker 0 only. Conditional
branches are handled specially so "idle" (non-0) workers follow along with
worker 0. On transitioning to "worker partitioned" mode, any variables
modified by worker 0 are propagated to the other workers via GPU shared
memory. Special care is taken for routine calls, writes through pointers,
and so forth.

Much of omp-sese.c originates from code written for NVPTX by Nathan
Sidwell (adapted to work on gimple instead of RTL) -- though at present,
only the per-basic-block scheme is implemented, and the SESE-finding
algorithm isn't yet used.

OK?

Julian

ChangeLog

gcc/
* Makefile.in (OBJS): Add omp-sese.o.
* config/nvptx/nvptx.c (omp-sese.h): Include.
(bb_pair_t, bb_pair_vec_t, pseudo_node_t, bracket, bracket_vec_t,
bb_sese, bb_sese::~bb_sese, bb_sese::append, bb_sese::remove,
BB_SET_SESE, BB_GET_SESE, nvptx_sese_number, nvptx_sese_pseudo,
nvptx_sese_color, nvptx_find_sese): Remove.
(nvptx_neuter_pars): Call omp_find_sese instead of nvptx_find_sese.
* omp-builtins.def (BUILT_IN_GOACC_BARRIER, BUILT_IN_GOACC_SINGLE_START,
BUILT_IN_GOACC_SINGLE_COPY_START, BUILT_IN_GOACC_SINGLE_COPY_END): New
builtins.
* omp-offload.c (omp-sese.h): Include header.
(oacc_loop_xform_head_tail): Call update_stmt for modified builtin
calls.
(oacc_loop_process): Likewise.
(default_goacc_create_propagation_record): New default implementation
for TARGET_GOACC_CREATE_PROPAGATION_RECORD hook.
(execute_oacc_loop_designation): New.  Split out of oacc_device_lower.
(execute_oacc_gimple_workers): New.  Likewise.
(execute_oacc_device_lower): Recreate dims array.
(pass_data_oacc_loop_designation, pass_data_oacc_gimple_workers): New.
(pass_oacc_loop_designation, pass_oacc_gimple_workers): New.
(make_pass_oacc_loop_designation, make_pass_oacc_gimple_workers): New.
* omp-offload.h (oacc_fn_attrib_level): Add prototype.
* omp-sese.c: New file.
* omp-sese.h: New file.
* passes.def (pass_oacc_loop_designation, pass_oacc_gimple_workers):
Add passes.
* target.def (worker_partitioning, create_propagation_record): Add
target hooks.
* targhooks.h (default_goacc_create_propagation_record): Add prototype.
* tree-pass.h (make_pass_oacc_loop_designation,
make_pass_oacc_gimple_workers): Add prototypes.
* doc/tm.texi.in (TARGET_GOACC_WORKER_PARTITIONING,
TARGET_GOACC_CREATE_PROPAGATION_RECORD): Add documentation hooks.
* doc/tm.texi: Regenerate.
---
 gcc/Makefile.in  |1 +
 gcc/config/nvptx/nvptx.c |  622 +---
 gcc/doc/tm.texi  |   10 +
 gcc/doc/tm.texi.in   |4 +
 gcc/omp-builtins.def |8 +
 gcc/omp-offload.c|  159 ++-
 gcc/omp-offload.h|1 +
 gcc/omp-sese.c   | 2086 ++
 gcc/omp-sese.h   |   32 +
 gcc/passes.def   |2 +
 gcc/target.def   |   13 +
 gcc/targhooks.h  |1 +
 gcc/tree-pass.h  |2 +
 13 files changed, 2302 insertions(+), 639 deletions(-)
 create mode 100644 gcc/omp-sese.c
 create mode 100644 gcc/omp-sese.h

diff --git a/gcc/Makefile.in b/gcc/Makefile.in
index 0004d46b93d..eadf235c9f8 100644
--- a/gcc/Makefile.in
+++ b/gcc/Makefile.in
@@ -1432,6 +1432,7 @@ OBJS = \
omp-expand.o \
omp-general.o \
omp-grid.o \
+   omp-sese.o \
omp-low.o \
omp-simd-clone.o \
opt-problem.o \
diff --git a/gcc/config/nvptx/nvptx.c b/gcc/config/nvptx/nvptx.c
index 9934a240209..5ac8b6798cf 100644
--- a/gcc/config/nvptx/nvptx.c
+++ b/gcc/config/nvptx/nvptx.c
@@ -76,6 +76,7 @@
 #include "intl.h"
 #include "tree-hash-traits.h"
 #include "tree-pretty-print.h"
+#include "omp-sese.h"
 
 /* This file should be included last.  */
 #include "target-def.h"
@@ -3327,625 +3328,6 @@ nvptx_discover_pars (bb_insn_map_t *map)
   return par;
 }
 
-/* Analyse a group of BBs within a partitioned 

[PATCH 06/13] Fix up tests for oaccdevlow pass split

2019-11-15 Thread Julian Brown
This patch adjusts expected output for several tests after the oaccdevlow
pass is split into three by an earlier patch in this series.

OK?

Julian

ChangeLog

gcc/testsuite/
* c-c++-common/goacc/classify-kernels-unparallelized.c,
c-c++-common/goacc/classify-kernels.c,
c-c++-common/goacc/classify-parallel.c,
c-c++-common/goacc/classify-routine.c,
gcc.dg/goacc/loop-processing-1.c,
gfortran.dg/goacc/classify-kernels-unparallelized.f95,
gfortran.dg/goacc/classify-kernels.f95,
gfortran.dg/goacc/classify-parallel.f95,
gfortran.dg/goacc/classify-routine.f95: Scan oaccloops dump instead of
oaccdevlow pass.
---
 .../c-c++-common/goacc/classify-kernels-unparallelized.c  | 8 
 gcc/testsuite/c-c++-common/goacc/classify-kernels.c   | 8 
 gcc/testsuite/c-c++-common/goacc/classify-parallel.c  | 8 
 gcc/testsuite/c-c++-common/goacc/classify-routine.c   | 8 
 gcc/testsuite/gcc.dg/goacc/loop-processing-1.c| 4 ++--
 .../gfortran.dg/goacc/classify-kernels-unparallelized.f95 | 8 
 gcc/testsuite/gfortran.dg/goacc/classify-kernels.f95  | 8 
 gcc/testsuite/gfortran.dg/goacc/classify-parallel.f95 | 8 
 gcc/testsuite/gfortran.dg/goacc/classify-routine.f95  | 8 
 9 files changed, 34 insertions(+), 34 deletions(-)

diff --git a/gcc/testsuite/c-c++-common/goacc/classify-kernels-unparallelized.c 
b/gcc/testsuite/c-c++-common/goacc/classify-kernels-unparallelized.c
index d4c4b2ca237..79b4cad7916 100644
--- a/gcc/testsuite/c-c++-common/goacc/classify-kernels-unparallelized.c
+++ b/gcc/testsuite/c-c++-common/goacc/classify-kernels-unparallelized.c
@@ -5,7 +5,7 @@
{ dg-additional-options "-fopt-info-optimized-omp" }
{ dg-additional-options "-fdump-tree-ompexp" }
{ dg-additional-options "-fdump-tree-parloops1-all" }
-   { dg-additional-options "-fdump-tree-oaccdevlow" } */
+   { dg-additional-options "-fdump-tree-oaccloops" } */
 
 #define N 1024
 
@@ -35,6 +35,6 @@ void KERNELS ()
 
 /* Check the offloaded function's classification and compute dimensions (will
always be 1 x 1 x 1 for non-offloading compilation).
-   { dg-final { scan-tree-dump-times "(?n)Function is unparallelized OpenACC 
kernels offload" 1 "oaccdevlow" } }
-   { dg-final { scan-tree-dump-times "(?n)Compute dimensions \\\[1, 1, 1\\\]" 
1 "oaccdevlow" } }
-   { dg-final { scan-tree-dump-times "(?n)__attribute__\\(\\(oacc function 
\\(1, 1, 1\\), oacc kernels, omp target entrypoint\\)\\)" 1 "oaccdevlow" } } */
+   { dg-final { scan-tree-dump-times "(?n)Function is unparallelized OpenACC 
kernels offload" 1 "oaccloops" } }
+   { dg-final { scan-tree-dump-times "(?n)Compute dimensions \\\[1, 1, 1\\\]" 
1 "oaccloops" } }
+   { dg-final { scan-tree-dump-times "(?n)__attribute__\\(\\(oacc function 
\\(1, 1, 1\\), oacc kernels, omp target entrypoint\\)\\)" 1 "oaccloops" } } */
diff --git a/gcc/testsuite/c-c++-common/goacc/classify-kernels.c 
b/gcc/testsuite/c-c++-common/goacc/classify-kernels.c
index 16e9b9e31d1..8fcfc3f4278 100644
--- a/gcc/testsuite/c-c++-common/goacc/classify-kernels.c
+++ b/gcc/testsuite/c-c++-common/goacc/classify-kernels.c
@@ -5,7 +5,7 @@
{ dg-additional-options "-fopt-info-optimized-omp" }
{ dg-additional-options "-fdump-tree-ompexp" }
{ dg-additional-options "-fdump-tree-parloops1-all" }
-   { dg-additional-options "-fdump-tree-oaccdevlow" } */
+   { dg-additional-options "-fdump-tree-oaccloops" } */
 
 #define N 1024
 
@@ -31,6 +31,6 @@ void KERNELS ()
 
 /* Check the offloaded function's classification and compute dimensions (will
always be 1 x 1 x 1 for non-offloading compilation).
-   { dg-final { scan-tree-dump-times "(?n)Function is parallelized OpenACC 
kernels offload" 1 "oaccdevlow" } }
-   { dg-final { scan-tree-dump-times "(?n)Compute dimensions \\\[1, 1, 1\\\]" 
1 "oaccdevlow" } }
-   { dg-final { scan-tree-dump-times "(?n)__attribute__\\(\\(oacc function 
\\(1, 1, 1\\), oacc kernels parallelized, oacc function \\(, , \\), oacc 
kernels, omp target entrypoint\\)\\)" 1 "oaccdevlow" } } */
+   { dg-final { scan-tree-dump-times "(?n)Function is parallelized OpenACC 
kernels offload" 1 "oaccloops" } }
+   { dg-final { scan-tree-dump-times "(?n)Compute dimensions \\\[1, 1, 1\\\]" 
1 "oaccloops" } }
+   { dg-final { scan-tree-dump-times "(?n)__attribute__\\(\\(oacc function 
\\(1, 1, 1\\), oacc kernels parallelized, oacc function \\(, , \\), oacc 
kernels, omp target entrypoint\\)\\)" 1 "oaccloops" } } */
diff --git a/gcc/testsuite/c-c++-common/goacc/classify-parallel.c 
b/gcc/testsuite/c-c++-common/goacc/classify-parallel.c
index 66a6d133663..4e8f155961e 100644
--- a/gcc/testsuite/c-c++-common/goacc/classify-parallel.c
+++ b/gcc/testsuite/c-c++-common/goacc/classify-parallel.c
@@ -4,7 +4,7 @@
 /* { dg-additional-options "-O2" }
{ dg-additional-options "-fopt-info-optimized-omp" }
{ dg-additional-options 

[PATCH 05/13] AMD GCN adjustments for middle-end worker partitioning

2019-11-15 Thread Julian Brown
This patch provides AMD GCN-specific parts supporting middle-end
worker partitioning. The adjust_propagation_record hook is now called
create_propagation_record. Several builtins are redefined to take an
argument in a special address space (corresponding to GPU shared memory).

Tested alongside other patches in this series. OK?

Thanks,

Julian

ChangeLog

gcc/
* config/gcn/gcn-protos.h (gcn_goacc_adjust_propagation_record): Rename
prototype to...
(gcn_goacc_create_propagation_record): This.
* config/gcn/gcn-tree.c (gcn_goacc_adjust_propagation_record): Rename
function to...
(gcn_goacc_create_propagation_record): This.  Adjust comment.
* config/gcn/gcn.c (gcn_init_builtins): Override decls for
BUILT_IN_GOACC_SINGLE_START, BUILT_IN_GOACC_SINGLE_COPY_START,
BUILT_IN_GOACC_SINGLE_COPY_END and BUILT_IN_GOACC_BARRIER.
(gcn_fork_join): Remove inaccurate comment.
(TARGET_GOACC_ADJUST_PROPAGATION_RECORD): Rename to...
(TARGET_GOACC_CREATE_PROPAGATION_RECORD): This.
---
 gcc/config/gcn/gcn-protos.h |  2 +-
 gcc/config/gcn/gcn-tree.c   |  6 +++---
 gcc/config/gcn/gcn.c| 11 +++
 3 files changed, 7 insertions(+), 12 deletions(-)

diff --git a/gcc/config/gcn/gcn-protos.h b/gcc/config/gcn/gcn-protos.h
index 714d51189d9..e33c0598fee 100644
--- a/gcc/config/gcn/gcn-protos.h
+++ b/gcc/config/gcn/gcn-protos.h
@@ -37,7 +37,7 @@ extern rtx gcn_full_exec ();
 extern rtx gcn_full_exec_reg ();
 extern rtx gcn_gen_undef (machine_mode);
 extern bool gcn_global_address_p (rtx);
-extern tree gcn_goacc_adjust_propagation_record (tree record_type, bool sender,
+extern tree gcn_goacc_create_propagation_record (tree record_type, bool sender,
 const char *name);
 extern void gcn_goacc_adjust_private_decl (tree var, int level);
 extern void gcn_goacc_reduction (gcall *call);
diff --git a/gcc/config/gcn/gcn-tree.c b/gcc/config/gcn/gcn-tree.c
index aa56e236134..538034f7372 100644
--- a/gcc/config/gcn/gcn-tree.c
+++ b/gcc/config/gcn/gcn-tree.c
@@ -667,12 +667,12 @@ gcn_goacc_reduction (gcall *call)
 }
 }
 
-/* Implement TARGET_GOACC_ADJUST_PROPAGATION_RECORD.
+/* Implement TARGET_GOACC_CREATE_PROPAGATION_RECORD.
  
-   Tweak (worker) propagation record, e.g. to put it in shared memory.  */
+   Create (worker) propagation record in shared memory.  */
 
 tree
-gcn_goacc_adjust_propagation_record (tree record_type, bool sender,
+gcn_goacc_create_propagation_record (tree record_type, bool sender,
 const char *name)
 {
   tree type = record_type;
diff --git a/gcc/config/gcn/gcn.c b/gcc/config/gcn/gcn.c
index cf2f30413ae..2f758ef3ddc 100644
--- a/gcc/config/gcn/gcn.c
+++ b/gcc/config/gcn/gcn.c
@@ -3494,8 +3494,6 @@ gcn_init_builtins (void)
   TREE_NOTHROW (gcn_builtin_decls[i]) = 1;
 }
 
-/* FIXME: remove the ifdef once OpenACC support is merged upstream.  */
-#ifdef BUILT_IN_GOACC_SINGLE_START
   /* These builtins need to take/return an LDS pointer: override the generic
  versions here.  */
 
@@ -3512,7 +3510,6 @@ gcn_init_builtins (void)
 
   set_builtin_decl (BUILT_IN_GOACC_BARRIER,
gcn_builtin_decls[GCN_BUILTIN_ACC_BARRIER], false);
-#endif
 }
 
 /* Expand the CMP_SWAP GCN builtins.  We have our own versions that do
@@ -4798,8 +4795,6 @@ static bool
 gcn_fork_join (gcall *ARG_UNUSED (call), const int *ARG_UNUSED (dims),
   bool ARG_UNUSED (is_fork))
 {
-  /* GCN does not use the fork/join concept invented for NVPTX.
- Instead we use standard autovectorization.  */
   return false;
 }
 
@@ -6064,9 +6059,9 @@ print_operand (FILE *file, rtx x, int code)
 #define TARGET_GIMPLIFY_VA_ARG_EXPR gcn_gimplify_va_arg_expr
 #undef TARGET_OMP_DEVICE_KIND_ARCH_ISA
 #define TARGET_OMP_DEVICE_KIND_ARCH_ISA gcn_omp_device_kind_arch_isa
-#undef  TARGET_GOACC_ADJUST_PROPAGATION_RECORD
-#define TARGET_GOACC_ADJUST_PROPAGATION_RECORD \
-  gcn_goacc_adjust_propagation_record
+#undef  TARGET_GOACC_CREATE_PROPAGATION_RECORD
+#define TARGET_GOACC_CREATE_PROPAGATION_RECORD \
+  gcn_goacc_create_propagation_record
 #undef  TARGET_GOACC_ADJUST_PRIVATE_DECL
 #define TARGET_GOACC_ADJUST_PRIVATE_DECL gcn_goacc_adjust_private_decl
 #undef  TARGET_GOACC_FORK_JOIN
-- 
2.23.0



[PATCH 03/13] Rewrite OpenACC private or reduction reference variables

2019-11-15 Thread Julian Brown
Reference-type private variables or reference-type variables used as
reduction targets do not work well with the scheme to implement worker
partitioning on AMD GCN. This patch (originally by Cesar Philippidis, but
modified somewhat) provides support for replacing such variables with new
non-reference-typed temporary versions within partitioned offload regions.

Tested alongside other patches in this series.

OK?

Thanks,

Julian

ChangeLog

gcc/
* gimplify.c (privatize_reduction): New struct.
(localize_reductions_r, localize_reductions): New functions.
(gimplify_omp_for): Call localize_reductions.
(gimplify_omp_workshare): Likewise.
* omp-low.c (lower_oacc_reductions): Handle localized reductions.
Create fewer temp vars.
* tree-core.h (omp_clause_code): Add OMP_CLAUSE_REDUCTION_PRIVATE_DECL
documentation.
* tree.c (omp_clause_num_ops): Bump number of ops for
OMP_CLAUSE_REDUCTION to 6.
(walk_tree_1): Adjust accordingly.
* tree.h (OMP_CLAUSE_REDUCTION_PRIVATE_DECL): Add macro.

libgomp/
* testsuite/libgomp.oacc-fortran/privatized-ref-1.f95: New test.
* testsuite/libgomp.oacc-c++/privatized-ref-2.C: New test.
* testsuite/libgomp.oacc-c++/privatized-ref-3.C: New test.
---
 gcc/gimplify.c| 116 ++
 gcc/omp-low.c |  47 +++
 gcc/tree-core.h   |   4 +-
 gcc/tree.c|  11 +-
 gcc/tree.h|   2 +
 .../libgomp.oacc-c++/privatized-ref-2.C   |  64 ++
 .../libgomp.oacc-c++/privatized-ref-3.C   |  64 ++
 .../libgomp.oacc-fortran/privatized-ref-1.f95 |  71 +++
 8 files changed, 342 insertions(+), 37 deletions(-)
 create mode 100644 libgomp/testsuite/libgomp.oacc-c++/privatized-ref-2.C
 create mode 100644 libgomp/testsuite/libgomp.oacc-c++/privatized-ref-3.C
 create mode 100644 libgomp/testsuite/libgomp.oacc-fortran/privatized-ref-1.f95

diff --git a/gcc/gimplify.c b/gcc/gimplify.c
index 87a64054514..191ade6be3e 100644
--- a/gcc/gimplify.c
+++ b/gcc/gimplify.c
@@ -229,6 +229,11 @@ struct gimplify_omp_ctx
   int defaultmap[4];
 };
 
+struct privatize_reduction
+{
+  tree ref_var, local_var;
+};
+
 static struct gimplify_ctx *gimplify_ctxp;
 static struct gimplify_omp_ctx *gimplify_omp_ctxp;
 static bool in_omp_construct;
@@ -10811,6 +10816,95 @@ find_combined_omp_for (tree *tp, int *walk_subtrees, 
void *data)
   return NULL_TREE;
 }
 
+/* Helper function for localize_reductions.  Replace all uses of REF_VAR with
+   LOCAL_VAR.  */
+
+static tree
+localize_reductions_r (tree *tp, int *walk_subtrees, void *data)
+{
+  enum tree_code tc = TREE_CODE (*tp);
+  struct privatize_reduction *pr = (struct privatize_reduction *) data;
+
+  if (TYPE_P (*tp))
+*walk_subtrees = 0;
+
+  switch (tc)
+{
+case INDIRECT_REF:
+case MEM_REF:
+  if (TREE_OPERAND (*tp, 0) == pr->ref_var)
+   *tp = pr->local_var;
+
+  *walk_subtrees = 0;
+  break;
+
+case VAR_DECL:
+case PARM_DECL:
+case RESULT_DECL:
+  if (*tp == pr->ref_var)
+   *tp = pr->local_var;
+
+  *walk_subtrees = 0;
+  break;
+
+default:
+  break;
+}
+
+  return NULL_TREE;
+}
+
+/* OpenACC worker and vector loop state propagation requires reductions
+   to be inside local variables.  This function replaces all reference-type
+   reductions variables associated with the loop with a local copy.  It is
+   also used to create private copies of reduction variables for those
+   which are not associated with acc loops.  */
+
+static void
+localize_reductions (tree clauses, tree body)
+{
+  tree c, var, type, new_var;
+  struct privatize_reduction pr;
+
+  for (c = clauses; c; c = OMP_CLAUSE_CHAIN (c))
+if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_REDUCTION)
+  {
+   var = OMP_CLAUSE_DECL (c);
+
+   if (!lang_hooks.decls.omp_privatize_by_reference (var))
+ {
+   OMP_CLAUSE_REDUCTION_PRIVATE_DECL (c) = NULL;
+   continue;
+ }
+
+   type = TREE_TYPE (TREE_TYPE (var));
+   new_var = create_tmp_var (type, IDENTIFIER_POINTER (DECL_NAME (var)));
+
+   pr.ref_var = var;
+   pr.local_var = new_var;
+
+   walk_tree (, localize_reductions_r, , NULL);
+
+   OMP_CLAUSE_REDUCTION_PRIVATE_DECL (c) = new_var;
+  }
+else if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_PRIVATE)
+  {
+   var = OMP_CLAUSE_DECL (c);
+
+   if (!lang_hooks.decls.omp_privatize_by_reference (var))
+ continue;
+
+   type = TREE_TYPE (TREE_TYPE (var));
+   new_var = create_tmp_var (type, IDENTIFIER_POINTER (DECL_NAME (var)));
+
+   pr.ref_var = var;
+   pr.local_var = new_var;
+
+   walk_tree (, localize_reductions_r, , NULL);
+  }
+}
+
+
 /* Gimplify the gross structure of an OMP_FOR statement.  */
 
 static enum 

[PATCH 00/13] AMD GCN worker partitioning support

2019-11-15 Thread Julian Brown
This patch series brings together support for worker partitioning on
AMD GCN and various support patches to ensure no testsuite regressions.

Some of these patches have been sent upstream previously. Most are present
on the openacc-gcc-9-branch, and have been tested with both AMD GCN and
nVidia GPUs.

The series has been tested as a whole with offloading to AMD GCN.

Further commentary is provided alongside individual patches.

OK for trunk?

Thanks,

Julian

Julian Brown (13):
  Add support for gang local storage allocation in shared memory
  Target-dependent gang-private variable decl rewriting
  Rewrite OpenACC private or reduction reference variables
  OpenACC middle-end worker-partitioning support
  AMD GCN adjustments for middle-end worker partitioning
  Fix up tests for oaccdevlow pass split
  Fix OpenACC "ephemeral" asynchronous host-to-device copies
  Fix host-to-device copies from rodata for AMD GCN
  AMD GCN libgomp plugin queue-full condition locking fix
  Race conditions in OpenACC async tests
  AMD GCN symbol output with null cfun
  Fix parallel-dims.f90 for AMD GCN
  Enable worker partitioning for AMD GCN

 gcc/Makefile.in   |1 +
 gcc/config/gcn/gcn-protos.h   |4 +-
 gcc/config/gcn/gcn-tree.c |   11 +-
 gcc/config/gcn/gcn.c  |   25 +-
 gcc/config/gcn/gcn.opt|2 +-
 gcc/config/nvptx/nvptx.c  |  699 +-
 gcc/doc/tm.texi   |   23 +
 gcc/doc/tm.texi.in|8 +
 gcc/expr.c|   13 +-
 gcc/gimplify.c|  116 +
 gcc/internal-fn.c |2 +
 gcc/internal-fn.h |3 +-
 gcc/omp-builtins.def  |8 +
 gcc/omp-low.c |  172 +-
 gcc/omp-offload.c |  322 ++-
 gcc/omp-offload.h |1 +
 gcc/omp-sese.c| 2086 +
 gcc/omp-sese.h|   32 +
 gcc/passes.def|2 +
 gcc/target.def|   30 +
 gcc/targhooks.h   |1 +
 .../goacc/classify-kernels-unparallelized.c   |8 +-
 .../c-c++-common/goacc/classify-kernels.c |8 +-
 .../c-c++-common/goacc/classify-parallel.c|8 +-
 .../c-c++-common/goacc/classify-routine.c |8 +-
 .../gcc.dg/goacc/loop-processing-1.c  |4 +-
 .../goacc/classify-kernels-unparallelized.f95 |8 +-
 .../gfortran.dg/goacc/classify-kernels.f95|8 +-
 .../gfortran.dg/goacc/classify-parallel.f95   |8 +-
 .../gfortran.dg/goacc/classify-routine.f95|8 +-
 gcc/tree-core.h   |4 +-
 gcc/tree-pass.h   |2 +
 gcc/tree.c|   11 +-
 gcc/tree.h|2 +
 libgomp/libgomp-plugin.h  |3 +-
 libgomp/libgomp.h |2 +-
 libgomp/oacc-host.c   |1 +
 libgomp/oacc-mem.c|4 +-
 libgomp/plugin/plugin-gcn.c   |   82 +-
 libgomp/plugin/plugin-nvptx.c |   13 +-
 libgomp/target.c  |   92 +-
 .../libgomp.oacc-c++/privatized-ref-2.C   |   64 +
 .../libgomp.oacc-c++/privatized-ref-3.C   |   64 +
 .../gang-private-1.c  |   38 +
 .../libgomp.oacc-c-c++-common/lib-94.c|4 +-
 .../libgomp.oacc-c-c++-common/loop-gwv-2.c|   95 +
 .../gangprivate-attrib-1.f90  |   25 +
 .../gangprivate-attrib-2.f90  |   25 +
 .../libgomp.oacc-fortran/lib-16-2.f90 |5 +
 .../libgomp.oacc-fortran/parallel-dims-aux.c  |9 +-
 .../libgomp.oacc-fortran/privatized-ref-1.f95 |   71 +
 51 files changed, 3426 insertions(+), 819 deletions(-)
 create mode 100644 gcc/omp-sese.c
 create mode 100644 gcc/omp-sese.h
 create mode 100644 libgomp/testsuite/libgomp.oacc-c++/privatized-ref-2.C
 create mode 100644 libgomp/testsuite/libgomp.oacc-c++/privatized-ref-3.C
 create mode 100644 libgomp/testsuite/libgomp.oacc-c-c++-common/gang-private-1.c
 create mode 100644 libgomp/testsuite/libgomp.oacc-c-c++-common/loop-gwv-2.c
 create mode 100644 
libgomp/testsuite/libgomp.oacc-fortran/gangprivate-attrib-1.f90
 create mode 100644 
libgomp/testsuite/libgomp.oacc-fortran/gangprivate-attrib-2.f90
 create mode 100644 libgomp/testsuite/libgomp.oacc-fortran/privatized-ref-1.f95

-- 
2.23.0



[PATCH 02/13] Target-dependent gang-private variable decl rewriting

2019-11-15 Thread Julian Brown
This patch provides support for the adjust_private_decl hook introduced
by the previous patch changing the type of its decl argument, e.g. if the
offload target forces it into another address space. Any ADDR_EXPR nodes
that have the decl as an argument will have the wrong type: this patch
implements a scheme to rewrite those nodes at oaccdevlow time. Arguments
to sync builtins are handled specially, since those often have variants
that operate on alternative address spaces, so the rewritten decl can
be passed to them directly.

ChangeLog

gcc/
* omp-offload.c (struct addr_expr_rewrite_info): Add struct.
(rewrite_addr_expr): New function.
(is_sync_builtin_call): New function.
(execute_oacc_device_lower): Fix up addr_expr nodes whose argument type
has changed after calling the OpenACC adjust_private_decl hook.
---
 gcc/omp-offload.c | 130 +-
 1 file changed, 129 insertions(+), 1 deletion(-)

diff --git a/gcc/omp-offload.c b/gcc/omp-offload.c
index d8291125370..2e56a04a714 100644
--- a/gcc/omp-offload.c
+++ b/gcc/omp-offload.c
@@ -1502,6 +1502,78 @@ default_goacc_reduction (gcall *call)
   gsi_replace_with_seq (, seq, true);
 }
 
+struct addr_expr_rewrite_info
+{
+  gimple *stmt;
+  hash_set *adjusted_vars;
+  bool avoid_pointer_conversion;
+  bool modified;
+};
+
+static tree
+rewrite_addr_expr (tree *tp, int *walk_subtrees, void *data)
+{
+  walk_stmt_info *wi = (walk_stmt_info *) data;
+  addr_expr_rewrite_info *info = (addr_expr_rewrite_info *) wi->info;
+
+  if (TREE_CODE (*tp) == ADDR_EXPR)
+{
+  tree arg = TREE_OPERAND (*tp, 0);
+
+  if (info->adjusted_vars->contains (arg))
+   {
+ if (info->avoid_pointer_conversion)
+   {
+ *tp = build_fold_addr_expr (arg);
+ info->modified = true;
+ *walk_subtrees = 0;
+   }
+ else
+   {
+ gimple_stmt_iterator gsi = gsi_for_stmt (info->stmt);
+ tree repl = build_fold_addr_expr (arg);
+ gimple *stmt1
+   = gimple_build_assign (make_ssa_name (TREE_TYPE (repl)), repl);
+ tree conv = convert_to_pointer (TREE_TYPE (*tp),
+ gimple_assign_lhs (stmt1));
+ gimple *stmt2
+   = gimple_build_assign (make_ssa_name (TREE_TYPE (*tp)), conv);
+ gsi_insert_before (, stmt1, GSI_SAME_STMT);
+ gsi_insert_before (, stmt2, GSI_SAME_STMT);
+ *tp = gimple_assign_lhs (stmt2);
+ info->modified = true;
+ *walk_subtrees = 0;
+   }
+   }
+}
+
+  return NULL_TREE;
+}
+
+/* Return TRUE if CALL is a call to a builtin atomic/sync operation.  */
+
+static bool
+is_sync_builtin_call (gcall *call)
+{
+  tree callee = gimple_call_fndecl (call);
+
+  if (callee != NULL_TREE
+  && gimple_call_builtin_p (call, BUILT_IN_NORMAL))
+switch (DECL_FUNCTION_CODE (callee))
+  {
+#undef DEF_SYNC_BUILTIN
+#define DEF_SYNC_BUILTIN(ENUM, NAME, TYPE, ATTRS) case ENUM:
+#include "sync-builtins.def"
+#undef DEF_SYNC_BUILTIN
+   return true;
+
+  default:
+   ;
+  }
+
+  return false;
+}
+
 /* Main entry point for oacc transformations which run on the device
compiler after LTO, so we know what the target device is at this
point (including the host fallback).  */
@@ -1611,6 +1683,8 @@ execute_oacc_device_lower ()
  dominance information to update SSA.  */
   calculate_dominance_info (CDI_DOMINATORS);
 
+  hash_set adjusted_vars;
+
   /* Now lower internal loop functions to target-specific code
  sequences.  */
   basic_block bb;
@@ -1714,7 +1788,12 @@ execute_oacc_device_lower ()
fputc ('\n', dump_file);
  }
if (targetm.goacc.adjust_private_decl)
- targetm.goacc.adjust_private_decl (decl, level);
+ {
+   tree oldtype = TREE_TYPE (decl);
+   targetm.goacc.adjust_private_decl (decl, level);
+   if (TREE_TYPE (decl) != oldtype)
+ adjusted_vars.add (decl);
+ }
  }
remove = true;
  }
@@ -1750,6 +1829,55 @@ execute_oacc_device_lower ()
  gsi_next ();
   }
 
+  /* Make adjustments to gang-private local variables if required by the
+ target, e.g. forcing them into a particular address space.  Afterwards,
+ ADDR_EXPR nodes which have adjusted variables as their argument need to
+ be modified in one of two ways:
+
+   1. They can be recreated, making a pointer to the variable in the new
+ address space, or
+
+   2. The address of the variable in the new address space can be taken,
+ converted to the default (original) address space, and the result of
+ 

[PATCH 01/13] Add support for gang local storage allocation in shared memory

2019-11-15 Thread Julian Brown
This patch provides support for gang local storage allocation in shared
memory. It is mostly identical to the version posted previously, with
one cosmetic fix (a duplicated identical condition):

https://gcc.gnu.org/ml/gcc-patches/2019-11/msg00448.html

Tested alongside other patches in this series with offloading to AMD GCN.

OK?

Julian

ChangeLog

gcc/
* config/gcn/gcn-protos.h (gcn_goacc_adjust_gangprivate_decl): Rename
to...
(gcn_goacc_adjust_private_decl): ...this.  Add and use LEVEL parameter.
* config/gcn/gcn-tree.c (gcn_goacc_adjust_gangprivate_decl): Rename
to...
(gcn_goacc_adjust_private_decl): ...this. Add LEVEL parameter.
* config/gcn/gcn.c (TARGET_GOACC_ADJUST_GANGPRIVATE_DECL): Delete.
(TARGET_GOACC_ADJUST_PRIVATE_DECL): Define using renamed
gcn_goacc_adjust_private_decl.
* config/nvptx/nvptx.c (tree-hash-traits.h, tree-pretty-print.h):
Include.
(gangprivate_shared_size): New global variable.
(gangprivate_shared_align): Likewise.
(gangprivate_shared_sym): Likewise.
(gangprivate_shared_hmap): Likewise.
(nvptx_option_override): Initialize gangprivate_shared_sym,
gangprivate_shared_align.
(nvptx_file_end): Output gangprivate_shared_sym.
(nvptx_goacc_adjust_private_decl): New function.
(nvptx_goacc_expand_accel_var): New function.
(nvptx_set_current_function): New function.
(TARGET_GOACC_ADJUST_PRIVATE_DECL, TARGET_GOACC_EXPAND_ACCEL_VAR):
Define hooks.
* doc/tm.texi.in (TARGET_GOACC_EXPAND_ACCEL_VAR,
TARGET_GOACC_ADJUST_PRIVATE_DECL): Place new documentation hooks.
* doc/tm.texi: Regenerate.
* expr.c (expand_expr_real_1): Expand decls using the expand_accel_var
OpenACC hook if defined.
* internal-fn.c (expand_UNIQUE): Handle IFN_UNIQUE_OACC_PRIVATE.
* internal-fn.h (IFN_UNIQUE_CODES): Add OACC_PRIVATE.
* omp-low.c (omp_context): Add oacc_addressable_var_decls field.
(new_omp_context): Initialize oacc_addressable_var_decls in new
omp_context.
(delete_omp_context): Delete oacc_addressable_var_decls in old
omp_context.
(lower_oacc_reductions): Add PRIVATE_MARKER parameter.  Insert private
marker before fork.
(lower_oacc_head_tail): Add PRIVATE_MARKER parameter. Modify private
marker's gimple call arguments, and pass it to lower_oacc_reductions.
(oacc_record_private_var_clauses, oacc_record_vars_in_bind,
make_oacc_private_marker): New functions.
(lower_omp_for): Call oacc_record_private_var_clauses with "for"
clauses.  Call oacc_record_vars_in_bind for OpenACC contexts.  Create
private marker and pass to lower_oacc_head_tail.
(lower_omp_target): Create private marker and pass to
lower_oacc_reductions.
(lower_omp_1): Call oacc_record_vars_in_bind for OpenACC bind contexts.
* omp-offload.c (convert.h): Include.
(oacc_loop_xform_head_tail): Treat private-variable markers like
fork/join when transforming head/tail sequences.
(execute_oacc_device_lower): Use IFN_UNIQUE_OACC_PRIVATE to determine
partitioning level of private variables, and process any found via
adjust_private_decl target hook.
* target.def (expand_accel_var, adjust_private_decl): New target hooks.

libgomp/
* testsuite/libgomp.oacc-c-c++-common/gang-private-1.c: New test.
* testsuite/libgomp.oacc-c-c++-common/loop-gwv-2.c: New test.
* testsuite/libgomp.oacc-fortran/gangprivate-attrib-1.f90: New test.
* testsuite/libgomp.oacc-fortran/gangprivate-attrib-2.f90: New test.
---
 gcc/config/gcn/gcn-protos.h   |   2 +-
 gcc/config/gcn/gcn-tree.c |   5 +-
 gcc/config/gcn/gcn.c  |   4 +-
 gcc/config/nvptx/nvptx.c  |  77 +++
 gcc/doc/tm.texi   |  13 ++
 gcc/doc/tm.texi.in|   4 +
 gcc/expr.c|  13 +-
 gcc/internal-fn.c |   2 +
 gcc/internal-fn.h |   3 +-
 gcc/omp-low.c | 125 +-
 gcc/omp-offload.c |  37 +-
 gcc/target.def|  17 +++
 .../gang-private-1.c  |  38 ++
 .../libgomp.oacc-c-c++-common/loop-gwv-2.c|  95 +
 .../gangprivate-attrib-1.f90  |  25 
 .../gangprivate-attrib-2.f90  |  25 
 16 files changed, 472 insertions(+), 13 deletions(-)
 create mode 100644 libgomp/testsuite/libgomp.oacc-c-c++-common/gang-private-1.c
 create mode 100644 libgomp/testsuite/libgomp.oacc-c-c++-common/loop-gwv-2.c
 create mode 100644 

Re: [PATCH 0/4] Eliminate cc0 from m68k

2019-11-15 Thread Bernd Schmidt
On 11/15/19 5:34 PM, Andreas Schwab wrote:
> On Nov 15 2019, Bernd Schmidt wrote:
> 
>> Are these with the patch?
> 
> Yes.
> 
>> Are you on real hardware
> 
> No, I'm using aranym.

Any chance you could show the command lines from the log files or some
other way of reproducing the issue?


Bernd


Re: [WIP PATCH] add object access attributes (PR 83859)

2019-11-15 Thread Martin Sebor

On 10/27/19 11:31 AM, Jeff Law wrote:

On 9/29/19 1:51 PM, Martin Sebor wrote:

-Wstringop-overflow detects a subset of past-the-end read and write
accesses by built-in functions such as memcpy and strcpy.  It relies
on the functions' effects the knowledge of which is hardwired into
GCC.  Although it's possible for users to create wrappers for their
own functions to detect similar problems, it's quite cumbersome and
so only lightly used outside system libraries like Glibc.  Even Glibc
only checks for buffer overflow and not for reading past the end.

PR 83859 asks to expose the same checking that GCC does natively for
built-in calls via a function attribute that associates a pointer
argument with the size argument, such as:

   __attribute__((buffer_size (1, 2))) void
   f (char* dst, size_t dstsize);

The attached patch is my initial stab at providing this feature by
introducing three new attributes:

   * read_only (ptr-argno, size-argno)
   * read_only (ptr-argno, size-argno)
   * read_write (ptr-argno, size-argno)

As requested, the attributes associate a pointer parameter to
a function with a size parameter.  In addition, they also specify
how the function accesses the object the pointer points to: either
it only reads from it, or it only writes to it, or it does both.

Besides enabling the same buffer overflow detection as for built-in
string functions they also let GCC issue -Wuninitialized warnings
for uninitialized objects passed to read-only functions by reference,
and -Wunused-but-set warnings for objects passed to write-only
functions that are otherwise unused (PR 80806).  The -Wununitialized
part is done. The -Wunused-but-set detection is implemented only in
the C FE and not yet in C++.

Besides the diagnostic improvements above the attributes also open
up optimization opportunities such as DCE.  I'm still working on this
and so it's not yet part of the initial patch.

I plan to finish the patch for GCC 10 but I don't expect to have
the time to start taking advantage of the attributes for optimization
until GCC 11.

Besides regression testing on x86_64-linux, I also tested the patch
by compiling Binutils/GDB, Glibc, and the Linux kernel with it.  It
found no new problems but caused a handful of -Wunused-but-set-variable
false positives due to an outstanding bug in the C front-end introduced
by the patch that I still need to fix.

Martin

gcc-80806.diff

PR c/80806 - gcc does not warn if local array is memset only
PR middle-end/83859 - attribute to associate buffer and its size

gcc/ChangeLog:

PR c/80806
PR middle-end/83859
* builtin-attrs.def (ATTR_NO_SIDE_EFFECT): New.
(ATTR_READ_ONLY, ATTR_READ_WRITE, ATTR_WRITE_ONLY): New.
(ATTR_NOTHROW_WRONLY1_LEAF, ATTR_NOTHROW_WRONLY1_2_LEAF): New.
(ATTR_NOTHROW_WRONLY1_3_LEAF, ATTR_NOTHROW_WRONLY2_3_LEAF): New.
(ATTR_RET1_NOTHROW_WRONLY1_LEAF, ATTR_RET1_NOTHROW_WRONLY1_3_LEAF): New.
(ATTR_RET1_NOTHROW_NONNULL_RDONLY2_LEAF): New.
(ATTR_RET1_NOTHROW_NONNULL_RDWR1_RDONLY2_LEAF): New.
(ATTR_RET1_NOTHROW_WRONLY1_3_RDONLY2_3_LEAF): New.
(ATTR_RET1_NOTHROW_WRONLY1_RDONLY2_LEAF): New.
(ATTR_RET1_NOTHROW_WRONLY1_3_RDONLY2_LEAF): New.
(ATTR_MALLOC_NOTHROW_NONNULL_RDONLY1_LEAF): New.
(ATTR_PURE_NOTHROW_NONNULL_RDONLY1_LEAF): New.
(ATTR_PURE_NOTHROW_NONNULL_RDONLY1_RDONLY2_LEAF): New.
(ATTR_RETNONNULL_RDONLY2_3_NOTHROW_LEAF): New.
(ATTR_RETNONNULL_WRONLY1_3_RDONLY2_3_NOTHROW_LEAF): New.
(ATTR_PURE_NOTHROW_NONNULL_RDONLY1_3_LEAF): New.
(ATTR_PURE_NOTHROW_NONNULL_RDONLY1_2_3_LEAF): New.
(ATTR_RETNONNULL_RDONLY2_NOTHROW_LEAF): New.
(ATTR_RETNONNULL_WRONLY1_RDONLY2_NOTHROW_LEAF): New.
(ATTR_RETNONNULL_WRONLY1_3_RDONLY2_NOTHROW_LEAF): New.
* builtins.c (check_access): Make extern.  Consistently set
the no-warning bit after issuing a warning.
* builtins.h (check_access): Declare.
* builtins.def (bcopy, bzero, index, memchr, memcmp, memcpy): Add
read_only and write_only attributes.
(memset, rindex, stpcpy, stpncpy, strcasecmp, strcat): Same.
(strchr, strcmp, strcpy, strcspn, strdup, strndup, strlen): Same.
(strncasecmp, strncat, strncmp, strncpy, strrchr, strspn, strstr): Same.
(free, __memcpy_chk, __memmove_chk, __memset_chk): Same.
(__strcpy_chk, __strncpy_chk): Same.
* calls.c (rdwr_access_hash): New type.
(rdwr_map): Same.
(init_attr_rdwr_indices): New function.
(maybe_warn_rdwr_sizes): Same.
(initialize_argument_information): Call init_attr_rdwr_indices.
Call maybe_warn_rdwr_sizes.
* doc/extend.texi (no_side_effect): Document new attribute.
(read_only, write_only, read_write): Same.
* tree-ssa-uninit.c (maybe_warn_uninit_accesss): New functions.
(warn_uninitialized_vars): Rename argument.  Factor out code into

Re: [PATCH] libgo/test: Pass $GOLIBS to compilation in DejaGNU testing

2019-11-15 Thread Ian Lance Taylor
On Tue, Nov 12, 2019 at 4:43 PM Maciej W. Rozycki  wrote:
>
> Pass $GOLIBS to compilation in DejaGNU testing like with direct compiler
> invocation from `libgo/testsuite/gotest', removing link problems in
> cross-toolchain testing like:
>
> .../bin/riscv64-linux-gnu-ld: _gotest_.o: in function 
> `cmd..z2fgo..z2finternal..z2fcache.Cache.get':
> .../riscv64-linux-gnu/libgo/gotest24771/test/cache.go:182: undefined 
> reference to `cmd..z2fgo..z2finternal..z2frenameio.ReadFile'
>
> due to `libgotool.a' missing from the linker invocation command and
> improving overall test results for the `riscv64-linux-gnu' target (here
> with the `x86_64-linux-gnu' host and RISC-V QEMU in the Linux user
> emulation mode as the target board) from 133 PASSes and 26 FAILs to 145
> PASSes and 29 FAILs.

Thanks.  Committed to trunk.

Ian


Re: [C++ Patch] Improve cp_truthvalue_conversion locations and more

2019-11-15 Thread Jason Merrill

On 11/12/19 8:57 AM, Paolo Carlini wrote:

Hi,

a few days ago I noticed that we weren't doing the right thing 
location-wise for the first test of g++.dg/warn/Waddress-1.C: it seems 
clear that the ultimate reason is that we didn't pass an accurate 
location to build_binary_op called from cp_truthvalue_conversion. When I 
fixed that, I noticed that for testcases like warn/Walways-true-3.C we 
were issuing many duplicate warnings and I traced that to ocp_convert 
not using its tsubst_flags_t argument - which can come from 
cp_convert_and_check as tf_none - when calling cp_truthvalue_conversion. 
Thus I also added a tusbst_flags_t parameter to the latter and 
everything looks finally good for these testcases.


Tested x86_64-linux.

Thanks, Paolo.




OK.



Re: [PATCH] Refactor rust-demangle to be independent of C++ demangling.

2019-11-15 Thread Eduard-Mihai Burtescu
> This is OK.
> 
> Thanks.
> 
> Ian
>

Ping for someone to commit this (as mentioned before, I have no commit access).
I've tried pinging some people on IRC, but saw no response.

Approved version of the patch: 
https://gcc.gnu.org/ml/gcc-patches/2019-11/msg00647.html

Original email, containing the description: 
https://gcc.gnu.org/ml/gcc-patches/2019-10/msg01591.html
(ignore the original patch, two changes had to be made before it was approved)

Thanks,
- Eddy B.


Re: [PATCH, libstdc++] Implement C++20 p1032 default_searcher constexprosity.

2019-11-15 Thread Jonathan Wakely

On 15/11/19 20:15 +, Smith-Rowland, Edward M wrote:

--- testsuite/20_util/function_objects/constexpr_searcher.cc(nonexistent)
+++ testsuite/20_util/function_objects/constexpr_searcher.cc(working copy)
@@ -0,0 +1,52 @@
+// Copyright (C) 2014-2019 Free Software Foundation, Inc.


Just 2019 here, OK for trunk with that change. Thanks!




Re: [PATCH, libstdc++] Implement C++20 p1032 default_searcher constexprosity.

2019-11-15 Thread Ville Voutilainen
On Fri, 15 Nov 2019 at 22:16, Smith-Rowland, Edward M
 wrote:
>
> Pretty self-explanatory.

LGTM. Jonathan still needs to ack it.


Re: [External]_Re: Implement the part of C++20 p1032 Misc constexpr bits.

2019-11-15 Thread Smith-Rowland, Edward M

From: Jonathan Wakely 
Sent: Friday, November 15, 2019 2:33 PM
To: Smith-Rowland, Edward M
Cc: libstd...@gcc.gnu.org; gcc-patches@gcc.gnu.org
Subject: Re: [External]_Re: Implement the  part of C++20 p1032 Misc 
constexpr bits.   

Oh I see the problem, it's because I made synopsis_c++20.cc include
synopsis_c++17.cc because I was lazy.

How about leaving those declarations in synopsis_c++17.cc but
guarding them with #if __cplusplus == 201703L and then adding the
constexpr versions of them in synopsis_c++20.cc ?

I think we should also add { target c++17_only } to synopsis_c++17.cc
(which should have had a target selector anyway).


Ok,
Testing this...
2019-11-15  Edward Smith-Rowland  <3dw...@verizon.net>

	Implement the  part of C++20 p1032 Misc constexpr bits.
	* include/bits/stl_iterator.h (back_insert_iterator, back_inserter)
	(front_insert_iterator, front_inserter, insert_iterator, inserter):
	Make constexpr.
	* testsuite/24_iterators/insert_iterator/requirements/constexpr.cc: New.
	* testsuite/24_iterators/back_insert_iterator/requirements/
	constexpr.cc: New.
	* testsuite/24_iterators/front_insert_iterator/requirements/
	constexpr.cc: New.
	* testsuite/24_iterators/headers/iterator/synopsis_c++17.cc: Make test
	C++17 only and block insert_iterator tests for C++17 (because of include
	of synopsis_c++20.cc.
	* testsuite/24_iterators/headers/iterator/synopsis_c++20.cc: Add
	constexpr inserter tests.

Index: include/bits/stl_iterator.h
===
--- include/bits/stl_iterator.h	(revision 278302)
+++ include/bits/stl_iterator.h	(working copy)
@@ -497,8 +497,12 @@
   /// A nested typedef for the type of whatever container you used.
   typedef _Container  container_type;
 
+#if __cplusplus > 201703L
+  constexpr back_insert_iterator() noexcept = default;
+#endif
+
   /// The only way to create this %iterator is with a container.
-  explicit
+  explicit _GLIBCXX20_CONSTEXPR
   back_insert_iterator(_Container& __x)
   : container(std::__addressof(__x)) { }
 
@@ -521,7 +525,7 @@
 	return *this;
   }
 #else
-  back_insert_iterator&
+  _GLIBCXX20_CONSTEXPR back_insert_iterator&
   operator=(const typename _Container::value_type& __value)
   {
 	container->push_back(__value);
@@ -528,7 +532,7 @@
 	return *this;
   }
 
-  back_insert_iterator&
+  _GLIBCXX20_CONSTEXPR back_insert_iterator&
   operator=(typename _Container::value_type&& __value)
   {
 	container->push_back(std::move(__value));
@@ -537,17 +541,17 @@
 #endif
 
   /// Simply returns *this.
-  back_insert_iterator&
+  _GLIBCXX20_CONSTEXPR back_insert_iterator&
   operator*()
   { return *this; }
 
   /// Simply returns *this.  (This %iterator does not @a move.)
-  back_insert_iterator&
+  _GLIBCXX20_CONSTEXPR back_insert_iterator&
   operator++()
   { return *this; }
 
   /// Simply returns *this.  (This %iterator does not @a move.)
-  back_insert_iterator
+  _GLIBCXX20_CONSTEXPR back_insert_iterator
   operator++(int)
   { return *this; }
 };
@@ -564,7 +568,7 @@
*  types for you.
   */
   template
-inline back_insert_iterator<_Container>
+inline _GLIBCXX20_CONSTEXPR back_insert_iterator<_Container>
 back_inserter(_Container& __x)
 { return back_insert_iterator<_Container>(__x); }
 
@@ -589,8 +593,13 @@
   /// A nested typedef for the type of whatever container you used.
   typedef _Container  container_type;
 
+#if __cplusplus > 201703L
+  constexpr front_insert_iterator() noexcept = default;
+#endif
+
   /// The only way to create this %iterator is with a container.
-  explicit front_insert_iterator(_Container& __x)
+  explicit _GLIBCXX20_CONSTEXPR
+  front_insert_iterator(_Container& __x)
   : container(std::__addressof(__x)) { }
 
   /**
@@ -612,14 +621,13 @@
 	return *this;
   }
 #else
-  front_insert_iterator&
+  _GLIBCXX20_CONSTEXPR front_insert_iterator&
   operator=(const typename _Container::value_type& __value)
   {
 	container->push_front(__value);
 	return *this;
   }
-
-  front_insert_iterator&
+  _GLIBCXX20_CONSTEXPR front_insert_iterator&
   operator=(typename _Container::value_type&& __value)
   {
 	container->push_front(std::move(__value));
@@ -628,17 +636,17 @@
 #endif
 
   /// Simply returns *this.
-  front_insert_iterator&
+  _GLIBCXX20_CONSTEXPR front_insert_iterator&
   operator*()
   { return *this; }
 
   /// Simply returns *this.  (This %iterator does not @a move.)
-  front_insert_iterator&
+  _GLIBCXX20_CONSTEXPR front_insert_iterator&
   operator++()
   { return *this; }
 
   /// Simply returns *this.  (This %iterator does not @a move.)
-  front_insert_iterator
+  _GLIBCXX20_CONSTEXPR front_insert_iterator
   operator++(int)
   { return *this; }
 };
@@ -655,7 

Re: [PATCH] extend missing nul checks to all built-ins (PR 88226)

2019-11-15 Thread Jeff Law
On 11/14/19 10:38 AM, Martin Sebor wrote:
> GCC 9 added checks for usafe uses of unterminated constant char
> arrays to a few string functions but the checking is far from
> comprehensive.  It's been on my list of things to do to do
> a more thorough review and add the checks where they're missing.
> 
> The attached patch does this for the majority of common built-ins.
> There still are a few where it could be added but this should cover
> most of the commonly used ones where the misuses are likely to come
> up.
> 
> This patch depends on the one I posted earlier today for PR 92501:
>   https://gcc.gnu.org/ml/gcc-patches/2019-11/msg01233.html
> 
> I tested both patches together on x86_64-linux.
> 
> Martin
> 
> PS I considered introducing a new attribute, say string, first
> to reduce the extent of the changes in GCC, and second to provide
> a mechanism to let GCC check even user-defined functions for these
> bugs.  I stopped short of doing this because most of the changes
> to the built-ins are necessary either way, and also because it
> seems late in the cycle to introduce such an extension.  Unless
> there's a strong preference for adding it now I will revisit
> the decision for GCC 11.
> 
> gcc-88226.diff
> 
> PR middle-end/88226 - missing warning on fprintf, fputs, and puts with an 
> unterminated array
> 
> gcc/ChangeLog:
> 
>   PR middle-end/88226
>   * builtins.c (check_nul_terminated_array): New function.
>   (fold_builtin_0): Remove declaration.
>   (fold_builtin_1): Same.
>   (fold_builtin_2): Same.
>   (fold_builtin_3): Same.
>   (fold_builtin_strpbrk): Add argument.
>   (fold_builtin_strspn): Same.
>   (fold_builtin_strcspn): Same.
>   (expand_builtin_strcat): Call it.  Remove unused argument.
>   (expand_builtin_stpncpy): Same.
>   (expand_builtin_strncat): Same.
>   (expand_builtin_strncpy): Same.  Adjust indentation.
>   (expand_builtin_strcmp): Same.
>   (expand_builtin_strncmp): Same.
>   (expand_builtin_fork_or_exec): Same.
>   (expand_builtin): Handle more built-ins.
>   (fold_builtin_2): Add argument.
>   (fold_builtin_n): Make static.  Add argument.
>   (fold_call_expr): Pass new argument to fold_builtin_n and 
> fold_builtin_2.
>   (fold_builtin_call_array): Pass new argument to fold_builtin_n.
>   (fold_builtin_strpbrk): Add argument.  Call check_nul_terminated_array.
>   (fold_call_stmt): Pass new argument to fold_builtin_n.
>   * builtins.h: Correct a comment.
>   * gimple-fold.c (gimple_fold_builtin_strchr): Call
>   check_nul_terminated_array.
>   * tree-ssa-strlen.c (handle_builtin_strlen): Call
>   check_nul_terminated_array.
>   (handle_builtin_strchr): Same.
>   (handle_builtin_string_cmp): Same.
> 
> gcc/testsuite/ChangeLog:
>   PR middle-end/88226
>   * gcc.dg/Wstringop-overflow-22.c: New test.
>   * gcc.dg/tree-ssa/builtin-fprintf-warn-1.c: Remove xfails.
OK
jeff



Re: [PATCH] fold strncmp of unterminated arrays (PR 92501)

2019-11-15 Thread Jeff Law
On 11/14/19 10:11 AM, Martin Sebor wrote:
> Adding tests for unsafe uses of unterminated constant char arrays
> in string functions exposed the limitation in strncmp folding
> described in PR 92501: GCC only folds strncmp calls involving
> nul-terminated constant strings.
> 
> The attached patch improves the folder to also handle unterminated
> constant character arrays.  This capability is in turn relied on
> for the dependable detection of unsafe uses of unterminated arrays
> in strncpy, a patch for which I'm about to post separately.
> 
> Tested on x86_64-linux.
> 
> Martin
> 
> gcc-92501.diff
> 
> PR tree-optimization/92501 - strncmp with constant unterminated arrays not 
> folded
> 
> gcc/testsuite/ChangeLog:
> 
>   PR tree-optimization/92501
>   * gcc.dg/strcmpopt_7.c: New test.
> 
> gcc/ChangeLog:
> 
>   PR tree-optimization/92501
>   * gimple-fold.c ((gimple_fold_builtin_string_compare): Let strncmp
>   handle unterminated arrays.  Rename local variables for clarity.
> 
> Index: gcc/gimple-fold.c
> ===
> --- gcc/gimple-fold.c (revision 278253)
> +++ gcc/gimple-fold.c (working copy)
> @@ -2361,9 +2361,32 @@ gimple_fold_builtin_string_compare (gimple_stmt_it
>return true;
>  }
>  
> -  const char *p1 = c_getstr (str1);
> -  const char *p2 = c_getstr (str2);
> +  /* Initially set to the number of characters, including the terminating
> + nul if each array has one.   Nx == strnlen(Sx, Nx) implies that
> + the array is not terminated by a nul.
> + For nul-terminated strings then adjusted to their length.  */
> +  unsigned HOST_WIDE_INT len1 = HOST_WIDE_INT_MAX, len2 = len1;
> +  const char *p1 = c_getstr (str1, );
> +  const char *p2 = c_getstr (str2, );
>  
> +  /* The position of the terminting nul character if one exists, otherwise
terminting/terminating/


OK with the nit fixed.
jeff



[PATCH, libstdc++] Implement C++20 p1032 default_searcher constexprosity.

2019-11-15 Thread Smith-Rowland, Edward M
Pretty self-explanatory.
Ed
2019-11-15  Edward Smith-Rowland  <3dw...@verizon.net>

	Implement the default_searcher part of C++20 p1032 Misc constexpr bits.
	* include/std/functional
	(default_searcher, default_searcher::operator()): Constexpr.
	* testsuite/20_util/function_objects/constexpr_searcher.cc: New.



Index: include/std/functional
===
--- include/std/functional	(revision 278302)
+++ include/std/functional	(working copy)
@@ -1000,6 +1000,7 @@
 class default_searcher
 {
 public:
+  _GLIBCXX20_CONSTEXPR
   default_searcher(_ForwardIterator1 __pat_first,
 		   _ForwardIterator1 __pat_last,
 		   _BinaryPredicate __pred = _BinaryPredicate())
@@ -1007,7 +1008,8 @@
   { }
 
   template
-pair<_ForwardIterator2, _ForwardIterator2>
+	_GLIBCXX20_CONSTEXPR
+	pair<_ForwardIterator2, _ForwardIterator2>
 	operator()(_ForwardIterator2 __first, _ForwardIterator2 __last) const
 	{
 	  _ForwardIterator2 __first_ret =
Index: testsuite/20_util/function_objects/constexpr_searcher.cc
===
--- testsuite/20_util/function_objects/constexpr_searcher.cc	(nonexistent)
+++ testsuite/20_util/function_objects/constexpr_searcher.cc	(working copy)
@@ -0,0 +1,52 @@
+// Copyright (C) 2014-2019 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library.  This library is free
+// software; you can redistribute it and/or modify it under the
+// terms of the GNU General Public License as published by the
+// Free Software Foundation; either version 3, or (at your option)
+// any later version.
+
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License along
+// with this library; see the file COPYING3.  If not see
+// .
+
+// { dg-options "-std=gnu++2a" }
+// { dg-do compile { target c++2a } }
+
+#include 
+#include 
+
+const std::string_view
+patt = "World";
+
+constexpr std::string_view
+greet = "Hello, Humongous World of Wonder!!!";
+
+const std::wstring_view
+wpatt = L"World";
+
+constexpr std::wstring_view
+wgreet = L"Hello, Humongous World of Wonder!!!";
+
+constexpr bool
+test_searcher()
+{
+  auto ok = true;
+
+  const std::default_searcher search(patt.begin(), patt.end(),
+ std::equal_to<>());
+  const auto find = search(greet.begin(), greet.end());
+
+  const std::default_searcher wsearch(wpatt.begin(), wpatt.end(),
+  std::equal_to<>());
+  const auto wfind = wsearch(wgreet.begin(), wgreet.end());
+
+  return ok;
+}
+
+static_assert(test_searcher());


[PATCH] libstdc++: Implement LWG 3149 for std::default_constructible

2019-11-15 Thread Jonathan Wakely

The change approved in Belfast did not actually rename the concept from
std::default_constructible to std::default_initializable, even though
that was intended. That is expected to be done soon as a separate issue,
so I'm implementing that now too.

* include/bits/iterator_concepts.h (weakly_incrementable): Adjust.
* include/std/concepts (default_constructible): Rename to
default_initializable and require default-list-initialization and
default-initialization to be valid (LWG 3149).
(semiregular): Adjust to new name.
* testsuite/std/concepts/concepts.lang/concept.defaultconstructible/
1.cc: Rename directory to concept.defaultinitializable and adjust to
new name.
* testsuite/std/concepts/concepts.lang/concept.defaultinitializable/
lwg3149.cc: New test.
* testsuite/util/testsuite_iterators.h (test_range): Adjust.

Tested powerpc64le-linux, committed to trunk.

commit 7c6d180793479fa8ccc05e0764e90a7b16c48986
Author: Jonathan Wakely 
Date:   Fri Nov 15 16:31:08 2019 +

libstdc++: Implement LWG 3149 for std::default_constructible

The change approved in Belfast did not actually rename the concept from
std::default_constructible to std::default_initializable, even though
that was intended. That is expected to be done soon as a separate issue,
so I'm implementing that now too.

* include/bits/iterator_concepts.h (weakly_incrementable): Adjust.
* include/std/concepts (default_constructible): Rename to
default_initializable and require default-list-initialization and
default-initialization to be valid (LWG 3149).
(semiregular): Adjust to new name.
* testsuite/std/concepts/concepts.lang/concept.defaultconstructible/
1.cc: Rename directory to concept.defaultinitializable and adjust to
new name.
* testsuite/std/concepts/concepts.lang/concept.defaultinitializable/
lwg3149.cc: New test.
* testsuite/util/testsuite_iterators.h (test_range): Adjust.

diff --git a/libstdc++-v3/include/bits/iterator_concepts.h 
b/libstdc++-v3/include/bits/iterator_concepts.h
index 90a8bc8071f..3843ba5d57f 100644
--- a/libstdc++-v3/include/bits/iterator_concepts.h
+++ b/libstdc++-v3/include/bits/iterator_concepts.h
@@ -506,7 +506,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
 
   /// Requirements on types that can be incremented with ++.
   template
-concept weakly_incrementable = default_constructible<_Iter>
+concept weakly_incrementable = default_initializable<_Iter>
   && movable<_Iter>
   && requires(_Iter __i)
   {
diff --git a/libstdc++-v3/include/std/concepts 
b/libstdc++-v3/include/std/concepts
index e6d405a1bee..98b38940c56 100644
--- a/libstdc++-v3/include/std/concepts
+++ b/libstdc++-v3/include/std/concepts
@@ -138,9 +138,14 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
 concept constructible_from
   = destructible<_Tp> && is_constructible_v<_Tp, _Args...>;
 
-  /// [concept.defaultconstructible], concept default_constructible
+  /// [concept.defaultinitializable], concept default_initializable
   template
-concept default_constructible = constructible_from<_Tp>;
+concept default_initializable = constructible_from<_Tp>
+  && requires
+  {
+   _Tp{};
+   (void) ::new _Tp;
+  };
 
   /// [concept.moveconstructible], concept move_constructible
   template
@@ -249,7 +254,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
   && assignable_from<_Tp&, const _Tp&>;
 
   template
-concept semiregular = copyable<_Tp> && default_constructible<_Tp>;
+concept semiregular = copyable<_Tp> && default_initializable<_Tp>;
 
   // [concepts.compare], comparison concepts
 
diff --git 
a/libstdc++-v3/testsuite/std/concepts/concepts.lang/concept.defaultconstructible/1.cc
 
b/libstdc++-v3/testsuite/std/concepts/concepts.lang/concept.defaultinitializable/1.cc
similarity index 50%
rename from 
libstdc++-v3/testsuite/std/concepts/concepts.lang/concept.defaultconstructible/1.cc
rename to 
libstdc++-v3/testsuite/std/concepts/concepts.lang/concept.defaultinitializable/1.cc
+++ 
b/libstdc++-v3/testsuite/std/concepts/concepts.lang/concept.defaultinitializable/1.cc
@@ -20,28 +20,28 @@
 
 #include 
 
-static_assert( !std::default_constructible );
-static_assert( std::default_constructible );
-static_assert( std::default_constructible );
-static_assert( std::default_constructible );
-static_assert( std::default_constructible );
-static_assert( std::default_constructible );
-static_assert( std::default_constructible );
-static_assert( !std::default_constructible );
-static_assert( !std::default_constructible );
-static_assert( !std::default_constructible );
-static_assert( !std::default_constructible );
-static_assert( std::default_constructible );
-static_assert( !std::default_constructible );
-static_assert( std::default_constructible );
-static_assert( 

[PATCH] libstdc++: Implement LWG 3070 in path::lexically_relative

2019-11-15 Thread Jonathan Wakely

* src/c++17/fs_path.cc [_GLIBCXX_FILESYSTEM_IS_WINDOWS]
(is_disk_designator): New helper function.
(path::_Parser::root_path()): Use is_disk_designator.
(path::lexically_relative(const path&)): Implement resolution of
LWG 3070.
* testsuite/27_io/filesystem/path/generation/relative.cc: Check with
path components that look like a root-name.

Tested x86_64-mingw-w64, committed to trunk.

commit 737cef7acaa65e12e106073e8a7dbdf91356a484
Author: Jonathan Wakely 
Date:   Fri Nov 15 15:24:23 2019 +

libstdc++: Implement LWG 3070 in path::lexically_relative

* src/c++17/fs_path.cc [_GLIBCXX_FILESYSTEM_IS_WINDOWS]
(is_disk_designator): New helper function.
(path::_Parser::root_path()): Use is_disk_designator.
(path::lexically_relative(const path&)): Implement resolution of
LWG 3070.
* testsuite/27_io/filesystem/path/generation/relative.cc: Check with
path components that look like a root-name.

diff --git a/libstdc++-v3/src/c++17/fs_path.cc 
b/libstdc++-v3/src/c++17/fs_path.cc
index 14842452354..5fba971fef6 100644
--- a/libstdc++-v3/src/c++17/fs_path.cc
+++ b/libstdc++-v3/src/c++17/fs_path.cc
@@ -47,6 +47,13 @@ static inline bool is_dir_sep(path::value_type ch)
 #endif
 }
 
+#ifdef _GLIBCXX_FILESYSTEM_IS_WINDOWS
+static inline bool is_disk_designator(std::wstring_view s)
+{
+  return s.length() == 2 && s[1] == L':';
+}
+#endif
+
 struct path::_Parser
 {
   using string_view_type = std::basic_string_view;
@@ -117,7 +124,7 @@ struct path::_Parser
  ++pos;
   }
 #ifdef _GLIBCXX_FILESYSTEM_IS_WINDOWS
-else if (len > 1 && input[1] == L':')
+else if (is_disk_designator(input.substr(0, 2)))
   {
// got disk designator
root.first.str = input.substr(0, 2);
@@ -1747,6 +1754,19 @@ path::lexically_relative(const path& base) const
   if (!has_root_directory() && base.has_root_directory())
 return ret;
   auto [a, b] = std::mismatch(begin(), end(), base.begin(), base.end());
+#ifdef _GLIBCXX_FILESYSTEM_IS_WINDOWS
+  // _GLIBCXX_RESOLVE_LIB_DEFECTS
+  // 3070. path::lexically_relative causes surprising results if a filename
+  // can also be a root-name
+  if (!empty())
+for (auto& p : _M_cmpts)
+  if (p._M_type() == _Type::_Filename && is_disk_designator(p.native()))
+   return ret;
+  if (!base.empty())
+for (auto i = b, end = base.end(); i != end; ++i)
+  if (i->_M_type() == _Type::_Filename && is_disk_designator(i->native()))
+   return ret;
+#endif
   if (a == end() && b == base.end())
 ret = ".";
   else
diff --git 
a/libstdc++-v3/testsuite/27_io/filesystem/path/generation/relative.cc 
b/libstdc++-v3/testsuite/27_io/filesystem/path/generation/relative.cc
index dde08d46f2c..b2ac27293b2 100644
--- a/libstdc++-v3/testsuite/27_io/filesystem/path/generation/relative.cc
+++ b/libstdc++-v3/testsuite/27_io/filesystem/path/generation/relative.cc
@@ -77,10 +77,26 @@ test03()
   compare_paths( path("/dir/.").lexically_relative("/dir/."), "." );
 }
 
+void
+test04()
+{
+#if defined(__MING32__) || defined(__MINGW64__)
+  // DR 3070
+  compare_paths(path("c:/f:o/bar").lexically_relative("c:/f:o/bar"), ".");
+  compare_paths(path("c:/foo/bar").lexically_relative("c:/foo/b:r"), 
"..\\bar");
+  compare_paths(path("c:/foo/b:r").lexically_relative("c:/foo/bar"), 
"..\\b:r");
+  compare_paths(path("c:/foo/b:").lexically_relative("c:/foo/b:"), "");
+  compare_paths(path("c:/foo/bar").lexically_relative("c:/foo/b:"), "");
+  compare_paths(path("c:/f:/bar").lexically_relative("c:/foo/bar"), "");
+  compare_paths(path("foo/bar").lexically_relative("foo/b:/bar"), "");
+#endif
+}
+
 int
 main()
 {
   test01();
   test02();
   test03();
+  test04();
 }


Re: [PATCH] m68k: add musl support

2019-11-15 Thread Szabolcs Nagy
On 15/11/2019 19:16, Jeff Law wrote:
> On 11/15/19 10:22 AM, Szabolcs Nagy wrote:
>> Add the dynamic linker name and fix a type name to use the public name
>> instead of the glibc internal name.
>>
>> Build tested on m68k-linux-musl and m68k-linux-gnu.
>>
>> gcc/ChangeLog:
>>
>> 2019-11-15  Szabolcs Nagy  
>>
>>  * config/m68k/linux.h (MUSL_DYNAMIC_LINKER): Define.
> This part is clearly fine.
> 
>>
>> libgcc/ChangeLog:
>>
>> 2019-11-15  Szabolcs Nagy  
>>
>>  * config/m68k/linux-unwind.h (struct uw_ucontext): Use sigset_t instead
>>  of __sigset_t.
> Do the linux builds still work after this change?  If so, then this is
> fine too.

in my testing it worked and i don't know of
corner cases where using __sigset_t would
be necessary.

committed at r278312.

thanks.



Re: [PATCH] musl: use correct long double abi by default

2019-11-15 Thread Szabolcs Nagy
On 15/11/2019 19:22, Segher Boessenkool wrote:
> On Fri, Nov 15, 2019 at 06:58:24PM +, Szabolcs Nagy wrote:
>> 2019-11-15  Szabolcs Nagy  
>>
>>  * configure.ac (gcc_cv_target_ldbl128): Set for *-musl* targets.
> 
> That is not what the patch does.  It sets it to yes for s390*-linux-musl*,
> it sets it to no for powerpc*-*-linux-musl*, and it doesn't do anything for
> other *-musl* configurations.

ok i can fix the changelog to:

* configure.ac (gcc_cv_target_ldbl128): Set for powerpc*-*-linux-musl*
and s390*-*-linux-musl* targets.

(but i think there is no other *-musl* target that uses gcc_cv_target_ldbl128
so the original was not entirely wrong either)

> 
> The powerpc part is okay for trunk, if this is what musl wants to do.
> (musl has no OS port maintainer listed in MAINTAINERS, maybe that should
> be fixed?)
> 
> 
> Segher
> 



[PATCH] MAINTAINERS: Change to my personal email address

2019-11-15 Thread Kelvin Nilsen
I'm leaving IBM and am changing my email to my my personal address.

ChangeLog:

2019-11-15  Kelvin Nilsen  

* MAINTAINERS: Change my email address as maintainer.

Index: MAINTAINERS
===
--- MAINTAINERS (revision 278306)
+++ MAINTAINERS (working copy)
@@ -524,7 +524,7 @@ Quentin Neill   

 Adam Nemet 
 Thomas Neumann 
 Dan Nicolaescu 
-Kelvin Nilsen  
+Kelvin Nilsen  
 James Norris
 Diego Novillo  
 Dorit Nuzman   


  1   2   3   >