From: Soumya AR <soum...@nvidia.com>

This patch extends various compiler components to handle the newly added
atomic fetch min/max builtins:

1. Address Sanitizer (asan): Extended to recognize atomic min/max builtins and
   detect invalid memory accesses/overflows when these operations are used.

2. gimple-ssa-warn-access: Extended to validate atomic min/max operations for
   invalid memory accesses at compile time.

3. Static Analyzer: Extended kf_atomic_fetch_op and kf_atomic_op_fetch classes
   to model the behavior of atomic min/max builtins.
   Note: The analyzer currently doesn't recognize ternary operators
   (e.g., i < j ? i : j) as MIN_EXPR/MAX_EXPR, so analyzer tests use constants
   to verify correct min/max computation in memory.

4. Thread Sanitizer (tsan): Since TSAN runtime doesn't currently support atomic
   min/max operations, these builtins are explicitly marked as unsupported.
   When -fsanitize=thread is used, the compiler emits a warning but the code
   still compiles and runs correctly - just without thread sanitization for
   these specific operations.

5. Forward Propagation (forwprop): Optimizes sequences where
   __atomic_fetch_min/max is followed by a min/max operation using the same
   values. When the original value returned by fetch_op isn't otherwise used,
   this pattern is canonicalized to the more efficient __atomic_min/max_fetch
   variant (which returns the new value instead of the old one).

Bootstrapped and regression tested on aarch64-linux-gnu and x86_64-linux-gnu.
Cross-compiled and regression tested for arm-linux-gnueabihf-armv7-a and
aarch64-linux-gnu without LSE.

Signed-off-by: Soumya AR <soum...@nvidia.com>

gcc/analyzer/ChangeLog:

        * kf.cc (register_atomic_builtins): Add support for atomic
        min/max builtins in static analyzer.

gcc/ChangeLog:

        * asan.cc (get_mem_refs_of_builtin_call): Handle atomic min/max
        builtins for memory access tracking.
        * gimple-ssa-warn-access.cc (pass_waccess::check_atomic_builtin):
        Extend invalid access detection for min/max atomics.
        * tree-ssa-forwprop.cc (simplify_builtin_call): Add canonicalization
        for atomic min/max builtins.
        * tsan.cc (enum tsan_atomic_action): Add warn_missing.
        (UNHANDLED): Define macro for unsupported operations.
        (instrument_builtin_call): Emit warning for unsupported min/max
        atomics with tsan.

gcc/testsuite/ChangeLog:

        * gcc.dg/Wstringop-overflow-78.c: Add tests for min/max atomic
        overflow detection.
        * gcc.dg/analyzer/atomic-builtins-1.c: Add analyzer tests for
        atomic min/max operations.
        * c-c++-common/asan/atomic-max-invalid.c: New test.
        * gcc.dg/tree-ssa/atomic-minmax-forwprop.c: New test.
        * gcc.dg/tsan/atomic-minmax.c: New test.
---
 gcc/analyzer/kf.cc                            |  85 +++++++
 gcc/asan.cc                                   |  40 ++++
 gcc/gimple-ssa-warn-access.cc                 |   8 +
 .../c-c++-common/asan/atomic-max-invalid.c    |  19 ++
 gcc/testsuite/gcc.dg/Wstringop-overflow-78.c  | 106 +++++++++
 .../gcc.dg/analyzer/atomic-builtins-1.c       | 207 ++++++++++++++++++
 .../gcc.dg/tree-ssa/atomic-minmax-forwprop.c  |  56 +++++
 gcc/testsuite/gcc.dg/tsan/atomic-minmax.c     |  48 ++++
 gcc/tree-ssa-forwprop.cc                      |   7 +
 gcc/tsan.cc                                   |  56 ++++-
 10 files changed, 631 insertions(+), 1 deletion(-)
 create mode 100644 gcc/testsuite/c-c++-common/asan/atomic-max-invalid.c
 create mode 100644 gcc/testsuite/gcc.dg/tree-ssa/atomic-minmax-forwprop.c
 create mode 100644 gcc/testsuite/gcc.dg/tsan/atomic-minmax.c

diff --git a/gcc/analyzer/kf.cc b/gcc/analyzer/kf.cc
index 2a7c3570315..685b518d984 100644
--- a/gcc/analyzer/kf.cc
+++ b/gcc/analyzer/kf.cc
@@ -191,6 +191,8 @@ public:
    type __atomic_fetch_and (type *ptr, type val, int memorder);
    type __atomic_fetch_xor (type *ptr, type val, int memorder);
    type __atomic_fetch_or (type *ptr, type val, int memorder);
+   type __atomic_fetch_min (type *ptr, type val, int memorder);
+   type __atomic_fetch_max (type *ptr, type val, int memorder);
 */
 
 class kf_atomic_fetch_op : public internal_known_function
@@ -234,6 +236,8 @@ private:
    type __atomic_and_fetch (type *ptr, type val, int memorder);
    type __atomic_xor_fetch (type *ptr, type val, int memorder);
    type __atomic_or_fetch (type *ptr, type val, int memorder);
+   type __atomic_min_fetch (type *ptr, type val, int memorder);
+   type __atomic_max_fetch (type *ptr, type val, int memorder);
 */
 
 class kf_atomic_op_fetch : public internal_known_function
@@ -2208,6 +2212,87 @@ register_atomic_builtins (known_function_manager &kfm)
           std::make_unique<kf_atomic_fetch_op> (BIT_IOR_EXPR));
   kfm.add (BUILT_IN_ATOMIC_FETCH_OR_16,
           std::make_unique<kf_atomic_fetch_op> (BIT_IOR_EXPR));
