Add new *_atomic counter update function

	PR gcov-profile/58306
	* Makefile.in: New functions (modules) are added.
	* libgcov-profiler.c (__gcov_interval_profiler_atomic): New
	function.
	(__gcov_pow2_profiler_atomic): New function.
	(__gcov_one_value_profiler_body): New argument is instroduced.
	(__gcov_one_value_profiler): Call with the new argument.
	(__gcov_one_value_profiler_atomic): Likewise.
	(__gcov_indirect_call_profiler_v2): Likewise.
	(__gcov_time_profiler_atomic): New function.
	(__gcov_average_profiler_atomic): Likewise.
	(__gcov_ior_profiler_atomic): Likewise.
	* libgcov.h: Declare the aforementioned functions.
	PR gcov-profile/58306
	* gcc.dg/tree-prof/val-profiler-threads-1.c: New test.
	PR gcov-profile/58306
	* tree-profile.c (gimple_init_edge_profiler): Create conditionally
	atomic variants of profile update functions.

From-SVN: r239324
diff --git a/libgcc/libgcov-profiler.c b/libgcc/libgcov-profiler.c
index a99d93b..70a821d 100644
--- a/libgcc/libgcov-profiler.c
+++ b/libgcc/libgcov-profiler.c
@@ -46,6 +46,26 @@
 }
 #endif
 
+#ifdef L_gcov_interval_profiler_atomic
+/* If VALUE is in interval <START, START + STEPS - 1>, then increases the
+   corresponding counter in COUNTERS.  If the VALUE is above or below
+   the interval, COUNTERS[STEPS] or COUNTERS[STEPS + 1] is increased
+   instead.  Function is thread-safe.  */
+
+void
+__gcov_interval_profiler_atomic (gcov_type *counters, gcov_type value,
+				 int start, unsigned steps)
+{
+  gcov_type delta = value - start;
+  if (delta < 0)
+    __atomic_fetch_add (&counters[steps + 1], 1, MEMMODEL_RELAXED);
+  else if (delta >= steps)
+    __atomic_fetch_add (&counters[steps], 1, MEMMODEL_RELAXED);
+  else
+    __atomic_fetch_add (&counters[delta], 1, MEMMODEL_RELAXED);
+}
+#endif
+
 #ifdef L_gcov_pow2_profiler
 /* If VALUE is a power of two, COUNTERS[1] is incremented.  Otherwise
    COUNTERS[0] is incremented.  */
@@ -60,6 +80,21 @@
 }
 #endif
 
+#ifdef L_gcov_pow2_profiler_atomic
+/* If VALUE is a power of two, COUNTERS[1] is incremented.  Otherwise
+   COUNTERS[0] is incremented.  Function is thread-safe.  */
+
+void
+__gcov_pow2_profiler_atomic (gcov_type *counters, gcov_type value)
+{
+  if (value == 0 || (value & (value - 1)))
+    __atomic_fetch_add (&counters[0], 1, MEMMODEL_RELAXED);
+  else
+    __atomic_fetch_add (&counters[1], 1, MEMMODEL_RELAXED);
+}
+#endif
+
+
 /* Tries to determine the most common value among its inputs.  Checks if the
    value stored in COUNTERS[0] matches VALUE.  If this is the case, COUNTERS[1]
    is incremented.  If this is not the case and COUNTERS[1] is not zero,
@@ -68,10 +103,12 @@
    function is called more than 50% of the time with one value, this value
    will be in COUNTERS[0] in the end.
 
-   In any case, COUNTERS[2] is incremented.  */
+   In any case, COUNTERS[2] is incremented.  If USE_ATOMIC is set to 1,
+   COUNTERS[2] is updated with an atomic instruction.  */
 
 static inline void
-__gcov_one_value_profiler_body (gcov_type *counters, gcov_type value)
+__gcov_one_value_profiler_body (gcov_type *counters, gcov_type value,
+				int use_atomic)
 {
   if (value == counters[0])
     counters[1]++;
@@ -82,14 +119,36 @@
     }
   else
     counters[1]--;
-  counters[2]++;
+
+  if (use_atomic)
+    __atomic_fetch_add (&counters[2], 1, MEMMODEL_RELAXED);
+  else
+    counters[2]++;
 }
 
 #ifdef L_gcov_one_value_profiler
 void
 __gcov_one_value_profiler (gcov_type *counters, gcov_type value)
 {
-  __gcov_one_value_profiler_body (counters, value);
+  __gcov_one_value_profiler_body (counters, value, 0);
+}
+#endif
+
+#ifdef L_gcov_one_value_profiler_atomic
+
+/* Update one value profilers (COUNTERS) for a given VALUE.
+
+   CAVEAT: Following function is not thread-safe, only total number
+   of executions (COUNTERS[2]) is update with an atomic instruction.
+   Problem is that one cannot atomically update two counters
+   (COUNTERS[0] and COUNTERS[1]), for more information please read
+   following email thread:
+   https://gcc.gnu.org/ml/gcc-patches/2016-08/msg00024.html.  */
+
+void
+__gcov_one_value_profiler_atomic (gcov_type *counters, gcov_type value)
+{
+  __gcov_one_value_profiler_body (counters, value, 1);
 }
 #endif
 
@@ -265,7 +324,7 @@
   if (cur_func == __gcov_indirect_call_callee
       || (__LIBGCC_VTABLE_USES_DESCRIPTORS__ && __gcov_indirect_call_callee
           && *(void **) cur_func == *(void **) __gcov_indirect_call_callee))
-    __gcov_one_value_profiler_body (__gcov_indirect_call_counters, value);
+    __gcov_one_value_profiler_body (__gcov_indirect_call_counters, value, 0);
 }
 #endif
 
@@ -282,8 +341,19 @@
   if (!counters[0])
     counters[0] = ++function_counter;
 }
+
+/* Sets corresponding COUNTERS if there is no value.
+   Function is thread-safe.  */
+
+void
+__gcov_time_profiler_atomic (gcov_type* counters)
+{
+  if (!counters[0])
+    counters[0] = __atomic_add_fetch (&function_counter, 1, MEMMODEL_RELAXED);
+}
 #endif
 
+
 #ifdef L_gcov_average_profiler
 /* Increase corresponding COUNTER by VALUE.  FIXME: Perhaps we want
    to saturate up.  */
@@ -296,6 +366,18 @@
 }
 #endif
 
+#ifdef L_gcov_average_profiler_atomic
+/* Increase corresponding COUNTER by VALUE.  FIXME: Perhaps we want
+   to saturate up.  Function is thread-safe.  */
+
+void
+__gcov_average_profiler_atomic (gcov_type *counters, gcov_type value)
+{
+  __atomic_fetch_add (&counters[0], value, MEMMODEL_RELAXED);
+  __atomic_fetch_add (&counters[1], 1, MEMMODEL_RELAXED);
+}
+#endif
+
 #ifdef L_gcov_ior_profiler
 /* Bitwise-OR VALUE into COUNTER.  */
 
@@ -306,4 +388,15 @@
 }
 #endif
 
+#ifdef L_gcov_ior_profiler_atomic
+/* Bitwise-OR VALUE into COUNTER.  Function is thread-safe.  */
+
+void
+__gcov_ior_profiler_atomic (gcov_type *counters, gcov_type value)
+{
+  __atomic_fetch_or (&counters[0], value, MEMMODEL_RELAXED);
+}
+#endif
+
+
 #endif /* inhibit_libc */