+  /* Atomic min/max operations.  */
+  kfm.add (BUILT_IN_ATOMIC_FETCH_SMIN_1,
+          std::make_unique<kf_atomic_fetch_op> (MIN_EXPR));
+  kfm.add (BUILT_IN_ATOMIC_FETCH_SMIN_2,
+          std::make_unique<kf_atomic_fetch_op> (MIN_EXPR));
+  kfm.add (BUILT_IN_ATOMIC_FETCH_SMIN_4,
+          std::make_unique<kf_atomic_fetch_op> (MIN_EXPR));
+  kfm.add (BUILT_IN_ATOMIC_FETCH_SMIN_8,
+          std::make_unique<kf_atomic_fetch_op> (MIN_EXPR));
+  kfm.add (BUILT_IN_ATOMIC_FETCH_SMIN_16,
+          std::make_unique<kf_atomic_fetch_op> (MIN_EXPR));
+  kfm.add (BUILT_IN_ATOMIC_FETCH_SMAX_1,
+          std::make_unique<kf_atomic_fetch_op> (MAX_EXPR));
+  kfm.add (BUILT_IN_ATOMIC_FETCH_SMAX_2,
+          std::make_unique<kf_atomic_fetch_op> (MAX_EXPR));
+  kfm.add (BUILT_IN_ATOMIC_FETCH_SMAX_4,
+          std::make_unique<kf_atomic_fetch_op> (MAX_EXPR));
+  kfm.add (BUILT_IN_ATOMIC_FETCH_SMAX_8,
+          std::make_unique<kf_atomic_fetch_op> (MAX_EXPR));
+  kfm.add (BUILT_IN_ATOMIC_FETCH_SMAX_16,
+          std::make_unique<kf_atomic_fetch_op> (MAX_EXPR));
+  kfm.add (BUILT_IN_ATOMIC_FETCH_UMIN_1,
+          std::make_unique<kf_atomic_fetch_op> (MIN_EXPR));
+  kfm.add (BUILT_IN_ATOMIC_FETCH_UMIN_2,
+          std::make_unique<kf_atomic_fetch_op> (MIN_EXPR));
+  kfm.add (BUILT_IN_ATOMIC_FETCH_UMIN_4,
+          std::make_unique<kf_atomic_fetch_op> (MIN_EXPR));
+  kfm.add (BUILT_IN_ATOMIC_FETCH_UMIN_8,
+          std::make_unique<kf_atomic_fetch_op> (MIN_EXPR));
+  kfm.add (BUILT_IN_ATOMIC_FETCH_UMIN_16,
+          std::make_unique<kf_atomic_fetch_op> (MIN_EXPR));
+  kfm.add (BUILT_IN_ATOMIC_FETCH_UMAX_1,
+          std::make_unique<kf_atomic_fetch_op> (MAX_EXPR));
+  kfm.add (BUILT_IN_ATOMIC_FETCH_UMAX_2,
+          std::make_unique<kf_atomic_fetch_op> (MAX_EXPR));
+  kfm.add (BUILT_IN_ATOMIC_FETCH_UMAX_4,
+          std::make_unique<kf_atomic_fetch_op> (MAX_EXPR));
+  kfm.add (BUILT_IN_ATOMIC_FETCH_UMAX_8,
+          std::make_unique<kf_atomic_fetch_op> (MAX_EXPR));
+  kfm.add (BUILT_IN_ATOMIC_FETCH_UMAX_16,
+          std::make_unique<kf_atomic_fetch_op> (MAX_EXPR));
+  kfm.add (BUILT_IN_ATOMIC_SMIN_FETCH_1,
+          std::make_unique<kf_atomic_op_fetch> (MIN_EXPR));
+  kfm.add (BUILT_IN_ATOMIC_SMIN_FETCH_2,
+          std::make_unique<kf_atomic_op_fetch> (MIN_EXPR));
+  kfm.add (BUILT_IN_ATOMIC_SMIN_FETCH_4,
+          std::make_unique<kf_atomic_op_fetch> (MIN_EXPR));
+  kfm.add (BUILT_IN_ATOMIC_SMIN_FETCH_8,
+          std::make_unique<kf_atomic_op_fetch> (MIN_EXPR));
+  kfm.add (BUILT_IN_ATOMIC_SMIN_FETCH_16,
+          std::make_unique<kf_atomic_op_fetch> (MIN_EXPR));
+  kfm.add (BUILT_IN_ATOMIC_SMAX_FETCH_1,
+          std::make_unique<kf_atomic_op_fetch> (MAX_EXPR));
+  kfm.add (BUILT_IN_ATOMIC_SMAX_FETCH_2,
+          std::make_unique<kf_atomic_op_fetch> (MAX_EXPR));
+  kfm.add (BUILT_IN_ATOMIC_SMAX_FETCH_4,
+          std::make_unique<kf_atomic_op_fetch> (MAX_EXPR));
+  kfm.add (BUILT_IN_ATOMIC_SMAX_FETCH_8,
+          std::make_unique<kf_atomic_op_fetch> (MAX_EXPR));
+  kfm.add (BUILT_IN_ATOMIC_SMAX_FETCH_16,
+          std::make_unique<kf_atomic_op_fetch> (MAX_EXPR));
+  kfm.add (BUILT_IN_ATOMIC_UMIN_FETCH_1,
+          std::make_unique<kf_atomic_op_fetch> (MIN_EXPR));
+  kfm.add (BUILT_IN_ATOMIC_UMIN_FETCH_2,
+          std::make_unique<kf_atomic_op_fetch> (MIN_EXPR));
+  kfm.add (BUILT_IN_ATOMIC_UMIN_FETCH_4,
+          std::make_unique<kf_atomic_op_fetch> (MIN_EXPR));
+  kfm.add (BUILT_IN_ATOMIC_UMIN_FETCH_8,
+          std::make_unique<kf_atomic_op_fetch> (MIN_EXPR));
+  kfm.add (BUILT_IN_ATOMIC_UMIN_FETCH_16,
+          std::make_unique<kf_atomic_op_fetch> (MIN_EXPR));
+  kfm.add (BUILT_IN_ATOMIC_UMAX_FETCH_1,
+          std::make_unique<kf_atomic_op_fetch> (MAX_EXPR));
+  kfm.add (BUILT_IN_ATOMIC_UMAX_FETCH_2,
+          std::make_unique<kf_atomic_op_fetch> (MAX_EXPR));
+  kfm.add (BUILT_IN_ATOMIC_UMAX_FETCH_4,
+          std::make_unique<kf_atomic_op_fetch> (MAX_EXPR));
+  kfm.add (BUILT_IN_ATOMIC_UMAX_FETCH_8,
+          std::make_unique<kf_atomic_op_fetch> (MAX_EXPR));
+  kfm.add (BUILT_IN_ATOMIC_UMAX_FETCH_16,
+          std::make_unique<kf_atomic_op_fetch> (MAX_EXPR));
 }
 
 /* Handle calls to the various IFN_UBSAN_* with no return value.
diff --git a/gcc/asan.cc b/gcc/asan.cc
index 748b289d6f9..bd8c96932d6 100644
--- a/gcc/asan.cc
+++ b/gcc/asan.cc
@@ -1155,6 +1155,14 @@ get_mem_refs_of_builtin_call (gcall *call,
     case BUILT_IN_ATOMIC_FETCH_NAND_1:
     case BUILT_IN_ATOMIC_FETCH_XOR_1:
     case BUILT_IN_ATOMIC_FETCH_OR_1:
+    case BUILT_IN_ATOMIC_FETCH_SMIN_1:
+    case BUILT_IN_ATOMIC_FETCH_SMAX_1:
+    case BUILT_IN_ATOMIC_FETCH_UMIN_1:
+    case BUILT_IN_ATOMIC_FETCH_UMAX_1:
+    case BUILT_IN_ATOMIC_SMIN_FETCH_1:
+    case BUILT_IN_ATOMIC_SMAX_FETCH_1:
+    case BUILT_IN_ATOMIC_UMIN_FETCH_1:
+    case BUILT_IN_ATOMIC_UMAX_FETCH_1:
       access_size = 1;
       goto do_atomic;
 
@@ -1192,6 +1200,14 @@ get_mem_refs_of_builtin_call (gcall *call,
     case BUILT_IN_ATOMIC_FETCH_NAND_2:
     case BUILT_IN_ATOMIC_FETCH_XOR_2:
     case BUILT_IN_ATOMIC_FETCH_OR_2:
+    case BUILT_IN_ATOMIC_FETCH_SMIN_2:
+    case BUILT_IN_ATOMIC_FETCH_SMAX_2:
+    case BUILT_IN_ATOMIC_FETCH_UMIN_2:
+    case BUILT_IN_ATOMIC_FETCH_UMAX_2:
+    case BUILT_IN_ATOMIC_SMIN_FETCH_2:
+    case BUILT_IN_ATOMIC_SMAX_FETCH_2:
+    case BUILT_IN_ATOMIC_UMIN_FETCH_2:
+    case BUILT_IN_ATOMIC_UMAX_FETCH_2:
       access_size = 2;
       goto do_atomic;
 
@@ -1229,6 +1245,14 @@ get_mem_refs_of_builtin_call (gcall *call,
     case BUILT_IN_ATOMIC_FETCH_NAND_4:
     case BUILT_IN_ATOMIC_FETCH_XOR_4:
     case BUILT_IN_ATOMIC_FETCH_OR_4:
+    case BUILT_IN_ATOMIC_FETCH_SMIN_4:
+    case BUILT_IN_ATOMIC_FETCH_SMAX_4:
+    case BUILT_IN_ATOMIC_FETCH_UMIN_4:
+    case BUILT_IN_ATOMIC_FETCH_UMAX_4:
+    case BUILT_IN_ATOMIC_SMIN_FETCH_4:
+    case BUILT_IN_ATOMIC_SMAX_FETCH_4:
+    case BUILT_IN_ATOMIC_UMIN_FETCH_4:
+    case BUILT_IN_ATOMIC_UMAX_FETCH_4:
       access_size = 4;
       goto do_atomic;
 
@@ -1266,6 +1290,14 @@ get_mem_refs_of_builtin_call (gcall *call,
     case BUILT_IN_ATOMIC_FETCH_NAND_8:
     case BUILT_IN_ATOMIC_FETCH_XOR_8:
     case BUILT_IN_ATOMIC_FETCH_OR_8:
+    case BUILT_IN_ATOMIC_FETCH_SMIN_8:
+    case BUILT_IN_ATOMIC_FETCH_SMAX_8:
+    case BUILT_IN_ATOMIC_FETCH_UMIN_8:
+    case BUILT_IN_ATOMIC_FETCH_UMAX_8:
+    case BUILT_IN_ATOMIC_SMIN_FETCH_8:
+    case BUILT_IN_ATOMIC_SMAX_FETCH_8:
+    case BUILT_IN_ATOMIC_UMIN_FETCH_8:
+    case BUILT_IN_ATOMIC_UMAX_FETCH_8:
       access_size = 8;
       goto do_atomic;
 
@@ -1303,6 +1335,14 @@ get_mem_refs_of_builtin_call (gcall *call,
     case BUILT_IN_ATOMIC_FETCH_NAND_16:
     case BUILT_IN_ATOMIC_FETCH_XOR_16:
     case BUILT_IN_ATOMIC_FETCH_OR_16:
+    case BUILT_IN_ATOMIC_FETCH_SMIN_16:
+    case BUILT_IN_ATOMIC_FETCH_SMAX_16:
+    case BUILT_IN_ATOMIC_FETCH_UMIN_16:
+    case BUILT_IN_ATOMIC_FETCH_UMAX_16:
+    case BUILT_IN_ATOMIC_SMIN_FETCH_16:
+    case BUILT_IN_ATOMIC_SMAX_FETCH_16:
+    case BUILT_IN_ATOMIC_UMIN_FETCH_16:
+    case BUILT_IN_ATOMIC_UMAX_FETCH_16:
       access_size = 16;
       /* FALLTHRU */
     do_atomic:
diff --git a/gcc/gimple-ssa-warn-access.cc b/gcc/gimple-ssa-warn-access.cc
index 0f4aff6b59b..f64e9735925 100644
--- a/gcc/gimple-ssa-warn-access.cc
+++ b/gcc/gimple-ssa-warn-access.cc
@@ -3098,12 +3098,20 @@ pass_waccess::check_atomic_builtin (gcall *stmt)
     case BUILT_IN_ATOMIC_NAND_FETCH_ ## N:             \
     case BUILT_IN_ATOMIC_XOR_FETCH_ ## N:              \
     case BUILT_IN_ATOMIC_OR_FETCH_ ## N:               \
+    case BUILT_IN_ATOMIC_SMIN_FETCH_ ## N:             \
+    case BUILT_IN_ATOMIC_SMAX_FETCH_ ## N:             \
+    case BUILT_IN_ATOMIC_UMIN_FETCH_ ## N:             \
+    case BUILT_IN_ATOMIC_UMAX_FETCH_ ## N:             \
     case BUILT_IN_ATOMIC_FETCH_ADD_ ## N:              \
     case BUILT_IN_ATOMIC_FETCH_SUB_ ## N:              \
     case BUILT_IN_ATOMIC_FETCH_AND_ ## N:              \
     case BUILT_IN_ATOMIC_FETCH_NAND_ ## N:             \
     case BUILT_IN_ATOMIC_FETCH_OR_ ## N:               \
     case BUILT_IN_ATOMIC_FETCH_XOR_ ## N:              \
+    case BUILT_IN_ATOMIC_FETCH_SMIN_ ## N:             \
+    case BUILT_IN_ATOMIC_FETCH_SMAX_ ## N:             \
+    case BUILT_IN_ATOMIC_FETCH_UMIN_ ## N:             \
+    case BUILT_IN_ATOMIC_FETCH_UMAX_ ## N:             \
        bytes = N;                                      \
        if (sucs_arg == UINT_MAX)                       \
          sucs_arg = 2;                                 \
diff --git a/gcc/testsuite/c-c++-common/asan/atomic-max-invalid.c 
b/gcc/testsuite/c-c++-common/asan/atomic-max-invalid.c
new file mode 100644
index 00000000000..20f290470e7
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/asan/atomic-max-invalid.c
@@ -0,0 +1,19 @@
+/* Test that ASAN catches invalid memory access with atomic smax builtin.  */
+/* { dg-do run } */
+/* { dg-shouldfail "asan" } */
+
+#include <stdint.h>
+
+int32_t test_smax (int32_t *x) {
+   return __atomic_fetch_max (x, 100, 0);
+}
+
+int main() {
+    int32_t *p = (int32_t *) __builtin_malloc (sizeof(int16_t));
+    asm volatile ("" : "+r" (p) : : "memory");
+    test_smax (p);
+    asm volatile ("" : "+r" (p) : : "memory");
+    return 0;
+}
+
+/* { dg-output "ERROR: AddressSanitizer: heap-buffer-overflow" } */ 
\ No newline at end of file
diff --git a/gcc/testsuite/gcc.dg/Wstringop-overflow-78.c 
b/gcc/testsuite/gcc.dg/Wstringop-overflow-78.c
index a25a418ed76..93d3c767d7c 100644
--- a/gcc/testsuite/gcc.dg/Wstringop-overflow-78.c
+++ b/gcc/testsuite/gcc.dg/Wstringop-overflow-78.c
@@ -16,6 +16,8 @@
 #define or_fetch(p, q)    __atomic_or_fetch (p, q, 0)
 #define xor_fetch(p, q)   __atomic_xor_fetch (p, q, 0)
 #define nand_fetch(p, q)  __atomic_nand_fetch (p, q, 0)
+#define min_fetch(p, q)   __atomic_min_fetch (p, q, 0)
+#define max_fetch(p, q)   __atomic_max_fetch (p, q, 0)
 #define exchange(p, q, r) __atomic_exchange (p, q, r, 0)
 #define exchange_n(p, n)  __atomic_exchange_n (p, n, 0)
 #define cmpxchg(p, q, r)  __atomic_compare_exchange (p, q, r, __COUNTER__, 0, 
0)
@@ -485,6 +487,110 @@ NOIPA void warn_atomic_exchange_n (void)
 }
 
 
+NOIPA void nowarn_atomic_min_fetch (void)
+{
+  _Atomic char *pc = &eac;
+  min_fetch (pc, ecc);
+
+  _Atomic short *psi = &easi;
+  min_fetch (psi, esi);
+
+  _Atomic int *pi = &eai;
+  min_fetch (pi, ei);
+
+  _Atomic long *pli = &eali;
+  min_fetch (pli, eli);
+
+  _Atomic long long *plli = &ealli;
+  min_fetch (plli, elli);
+}
+
+
+NOIPA void warn_atomic_min_fetch (void)
+{
+  _Atomic char *pc = &eac + 1;
+  min_fetch (pc, ecc);                  // { dg-warning "-Wstringop-overflow" }
+
+  _Atomic short *psi = (_Atomic short*)((char*)&easi + 1);
+  min_fetch (psi, esi);                 // { dg-warning "-Wstringop-overflow" }
+  psi = (_Atomic short*)((char*)&easi + 2);
+  min_fetch (psi, esi);                 // { dg-warning "-Wstringop-overflow" }
+
+  _Atomic int *pi = (_Atomic int*)((char*)&eai + 1);
+  min_fetch (pi, ei);                   // { dg-warning "-Wstringop-overflow" }
+  pi = (_Atomic int*)((char*)&eai + 2);
+  min_fetch (pi, ei);                   // { dg-warning "-Wstringop-overflow" }
+  pi = (_Atomic int*)((char*)&eai + sizeof eai);
+  min_fetch (pi, ei);                   // { dg-warning "-Wstringop-overflow" }
+
+  _Atomic long *pli = (_Atomic long*)((char*)&eali + 1);
+  min_fetch (pli, eli);                 // { dg-warning "-Wstringop-overflow" }
+  pli = (_Atomic long*)((char*)&eali + 1);
+  min_fetch (pli, eli);                 // { dg-warning "-Wstringop-overflow" }
+  pli = &eali + 1;
+  min_fetch (pli, eli);                 // { dg-warning "-Wstringop-overflow" }
+
+  _Atomic long long *plli = (_Atomic long long*)((char*)&ealli + 1);
+  min_fetch (plli, elli);               // { dg-warning "-Wstringop-overflow" }
+  plli = (_Atomic long long*)((char*)&ealli + 1);
+  min_fetch (plli, eali);               // { dg-warning "-Wstringop-overflow" }
+  plli = &ealli + 1;
+  min_fetch (plli, elli);               // { dg-warning "-Wstringop-overflow" }
+}
+
+
+NOIPA void nowarn_atomic_max_fetch (void)
+{
+  _Atomic char *pc = &eac;
+  max_fetch (pc, ecc);
+
+  _Atomic short *psi = &easi;
+  max_fetch (psi, esi);
+
+  _Atomic int *pi = &eai;
+  max_fetch (pi, ei);
+
+  _Atomic long *pli = &eali;
+  max_fetch (pli, eli);
+
+  _Atomic long long *plli = &ealli;
+  max_fetch (plli, elli);
+}
+
+
+NOIPA void warn_atomic_max_fetch (void)
+{
+  _Atomic char *pc = &eac + 1;
+  max_fetch (pc, ecc);                  // { dg-warning "-Wstringop-overflow" }
+
+  _Atomic short *psi = (_Atomic short*)((char*)&easi + 1);
+  max_fetch (psi, esi);                 // { dg-warning "-Wstringop-overflow" }
+  psi = (_Atomic short*)((char*)&easi + 2);
+  max_fetch (psi, esi);                 // { dg-warning "-Wstringop-overflow" }
+
+  _Atomic int *pi = (_Atomic int*)((char*)&eai + 1);
+  max_fetch (pi, ei);                   // { dg-warning "-Wstringop-overflow" }
+  pi = (_Atomic int*)((char*)&eai + 2);
+  max_fetch (pi, ei);                   // { dg-warning "-Wstringop-overflow" }
+  pi = (_Atomic int*)((char*)&eai + sizeof eai);
+  max_fetch (pi, ei);                   // { dg-warning "-Wstringop-overflow" }
+
+  _Atomic long *pli = (_Atomic long*)((char*)&eali + 1);
+  max_fetch (pli, eli);                 // { dg-warning "-Wstringop-overflow" }
+  pli = (_Atomic long*)((char*)&eali + 1);
+  max_fetch (pli, eli);                 // { dg-warning "-Wstringop-overflow" }
+  pli = &eali + 1;
+  max_fetch (pli, eli);                 // { dg-warning "-Wstringop-overflow" }
+
+  _Atomic long long *plli = (_Atomic long long*)((char*)&ealli + 1);
+  max_fetch (plli, elli);               // { dg-warning "-Wstringop-overflow" }
+  plli = (_Atomic long long*)((char*)&ealli + 1);
+  max_fetch (plli, eali);               // { dg-warning "-Wstringop-overflow" }
+  plli = &ealli + 1;
+  max_fetch (plli, elli);               // { dg-warning "-Wstringop-overflow" }
+}
+
+
 NOIPA void warn_atomic_compare_exchange (void)
 {
   _Atomic char *pc = &eac + 1;
diff --git a/gcc/testsuite/gcc.dg/analyzer/atomic-builtins-1.c 
b/gcc/testsuite/gcc.dg/analyzer/atomic-builtins-1.c
index 69eac3f87fd..9b34c24e450 100644
--- a/gcc/testsuite/gcc.dg/analyzer/atomic-builtins-1.c
+++ b/gcc/testsuite/gcc.dg/analyzer/atomic-builtins-1.c
@@ -542,3 +542,210 @@ void test__atomic_fetch_or_on_uint64_t (uint64_t i, 
uint64_t j)
   __analyzer_eval (i == (orig_i | j)); /* { dg-warning "TRUE" } */
   __analyzer_eval (ret == orig_i); /* { dg-warning "TRUE" } */
 }
+
+/* __atomic_fetch_min.  */
+
+void test__atomic_fetch_min_on_uint32_t (uint32_t i, uint32_t j)
+{
+  uint32_t orig_i = i;
+  uint32_t ret;
+  ret = __atomic_fetch_min (&i, j, 0);
+  __analyzer_eval (ret == orig_i); /* { dg-warning "TRUE" } */
+
+  i = 10;
+  ret = __atomic_fetch_min (&i, 5, 0);
+  __analyzer_eval (ret == 10); /* { dg-warning "TRUE" } */
+  __analyzer_eval (i == 5); /* { dg-warning "TRUE" } */
+}
+
+void test__atomic_fetch_min_on_uint64_t (uint64_t i, uint64_t j)
+{
+  uint64_t orig_i = i;
+  uint64_t ret;
+  ret = __atomic_fetch_min (&i, j, 0);
+  __analyzer_eval (ret == orig_i); /* { dg-warning "TRUE" } */
+
+  i = 20;
+  ret = __atomic_fetch_min (&i, 15, 0);
+  __analyzer_eval (ret == 20); /* { dg-warning "TRUE" } */
+  __analyzer_eval (i == 15); /* { dg-warning "TRUE" } */
+}
+
+void test__atomic_fetch_min_on_int32_t (int32_t i, int32_t j)
+{
+  int32_t orig_i = i;
+  int32_t ret;
+  ret = __atomic_fetch_min (&i, j, 0);
+  __analyzer_eval (ret == orig_i); /* { dg-warning "TRUE" } */
+
+  i = 10;
+  ret = __atomic_fetch_min (&i, 5, 0);
+  __analyzer_eval (i == 5); /* { dg-warning "TRUE" } */
+}
+
+void test__atomic_fetch_min_on_int64_t (int64_t i, int64_t j)
+{
+  int64_t orig_i = i;
+  int64_t ret;
+  ret = __atomic_fetch_min (&i, j, 0);
+  __analyzer_eval (ret == orig_i); /* { dg-warning "TRUE" } */
+
+  i = -5;
+  ret = __atomic_fetch_min (&i, -10, 0);
+  __analyzer_eval (ret == -5); /* { dg-warning "TRUE" } */
+  __analyzer_eval (i == -10); /* { dg-warning "TRUE" } */
+}
+
+/* __atomic_fetch_max.  */
+
+void test__atomic_fetch_max_on_uint32_t (uint32_t i, uint32_t j)
+{
+  uint32_t orig_i = i;
+  uint32_t ret;
+  ret = __atomic_fetch_max (&i, j, 0);
+  __analyzer_eval (ret == orig_i); /* { dg-warning "TRUE" } */
+
+  i = 10;
+  ret = __atomic_fetch_max (&i, 15, 0);
+  __analyzer_eval (ret == 10); /* { dg-warning "TRUE" } */
+  __analyzer_eval (i == 15); /* { dg-warning "TRUE" } */
+}
+
+void test__atomic_fetch_max_on_uint64_t (uint64_t i, uint64_t j)
+{
+  uint64_t orig_i = i;
+  uint64_t ret;
+  ret = __atomic_fetch_max (&i, j, 0);
+  __analyzer_eval (ret == orig_i); /* { dg-warning "TRUE" } */
+
+  i = 25;
+  ret = __atomic_fetch_max (&i, 30, 0);
+  __analyzer_eval (ret == 25); /* { dg-warning "TRUE" } */
+  __analyzer_eval (i == 30); /* { dg-warning "TRUE" } */
+}
+
+void test__atomic_fetch_max_on_int32_t (int32_t i, int32_t j)
+{
+  int32_t orig_i = i;
+  int32_t ret;
+  ret = __atomic_fetch_max (&i, j, 0);
+  __analyzer_eval (ret == orig_i); /* { dg-warning "TRUE" } */
+
+  i = -10;
+  ret = __atomic_fetch_max (&i, -5, 0);
+  __analyzer_eval (ret == -10); /* { dg-warning "TRUE" } */
+  __analyzer_eval (i == -5); /* { dg-warning "TRUE" } */
+}
+
+void test__atomic_fetch_max_on_int64_t (int64_t i, int64_t j)
+{
+  int64_t orig_i = i;
+  int64_t ret;
+  ret = __atomic_fetch_max (&i, j, 0);
+  __analyzer_eval (ret == orig_i); /* { dg-warning "TRUE" } */
+
+  i = 100;
+  ret = __atomic_fetch_max (&i, 200, 0);
+  __analyzer_eval (ret == 100); /* { dg-warning "TRUE" } */
+  __analyzer_eval (i == 200); /* { dg-warning "TRUE" } */
+}
+
+/* __atomic_min_fetch.  */
+
+void test__atomic_min_fetch_on_uint32_t (uint32_t i, uint32_t j)
+{
+  uint32_t ret;
+  ret = __atomic_min_fetch (&i, j, 0);
+  __analyzer_eval (ret == i); /* { dg-warning "TRUE" } */
+
+  i = 10;
+  ret = __atomic_min_fetch (&i, 5, 0);
+  __analyzer_eval (ret == 5); /* { dg-warning "TRUE" } */
+  __analyzer_eval (i == 5); /* { dg-warning "TRUE" } */
+}
+
+void test__atomic_min_fetch_on_uint64_t (uint64_t i, uint64_t j)
+{
+  uint64_t ret;
+  ret = __atomic_min_fetch (&i, j, 0);
+  __analyzer_eval (ret == i); /* { dg-warning "TRUE" } */
+
+  i = 50;
+  ret = __atomic_min_fetch (&i, 40, 0);
+  __analyzer_eval (ret == 40); /* { dg-warning "TRUE" } */
+  __analyzer_eval (i == 40); /* { dg-warning "TRUE" } */
+}
+
+void test__atomic_min_fetch_on_int32_t (int32_t i, int32_t j)
+{
+  int32_t ret;
+  ret = __atomic_min_fetch (&i, j, 0);
+  __analyzer_eval (ret == i); /* { dg-warning "TRUE" } */
+
+  i = 5;
+  ret = __atomic_min_fetch (&i, -3, 0);
+  __analyzer_eval (ret == -3); /* { dg-warning "TRUE" } */
+  __analyzer_eval (i == -3); /* { dg-warning "TRUE" } */
+}
+
+void test__atomic_min_fetch_on_int64_t (int64_t i, int64_t j)
+{
+  int64_t ret;
+  ret = __atomic_min_fetch (&i, j, 0);
+  __analyzer_eval (ret == i); /* { dg-warning "TRUE" } */
+
+  i = -20;
+  ret = __atomic_min_fetch (&i, -30, 0);
+  __analyzer_eval (ret == -30); /* { dg-warning "TRUE" } */
+  __analyzer_eval (i == -30); /* { dg-warning "TRUE" } */
+}
+
+/* __atomic_max_fetch.  */
+
+void test__atomic_max_fetch_on_uint32_t (uint32_t i, uint32_t j)
+{
+  uint32_t ret;
+  ret = __atomic_max_fetch (&i, j, 0);
+  __analyzer_eval (ret == i); /* { dg-warning "TRUE" } */
+
+  i = 10;
+  ret = __atomic_max_fetch (&i, 15, 0);
+  __analyzer_eval (ret == 15); /* { dg-warning "TRUE" } */
+  __analyzer_eval (i == 15); /* { dg-warning "TRUE" } */
+}
+
+void test__atomic_max_fetch_on_uint64_t (uint64_t i, uint64_t j)
+{
+  uint64_t ret;
+  ret = __atomic_max_fetch (&i, j, 0);
+  __analyzer_eval (ret == i); /* { dg-warning "TRUE" } */
+
+  i = 75;
+  ret = __atomic_max_fetch (&i, 100, 0);
+  __analyzer_eval (ret == 100); /* { dg-warning "TRUE" } */
+  __analyzer_eval (i == 100); /* { dg-warning "TRUE" } */
+}
+
+void test__atomic_max_fetch_on_int32_t (int32_t i, int32_t j)
+{
+  int32_t ret;
+  ret = __atomic_max_fetch (&i, j, 0);
+  __analyzer_eval (ret == i); /* { dg-warning "TRUE" } */
+
+  i = -15;
+  ret = __atomic_max_fetch (&i, -10, 0);
+  __analyzer_eval (ret == -10); /* { dg-warning "TRUE" } */
+  __analyzer_eval (i == -10); /* { dg-warning "TRUE" } */
+}
+
+void test__atomic_max_fetch_on_int64_t (int64_t i, int64_t j)
+{
+  int64_t ret;
+  ret = __atomic_max_fetch (&i, j, 0);
+  __analyzer_eval (ret == i); /* { dg-warning "TRUE" } */
+
+  i = 50;
+  ret = __atomic_max_fetch (&i, 60, 0);
+  __analyzer_eval (ret == 60); /* { dg-warning "TRUE" } */
+  __analyzer_eval (i == 60); /* { dg-warning "TRUE" } */
+}
diff --git a/gcc/testsuite/gcc.dg/tree-ssa/atomic-minmax-forwprop.c 
b/gcc/testsuite/gcc.dg/tree-ssa/atomic-minmax-forwprop.c
new file mode 100644
index 00000000000..f6648a31ac7
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/tree-ssa/atomic-minmax-forwprop.c
@@ -0,0 +1,56 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -fdump-tree-forwprop1" } */
+
+#include <stdint.h>
+
+#define MIN(a, b) ((a) < (b) ? (a) : (b))
+#define MAX(a, b) ((a) > (b) ? (a) : (b))
+
+int32_t test_fetch_min_to_min_fetch_signed (int32_t *p, int32_t val)
+{
+  int32_t old = __atomic_fetch_min (p, val, __ATOMIC_SEQ_CST);
+  return MIN(old, val);
+}
+
+int32_t test_fetch_max_to_max_fetch_signed (int32_t *p, int32_t val)
+{
+  int32_t old = __atomic_fetch_max (p, val, __ATOMIC_SEQ_CST);
+  return MAX(old, val);
+}
+
+uint32_t test_fetch_min_to_min_fetch_unsigned (uint32_t *p, uint32_t val)
+{
+  uint32_t old = __atomic_fetch_min (p, val, __ATOMIC_SEQ_CST);
+  return MIN(old, val);
+}
+
+uint32_t test_fetch_max_to_max_fetch_unsigned (uint32_t *p, uint32_t val)
+{
+  uint32_t old = __atomic_fetch_max (p, val, __ATOMIC_SEQ_CST);
+  return MAX(old, val);
+}
+
+int16_t test_fetch_min_16bit (int16_t *p, int16_t val)
+{
+  int16_t old = __atomic_fetch_min (p, val, __ATOMIC_SEQ_CST);
+  return MIN(old, val);
+}
+
+int64_t test_fetch_max_64bit (int64_t *p, int64_t val)
+{
+  int64_t old = __atomic_fetch_max (p, val, __ATOMIC_SEQ_CST);
+  return MAX(old, val);
+}
+
+/* We expect the fetch_op calls to be converted to op_fetch calls.
+   Look for the op_fetch variants in the forwprop1 dump.  */
+/* { dg-final { scan-tree-dump-times "__atomic_smin_fetch_4" 1 "forwprop1" } } 
*/
+/* { dg-final { scan-tree-dump-times "__atomic_smax_fetch_4" 1 "forwprop1" } } 
*/
+/* { dg-final { scan-tree-dump-times "__atomic_umin_fetch_4" 1 "forwprop1" } } 
*/
+/* { dg-final { scan-tree-dump-times "__atomic_umax_fetch_4" 1 "forwprop1" } } 
*/
+/* { dg-final { scan-tree-dump-times "__atomic_smin_fetch_2" 1 "forwprop1" } } 
*/
+/* { dg-final { scan-tree-dump-times "__atomic_smax_fetch_8" 1 "forwprop1" } } 
*/
+
+/* And the original fetch_op calls should be gone.  */
+/* { dg-final { scan-tree-dump-not "__atomic_fetch_smin" "forwprop1" } } */
+/* { dg-final { scan-tree-dump-not "__atomic_fetch_smax" "forwprop1" } } */
\ No newline at end of file
diff --git a/gcc/testsuite/gcc.dg/tsan/atomic-minmax.c 
b/gcc/testsuite/gcc.dg/tsan/atomic-minmax.c
new file mode 100644
index 00000000000..0efbc52bd00
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/tsan/atomic-minmax.c
@@ -0,0 +1,48 @@
+/* Test that TSAN warns about unsupported atomic min/max operations.  */
+/* { dg-do compile } */
+/* { dg-options "-fsanitize=thread" } */
+
+#include <stdint.h>
+
+int8_t i8;
+int16_t i16;
+int32_t i32;
+int64_t i64;
+
+uint8_t u8;
+uint16_t u16;
+uint32_t u32;
+uint64_t u64;
+
+void test_atomic_minmax (void)
+{
+  /* Test fetch_min operations */
+  __atomic_fetch_min (&i8, 5, 0);    /* { dg-warning {.__atomic_fetch_smin_1. 
is not supported with .-fsanitize=thread.} } */
+  __atomic_fetch_min (&i16, 5, 0);   /* { dg-warning {.__atomic_fetch_smin_2. 
is not supported with .-fsanitize=thread.} } */
+  __atomic_fetch_min (&i32, 5, 0);   /* { dg-warning {.__atomic_fetch_smin_4. 
is not supported with .-fsanitize=thread.} } */
+  __atomic_fetch_min (&i64, 5, 0);   /* { dg-warning {.__atomic_fetch_smin_8. 
is not supported with .-fsanitize=thread.} } */
+  
+  /* Test fetch_max operations */
+  __atomic_fetch_max (&i8, 5, 0);    /* { dg-warning {.__atomic_fetch_smax_1. 
is not supported with .-fsanitize=thread.} } */
+  __atomic_fetch_max (&i16, 5, 0);   /* { dg-warning {.__atomic_fetch_smax_2. 
is not supported with .-fsanitize=thread.} } */
+  __atomic_fetch_max (&i32, 5, 0);   /* { dg-warning {.__atomic_fetch_smax_4. 
is not supported with .-fsanitize=thread.} } */
+  __atomic_fetch_max (&i64, 5, 0);   /* { dg-warning {.__atomic_fetch_smax_8. 
is not supported with .-fsanitize=thread.} } */
+  
+  /* Test unsigned fetch_min operations */
+  __atomic_fetch_min (&u8, 5, 0);    /* { dg-warning {.__atomic_fetch_umin_1. 
is not supported with .-fsanitize=thread.} } */
+  __atomic_fetch_min (&u16, 5, 0);   /* { dg-warning {.__atomic_fetch_umin_2. 
is not supported with .-fsanitize=thread.} } */
+  __atomic_fetch_min (&u32, 5, 0);   /* { dg-warning {.__atomic_fetch_umin_4. 
is not supported with .-fsanitize=thread.} } */
+  __atomic_fetch_min (&u64, 5, 0);   /* { dg-warning {.__atomic_fetch_umin_8. 
is not supported with .-fsanitize=thread.} } */
+  
+  /* Test unsigned fetch_max operations */
+  __atomic_fetch_max (&u8, 5, 0);    /* { dg-warning {.__atomic_fetch_umax_1. 
is not supported with .-fsanitize=thread.} } */
+  __atomic_fetch_max (&u16, 5, 0);   /* { dg-warning {.__atomic_fetch_umax_2. 
is not supported with .-fsanitize=thread.} } */
+  __atomic_fetch_max (&u32, 5, 0);   /* { dg-warning {.__atomic_fetch_umax_4. 
is not supported with .-fsanitize=thread.} } */
+  __atomic_fetch_max (&u64, 5, 0);   /* { dg-warning {.__atomic_fetch_umax_8. 
is not supported with .-fsanitize=thread.} } */
+  
+  /* Test op_fetch versions (return new value) */
+  __atomic_min_fetch (&i32, 5, 0);   /* { dg-warning {.__atomic_smin_fetch_4. 
is not supported with .-fsanitize=thread.} } */
+  __atomic_max_fetch (&i32, 5, 0);   /* { dg-warning {.__atomic_smax_fetch_4. 
is not supported with .-fsanitize=thread.} } */
+  __atomic_min_fetch (&u32, 5, 0);   /* { dg-warning {.__atomic_umin_fetch_4. 
is not supported with .-fsanitize=thread.} } */
+  __atomic_max_fetch (&u32, 5, 0);   /* { dg-warning {.__atomic_umax_fetch_4. 
is not supported with .-fsanitize=thread.} } */
+} 
\ No newline at end of file
diff --git a/gcc/tree-ssa-forwprop.cc b/gcc/tree-ssa-forwprop.cc
index 43b1c9d696f..bec061b2cab 100644
--- a/gcc/tree-ssa-forwprop.cc
+++ b/gcc/tree-ssa-forwprop.cc
@@ -1767,6 +1767,11 @@ simplify_builtin_call (gimple_stmt_iterator *gsi_p, tree 
callee2)
     CASE_ATOMIC (SYNC_SUB_AND_FETCH, SYNC_FETCH_AND_SUB, PLUS_EXPR)
     CASE_ATOMIC (SYNC_XOR_AND_FETCH, SYNC_FETCH_AND_XOR, BIT_XOR_EXPR)
 
+    CASE_ATOMIC (ATOMIC_FETCH_SMIN, ATOMIC_SMIN_FETCH, MIN_EXPR)
+    CASE_ATOMIC (ATOMIC_FETCH_SMAX, ATOMIC_SMAX_FETCH, MAX_EXPR)
+    CASE_ATOMIC (ATOMIC_FETCH_UMIN, ATOMIC_UMIN_FETCH, MIN_EXPR)
+    CASE_ATOMIC (ATOMIC_FETCH_UMAX, ATOMIC_UMAX_FETCH, MAX_EXPR)
+
 #undef CASE_ATOMIC
 
     handle_atomic_fetch_op:
@@ -1967,6 +1972,8 @@ simplify_builtin_call (gimple_stmt_iterator *gsi_p, tree 
callee2)
              update_stmt (use_stmt);
              if (atomic_op != BIT_AND_EXPR
                  && atomic_op != BIT_IOR_EXPR
+                 && atomic_op != MIN_EXPR
+                 && atomic_op != MAX_EXPR
                  && !stmt_ends_bb_p (stmt2))
                {
                  /* For the benefit of debug stmts, emit stmt(s) to set
diff --git a/gcc/tsan.cc b/gcc/tsan.cc
index 70a7d09065e..b3ea6595d92 100644
--- a/gcc/tsan.cc
+++ b/gcc/tsan.cc
@@ -254,7 +254,7 @@ enum tsan_atomic_action
 {
   check_last, add_seq_cst, add_acquire, weak_cas, strong_cas,
   bool_cas, val_cas, lock_release, fetch_op, fetch_op_seq_cst,
-  bool_clear, bool_test_and_set
+  bool_clear, bool_test_and_set, warn_missing
 };
 
 /* Table how to map sync/atomic builtins to their corresponding
@@ -292,6 +292,8 @@ static const struct tsan_map_atomic
   TRANSFORM (fcode, tsan_fcode, bool_clear, ERROR_MARK)
 #define BOOL_TEST_AND_SET(fcode, tsan_fcode) \
   TRANSFORM (fcode, tsan_fcode, bool_test_and_set, ERROR_MARK)
+#define UNHANDLED(fcode) \
+  TRANSFORM (fcode, TSAN_ATOMIC_THREAD_FENCE, warn_missing, ERROR_MARK)
 
   CHECK_LAST (ATOMIC_LOAD_1, TSAN_ATOMIC8_LOAD),
   CHECK_LAST (ATOMIC_LOAD_2, TSAN_ATOMIC16_LOAD),
@@ -339,6 +341,28 @@ static const struct tsan_map_atomic
   CHECK_LAST (ATOMIC_FETCH_NAND_8, TSAN_ATOMIC64_FETCH_NAND),
   CHECK_LAST (ATOMIC_FETCH_NAND_16, TSAN_ATOMIC128_FETCH_NAND),
 
+  /* Atomic min/max operations are not supported by TSAN.  */
+  UNHANDLED (ATOMIC_FETCH_SMIN_1),
+  UNHANDLED (ATOMIC_FETCH_SMIN_2),
+  UNHANDLED (ATOMIC_FETCH_SMIN_4),
+  UNHANDLED (ATOMIC_FETCH_SMIN_8),
+  UNHANDLED (ATOMIC_FETCH_SMIN_16),
+  UNHANDLED (ATOMIC_FETCH_SMAX_1),
+  UNHANDLED (ATOMIC_FETCH_SMAX_2),
+  UNHANDLED (ATOMIC_FETCH_SMAX_4),
+  UNHANDLED (ATOMIC_FETCH_SMAX_8),
+  UNHANDLED (ATOMIC_FETCH_SMAX_16),
+  UNHANDLED (ATOMIC_FETCH_UMIN_1),
+  UNHANDLED (ATOMIC_FETCH_UMIN_2),
+  UNHANDLED (ATOMIC_FETCH_UMIN_4),
+  UNHANDLED (ATOMIC_FETCH_UMIN_8),
+  UNHANDLED (ATOMIC_FETCH_UMIN_16),
+  UNHANDLED (ATOMIC_FETCH_UMAX_1),
+  UNHANDLED (ATOMIC_FETCH_UMAX_2),
+  UNHANDLED (ATOMIC_FETCH_UMAX_4),
+  UNHANDLED (ATOMIC_FETCH_UMAX_8),
+  UNHANDLED (ATOMIC_FETCH_UMAX_16),
+
   CHECK_LAST (ATOMIC_THREAD_FENCE, TSAN_ATOMIC_THREAD_FENCE),
   CHECK_LAST (ATOMIC_SIGNAL_FENCE, TSAN_ATOMIC_SIGNAL_FENCE),
 
@@ -373,6 +397,28 @@ static const struct tsan_map_atomic
   FETCH_OP (ATOMIC_NAND_FETCH_8, TSAN_ATOMIC64_FETCH_NAND, BIT_NOT_EXPR),
   FETCH_OP (ATOMIC_NAND_FETCH_16, TSAN_ATOMIC128_FETCH_NAND, BIT_NOT_EXPR),
 
+  /* Atomic min/max op_fetch operations are not supported by TSAN.  */
+  UNHANDLED (ATOMIC_SMIN_FETCH_1),
+  UNHANDLED (ATOMIC_SMIN_FETCH_2),
+  UNHANDLED (ATOMIC_SMIN_FETCH_4),
+  UNHANDLED (ATOMIC_SMIN_FETCH_8),
+  UNHANDLED (ATOMIC_SMIN_FETCH_16),
+  UNHANDLED (ATOMIC_SMAX_FETCH_1),
+  UNHANDLED (ATOMIC_SMAX_FETCH_2),
+  UNHANDLED (ATOMIC_SMAX_FETCH_4),
+  UNHANDLED (ATOMIC_SMAX_FETCH_8),
+  UNHANDLED (ATOMIC_SMAX_FETCH_16),
+  UNHANDLED (ATOMIC_UMIN_FETCH_1),
+  UNHANDLED (ATOMIC_UMIN_FETCH_2),
+  UNHANDLED (ATOMIC_UMIN_FETCH_4),
+  UNHANDLED (ATOMIC_UMIN_FETCH_8),
+  UNHANDLED (ATOMIC_UMIN_FETCH_16),
+  UNHANDLED (ATOMIC_UMAX_FETCH_1),
+  UNHANDLED (ATOMIC_UMAX_FETCH_2),
+  UNHANDLED (ATOMIC_UMAX_FETCH_4),
+  UNHANDLED (ATOMIC_UMAX_FETCH_8),
+  UNHANDLED (ATOMIC_UMAX_FETCH_16),
+
   ADD_ACQUIRE (SYNC_LOCK_TEST_AND_SET_1, TSAN_ATOMIC8_EXCHANGE),
   ADD_ACQUIRE (SYNC_LOCK_TEST_AND_SET_2, TSAN_ATOMIC16_EXCHANGE),
   ADD_ACQUIRE (SYNC_LOCK_TEST_AND_SET_4, TSAN_ATOMIC32_EXCHANGE),
@@ -508,6 +554,14 @@ instrument_builtin_call (gimple_stmt_iterator *gsi)
          warning_at (gimple_location (stmt), OPT_Wtsan,
                      "%qs is not supported with %qs", "atomic_thread_fence",
                      "-fsanitize=thread");
+       if (tsan_atomic_table[i].action == warn_missing)
+         {
+           warning_at (gimple_location (stmt), OPT_Wtsan,
+                       "%qD is not supported with %qs",
+                       builtin_decl_implicit (tsan_atomic_table[i].fcode),
+                       "-fsanitize=thread");
+           continue;
+         }
 
        tree decl = builtin_decl_implicit (tsan_atomic_table[i].tsan_fcode);
        if (decl == NULL_TREE)
-- 
2.44.0

Reply via email to