diff --git a/openmp/CMakeLists.txt b/openmp/CMakeLists.txt
--- a/openmp/CMakeLists.txt
+++ b/openmp/CMakeLists.txt
@@ -79,5 +79,17 @@
   add_subdirectory(libomptarget)
 endif()
 
+set(ENABLE_OMPT_TOOLS ON)
+# Currently tools are not tested well on Windows or MacOS X.
+if (APPLE OR WIN32)
+  set(ENABLE_OMPT_TOOLS OFF)
+endif()
+
+option(OPENMP_ENABLE_OMPT_TOOLS "Enable building ompt based tools for OpenMP."
+       ${ENABLE_OMPT_TOOLS})
+if (OPENMP_ENABLE_OMPT_TOOLS)
+  add_subdirectory(tools)
+endif()
+
 # Now that we have seen all testuites, create the check-openmp target.
 construct_check_openmp_target()
diff --git a/openmp/runtime/CMakeLists.txt b/openmp/runtime/CMakeLists.txt
--- a/openmp/runtime/CMakeLists.txt
+++ b/openmp/runtime/CMakeLists.txt
@@ -380,3 +380,7 @@
 
 add_subdirectory(src)
 add_subdirectory(test)
+
+# make these variables available for tools:
+set(LIBOMP_LIBRARY_DIR ${LIBOMP_LIBRARY_DIR} PARENT_SCOPE)
+set(LIBOMP_INCLUDE_DIR ${LIBOMP_INCLUDE_DIR} PARENT_SCOPE)
diff --git a/openmp/runtime/src/CMakeLists.txt b/openmp/runtime/src/CMakeLists.txt
--- a/openmp/runtime/src/CMakeLists.txt
+++ b/openmp/runtime/src/CMakeLists.txt
@@ -153,6 +153,7 @@
 else()
   set(LIBOMP_LIBRARY_DIR ${LIBOMP_LIBRARY_DIR} PARENT_SCOPE)
 endif()
+set(LIBOMP_INCLUDE_DIR ${CMAKE_CURRENT_BINARY_DIR} PARENT_SCOPE)
 
 # Add symbolic links to libomp
 if(NOT WIN32)
diff --git a/openmp/runtime/src/ompt-general.cpp b/openmp/runtime/src/ompt-general.cpp
--- a/openmp/runtime/src/ompt-general.cpp
+++ b/openmp/runtime/src/ompt-general.cpp
@@ -268,6 +268,22 @@
     }
     __kmp_str_free(&libs);
   }
+  if (ret)
+    return ret;
+
+#if KMP_OS_UNIX
+  { // Non-standard: load archer tool if application is built with TSan
+    const char *fname = "libarcher.so";
+    void *h = dlopen(fname, RTLD_LAZY);
+    if (h) {
+      start_tool = (ompt_start_tool_t)dlsym(h, "ompt_start_tool");
+      if (start_tool)
+        ret = (*start_tool)(omp_version, runtime_version);
+      if (ret)
+        return ret;
+    }
+  }
+#endif
   return ret;
 }
 
diff --git a/openmp/tools/CMakeLists.txt b/openmp/tools/CMakeLists.txt
new file mode 100644
--- /dev/null
+++ b/openmp/tools/CMakeLists.txt
@@ -0,0 +1,9 @@
+# Discover the tools that use CMake in the subdirectories.
+# Note that explicit cmake invocation is required every time a new tool
+# is added or removed.
+file(GLOB entries *)
+foreach(entry ${entries})
+  if(IS_DIRECTORY ${entry} AND EXISTS ${entry}/CMakeLists.txt)
+    add_subdirectory(${entry})
+  endif()
+endforeach(entry)
diff --git a/openmp/tools/archer/CMakeLists.txt b/openmp/tools/archer/CMakeLists.txt
new file mode 100644
--- /dev/null
+++ b/openmp/tools/archer/CMakeLists.txt
@@ -0,0 +1,20 @@
+# //===----------------------------------------------------------------------===//
+# //
+# // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+# // See https://llvm.org/LICENSE.txt for details.
+# // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+# //
+# //===----------------------------------------------------------------------===//
+  
+  
+
+include_directories(${LIBOMP_INCLUDE_DIR})
+
+add_library(archer SHARED ompt-tsan.cpp)
+add_library(archer_static STATIC ompt-tsan.cpp)
+
+install(TARGETS archer archer_static
+  LIBRARY DESTINATION ${OPENMP_INSTALL_LIBDIR}
+  ARCHIVE DESTINATION ${OPENMP_INSTALL_LIBDIR})
+
+add_subdirectory(tests)
diff --git a/openmp/tools/archer/README.md b/openmp/tools/archer/README.md
new file mode 100644
--- /dev/null
+++ b/openmp/tools/archer/README.md
@@ -0,0 +1,215 @@
+
+
+
+
+
+# License
+
+Archer is distributed under the terms of the Apache License.
+
+Please see LICENSE.txt for usage terms.
+
+LLNL-CODE-773957
+
+
+
+# Introduction
+
+**Archer** is an OMPT tool which annotates OpenMP synchronization semantics for data race
+detection.
+This avoids false alerts in data race detection.
+Archer is automatically loaded for OpenMP applications which are compiled
+with ThreadSanitizer option.
+
+
+
+# Build Archer within Clang/LLVM
+
+This distribution of Archer is automatically built with the OpenMP runtime
+and automatically loaded by the OpenMP runtime.
+
+
+
+# Usage
+
+
+
+
+## How to compile
+
+To use archer, compile the application with the extra flag
+`-fsanitize=thread`:
+
+    clang -O3 -g -fopenmp -fsanitize=thread app.c
+    clang++ -O3 -g -fopenmp -fsanitize=thread app.cpp
+
+To compile Fortran applications, compile with gfortran, link with clang:
+
+    gfortran -g -c -fopenmp -fsanitize=thread app.f
+    clang -fopenmp -fsanitize=thread app.o -lgfortran
+
+
+
+
+## Runtime Flags
+
+TSan runtime flags are passed via **TSAN_OPTIONS** environment variable,
+we highly recommend the following option to aviod false alerts for the
+OpenMP or MPI runtime implementation:
+
+    export TSAN_OPTIONS="ignore_noninstrumented_modules=1"
+
+
+Runtime flags are passed via **ARCHER_OPTIONS** environment variable,
+different flags are separated by spaces, e.g.:
+
+    ARCHER_OPTIONS="flush_shadow=1" ./myprogram
+
+
+
+
+
+
+
+
+
+
+
+
+
+| Flag Name+ | Default value+ | Description+ | 
+
+
+
+
+| flush_shadow+ | 0+ | Flush shadow memory at the end of an outer OpenMP parallel region. Our experiments show that this can reduce memory overhead by ~30% and runtime overhead by ~10%. This flag is useful for large OpenMP applications that typically require large amounts of memory, causing out-of-memory exceptions when checked by Archer.+ | 
+
+
+
+
+| print_ompt_counters+ | 0+ | Print the number of triggered OMPT events at the end of the execution.+ | 
+
+
+
+
+| print_max_rss+ | 0+ | Print the RSS memory peak at the end of the execution.+ | 
+
+
+
+
+| verbose+ | 0+ | Print startup information.+ | 
+
+
+
+
+| enable+ | 1+ | Use Archer runtime library during execution.+ | 
+
+
+
+
+
+
+# Example
+
+Let us take the program below and follow the steps to compile and
+check the program for data races.
+
+Suppose our program is called *myprogram.c*:
+
+     1  #include 
+     2
+     3  #define N 1000
+     4
+     5  int main (int argc, char **argv)
+     6  {
+     7    int a[N];
+     8
+     9  #pragma omp parallel for
+    10    for (int i = 0; i < N - 1; i++) {
+    11      a[i] = a[i + 1];
+    12    }
+    13  }
+
+We compile the program as follow:
+
+    clang -fsanitize=thread -fopenmp -g myprogram.c -o myprogram
+
+Now we can run the program with the following commands:
+
+    export OMP_NUM_THREADS=2
+    ./myprogram
+
+Archer will output a report in case it finds data races. In our case
+the report will look as follow:
+
+    ==================
+    WARNING: ThreadSanitizer: data race (pid=13641)
+      Read of size 4 at 0x7fff79a01170 by main thread:
+        #0 .omp_outlined. myprogram.c:11:12 (myprogram+0x00000049b5a2)
+        #1 __kmp_invoke_microtask  (libomp.so+0x000000077842)
+        #2 __libc_start_main /build/glibc-t3gR2i/glibc-2.23/csu/../csu/libc-start.c:291 (libc.so.6+0x00000002082f)
+
+      Previous write of size 4 at 0x7fff79a01170 by thread T1:
+        #0 .omp_outlined. myprogram.c:11:10 (myprogram+0x00000049b5d6)
+        #1 __kmp_invoke_microtask  (libomp.so+0x000000077842)
+
+      Location is stack of main thread.
+
+      Thread T1 (tid=13643, running) created by main thread at:
+        #0 pthread_create tsan_interceptors.cc:902:3 (myprogram+0x00000043db75)
+        #1 __kmp_create_worker  (libomp.so+0x00000006c364)
+        #2 __libc_start_main /build/glibc-t3gR2i/glibc-2.23/csu/../csu/libc-start.c:291 (libc.so.6+0x00000002082f)
+
+    SUMMARY: ThreadSanitizer: data race myprogram.c:11:12 in .omp_outlined.
+    ==================
+    ThreadSanitizer: reported 1 warnings
+
+
+
+
+# Contacts and Support
+
+-   [Google group](https://groups.google.com/forum/#!forum/archer-pruner)
+-   [Slack Channel](https://pruners.slack.com)
+
+     -  For an invitation please write an email to Simone Atzeni with a reason why you want to be part of the PRUNERS Slack Team. 
+-   E-Mail Contacts:
+
+    
+
+
diff --git a/openmp/tools/archer/ompt-tsan.cpp b/openmp/tools/archer/ompt-tsan.cpp
new file mode 100644
--- /dev/null
+++ b/openmp/tools/archer/ompt-tsan.cpp
@@ -0,0 +1,904 @@
+/*
+ * ompt-tsan.cpp -- Archer runtime library, TSan annotations for Archer
+ */
+  
+  //===----------------------------------------------------------------------===//
+  //
+  // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+  // See https://llvm.org/LICENSE.txt for details.
+  // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+  //
+  //===----------------------------------------------------------------------===//
+
+
+#ifndef __STDC_FORMAT_MACROS
+#define __STDC_FORMAT_MACROS
+#endif
+
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include
+#include 
+#include 
+#include 
+#include 
+
+#if (defined __APPLE__ && defined __MACH__)
+#include 
+#endif
+
+#include 
+#include "omp-tools.h"
+
+static int runOnTsan;
+static int hasReductionCallback;
+
+class ArcherFlags {
+public:
+#if (LLVM_VERSION) >= 40
+  int flush_shadow;
+#endif
+  int print_max_rss;
+  int verbose;
+  int enabled;
+
+  ArcherFlags(const char *env)
+      :
+#if (LLVM_VERSION) >= 40
+        flush_shadow(0),
+#endif
+        print_max_rss(0), verbose(0), enabled(1) {
+    if (env) {
+      std::vector tokens;
+      std::string token;
+      std::string str(env);
+      std::istringstream iss(str);
+      while (std::getline(iss, token, ' '))
+        tokens.push_back(token);
+
+      for (std::vector::iterator it = tokens.begin();
+           it != tokens.end(); ++it) {
+#if (LLVM_VERSION) >= 40
+        if (sscanf(it->c_str(), "flush_shadow=%d", &flush_shadow))
+          continue;
+#endif
+        if (sscanf(it->c_str(), "print_max_rss=%d", &print_max_rss))
+          continue;
+        if (sscanf(it->c_str(), "verbose=%d", &verbose))
+          continue;
+        if (sscanf(it->c_str(), "enable=%d", &enabled))
+          continue;
+        std::cerr << "Illegal values for ARCHER_OPTIONS variable: " << token
+                  << std::endl;
+      }
+    }
+  }
+};
+
+#if (LLVM_VERSION) >= 40
+extern "C" {
+int __attribute__((weak)) __archer_get_omp_status();
+void __attribute__((weak)) __tsan_flush_memory() {}
+}
+#endif
+ArcherFlags *archer_flags;
+
+// The following definitions are pasted from "llvm/Support/Compiler.h" to allow
+// the code
+// to be compiled with other compilers like gcc:
+
+#ifndef TsanHappensBefore
+// Thread Sanitizer is a tool that finds races in code.
+// See http://code.google.com/p/data-race-test/wiki/DynamicAnnotations .
+// tsan detects these exact functions by name.
+extern "C" {
+#if (defined __APPLE__ && defined __MACH__)
+static void AnnotateHappensAfter(const char *file, int line,
+                                 const volatile void *cv) {
+  void (*fptr)(const char *, int, const volatile void *);
+
+  fptr = (void (*)(const char *, int, const volatile void *))dlsym(
+      RTLD_DEFAULT, "AnnotateHappensAfter");
+  (*fptr)(file, line, cv);
+}
+static void AnnotateHappensBefore(const char *file, int line,
+                                  const volatile void *cv) {
+  void (*fptr)(const char *, int, const volatile void *);
+
+  fptr = (void (*)(const char *, int, const volatile void *))dlsym(
+      RTLD_DEFAULT, "AnnotateHappensBefore");
+  (*fptr)(file, line, cv);
+}
+static void AnnotateIgnoreWritesBegin(const char *file, int line) {
+  void (*fptr)(const char *, int);
+
+  fptr = (void (*)(const char *, int))dlsym(RTLD_DEFAULT,
+                                            "AnnotateIgnoreWritesBegin");
+  (*fptr)(file, line);
+}
+static void AnnotateIgnoreWritesEnd(const char *file, int line) {
+  void (*fptr)(const char *, int);
+
+  fptr = (void (*)(const char *, int))dlsym(RTLD_DEFAULT,
+                                            "AnnotateIgnoreWritesEnd");
+  (*fptr)(file, line);
+}
+static void AnnotateNewMemory(const char *file, int line,
+                              const volatile void *cv, size_t size) {
+  void (*fptr)(const char *, int, const volatile void *, size_t);
+
+  fptr = (void (*)(const char *, int, const volatile void *, size_t))dlsym(
+      RTLD_DEFAULT, "AnnotateNewMemory");
+  (*fptr)(file, line, cv, size);
+}
+static int RunningOnValgrind() {
+  int (*fptr)();
+
+  fptr = (int (*)())dlsym(RTLD_DEFAULT, "RunningOnValgrind");
+  if (fptr && fptr != RunningOnValgrind)
+    runOnTsan = 0;
+  return 0;
+}
+#else
+void __attribute__((weak))
+AnnotateHappensAfter(const char *file, int line, const volatile void *cv) {}
+void __attribute__((weak))
+AnnotateHappensBefore(const char *file, int line, const volatile void *cv) {}
+void __attribute__((weak))
+AnnotateIgnoreWritesBegin(const char *file, int line) {}
+void __attribute__((weak)) AnnotateIgnoreWritesEnd(const char *file, int line) {
+}
+void __attribute__((weak))
+AnnotateNewMemory(const char *file, int line, const volatile void *cv,
+                  size_t size) {}
+int __attribute__((weak)) RunningOnValgrind() {
+  runOnTsan = 0;
+  return 0;
+}
+#endif
+}
+
+// This marker is used to define a happens-before arc. The race detector will
+// infer an arc from the begin to the end when they share the same pointer
+// argument.
+#define TsanHappensBefore(cv) AnnotateHappensBefore(__FILE__, __LINE__, cv)
+
+// This marker defines the destination of a happens-before arc.
+#define TsanHappensAfter(cv) AnnotateHappensAfter(__FILE__, __LINE__, cv)
+
+// Ignore any races on writes between here and the next TsanIgnoreWritesEnd.
+#define TsanIgnoreWritesBegin() AnnotateIgnoreWritesBegin(__FILE__, __LINE__)
+
+// Resume checking for racy writes.
+#define TsanIgnoreWritesEnd() AnnotateIgnoreWritesEnd(__FILE__, __LINE__)
+
+// We don't really delete the clock for now
+#define TsanDeleteClock(cv)
+
+// newMemory
+#define TsanNewMemory(addr, size)                                              \
+  AnnotateNewMemory(__FILE__, __LINE__, addr, size)
+#define TsanFreeMemory(addr, size)                                             \
+  AnnotateNewMemory(__FILE__, __LINE__, addr, size)
+#endif
+
+/// Required OMPT inquiry functions.
+static ompt_get_parallel_info_t ompt_get_parallel_info;
+static ompt_get_thread_data_t ompt_get_thread_data;
+
+typedef uint64_t ompt_tsan_clockid;
+
+static uint64_t my_next_id() {
+  static uint64_t ID = 0;
+  uint64_t ret = __sync_fetch_and_add(&ID, 1);
+  return ret;
+}
+
+// Data structure to provide a threadsafe pool of reusable objects.
+// DataPool
+template  struct DataPool {
+  std::mutex DPMutex;
+  std::stack DataPointer;
+  std::list memory;
+  int total;
+
+  void newDatas() {
+    // prefix the Data with a pointer to 'this', allows to return memory to
+    // 'this',
+    // without explicitly knowing the source.
+    //
+    // To reduce lock contention, we use thread local DataPools, but Data
+    // objects move to other threads.
+    // The strategy is to get objects from local pool. Only if the object moved
+    // to another
+    // thread, we might see a penalty on release (returnData).
+    // For "single producer" pattern, a single thread creates tasks, these are
+    // executed by other threads.
+    // The master will have a high demand on TaskData, so return after use.
+    struct pooldata {
+      DataPool *dp;
+      T data;
+    };
+    // We alloc without initialize the memory. We cannot call constructors.
+    // Therfore use malloc!
+    pooldata *datas = (pooldata *)malloc(sizeof(pooldata) * N);
+    memory.push_back(datas);
+    for (int i = 0; i < N; i++) {
+      datas[i].dp = this;
+      DataPointer.push(&(datas[i].data));
+    }
+    total += N;
+  }
+
+  T *getData() {
+    T *ret;
+    DPMutex.lock();
+    if (DataPointer.empty())
+      newDatas();
+    ret = DataPointer.top();
+    DataPointer.pop();
+    DPMutex.unlock();
+    return ret;
+  }
+
+  void returnData(T *data) {
+    DPMutex.lock();
+    DataPointer.push(data);
+    DPMutex.unlock();
+  }
+
+  void getDatas(int n, T **datas) {
+    DPMutex.lock();
+    for (int i = 0; i < n; i++) {
+      if (DataPointer.empty())
+        newDatas();
+      datas[i] = DataPointer.top();
+      DataPointer.pop();
+    }
+    DPMutex.unlock();
+  }
+
+  void returnDatas(int n, T **datas) {
+    DPMutex.lock();
+    for (int i = 0; i < n; i++) {
+      DataPointer.push(datas[i]);
+    }
+    DPMutex.unlock();
+  }
+
+  DataPool() : DPMutex(), DataPointer(), total(0) {}
+
+  ~DataPool() {
+    // we assume all memory is returned when the thread finished / destructor is
+    // called
+    for (auto i : memory)
+      if (i)
+        free(i);
+  }
+};
+
+// This function takes care to return the data to the originating DataPool
+// A pointer to the originating DataPool is stored just before the actual data.
+template  static void retData(void *data) {
+  ((DataPool **)data)[-1]->returnData((T *)data);
+}
+
+struct ParallelData;
+__thread DataPool *pdp;
+
+/// Data structure to store additional information for parallel regions.
+struct ParallelData {
+
+  // Parallel fork is just another barrier, use Barrier[1]
+
+  /// Two addresses for relationships with barriers.
+  ompt_tsan_clockid Barrier[2];
+
+  void *GetParallelPtr() { return &(Barrier[1]); }
+
+  void *GetBarrierPtr(unsigned Index) { return &(Barrier[Index]); }
+
+  ~ParallelData() {
+    TsanDeleteClock(&(Barrier[0]));
+    TsanDeleteClock(&(Barrier[1]));
+  }
+  // overload new/delete to use DataPool for memory management.
+  void *operator new(size_t size) { return pdp->getData(); }
+  void operator delete(void *p, size_t) { retData(p); }
+};
+
+static inline ParallelData *ToParallelData(ompt_data_t *parallel_data) {
+  return reinterpret_cast(parallel_data->ptr);
+}
+
+struct Taskgroup;
+__thread DataPool *tgp;
+
+/// Data structure to support stacking of taskgroups and allow synchronization.
+struct Taskgroup {
+  /// Its address is used for relationships of the taskgroup's task set.
+  ompt_tsan_clockid Ptr;
+
+  /// Reference to the parent taskgroup.
+  Taskgroup *Parent;
+
+  Taskgroup(Taskgroup *Parent) : Parent(Parent) {}
+  ~Taskgroup() { TsanDeleteClock(&Ptr); }
+
+  void *GetPtr() { return &Ptr; }
+  // overload new/delete to use DataPool for memory management.
+  void *operator new(size_t size) { return tgp->getData(); }
+  void operator delete(void *p, size_t) { retData(p); }
+};
+
+struct TaskData;
+__thread DataPool *tdp;
+
+/// Data structure to store additional information for tasks.
+struct TaskData {
+  /// Its address is used for relationships of this task.
+  ompt_tsan_clockid Task;
+
+  /// Child tasks use its address to declare a relationship to a taskwait in
+  /// this task.
+  ompt_tsan_clockid Taskwait;
+
+  /// Whether this task is currently executing a barrier.
+  bool InBarrier;
+
+  /// Whether this task is an included task.
+  bool Included;
+
+  /// Index of which barrier to use next.
+  char BarrierIndex;
+
+  /// Count how often this structure has been put into child tasks + 1.
+  std::atomic_int RefCount;
+
+  /// Reference to the parent that created this task.
+  TaskData *Parent;
+
+  /// Reference to the implicit task in the stack above this task.
+  TaskData *ImplicitTask;
+
+  /// Reference to the team of this task.
+  ParallelData *Team;
+
+  /// Reference to the current taskgroup that this task either belongs to or
+  /// that it just created.
+  Taskgroup *TaskGroup;
+
+  /// Dependency information for this task.
+  ompt_dependence_t *Dependencies;
+
+  /// Number of dependency entries.
+  unsigned DependencyCount;
+
+  void *PrivateData;
+  size_t PrivateDataSize;
+
+  int execution;
+  int freed;
+
+  TaskData(TaskData *Parent)
+      : InBarrier(false), Included(false), BarrierIndex(0), RefCount(1),
+        Parent(Parent), ImplicitTask(nullptr), Team(Parent->Team),
+        TaskGroup(nullptr), DependencyCount(0), execution(0), freed(0) {
+    if (Parent != nullptr) {
+      Parent->RefCount++;
+      // Copy over pointer to taskgroup. This task may set up its own stack
+      // but for now belongs to its parent's taskgroup.
+      TaskGroup = Parent->TaskGroup;
+    }
+  }
+
+  TaskData(ParallelData *Team = nullptr)
+      : InBarrier(false), Included(false), BarrierIndex(0), RefCount(1),
+        Parent(nullptr), ImplicitTask(this), Team(Team), TaskGroup(nullptr),
+        DependencyCount(0), execution(1), freed(0) {}
+
+  ~TaskData() {
+    TsanDeleteClock(&Task);
+    TsanDeleteClock(&Taskwait);
+  }
+
+  void *GetTaskPtr() { return &Task; }
+
+  void *GetTaskwaitPtr() { return &Taskwait; }
+  // overload new/delete to use DataPool for memory management.
+  void *operator new(size_t size) { return tdp->getData(); }
+  void operator delete(void *p, size_t) { retData(p); }
+};
+
+static inline TaskData *ToTaskData(ompt_data_t *task_data) {
+  return reinterpret_cast(task_data->ptr);
+}
+
+static inline void *ToInAddr(void *OutAddr) {
+  // FIXME: This will give false negatives when a second variable lays directly
+  //        behind a variable that only has a width of 1 byte.
+  //        Another approach would be to "negate" the address or to flip the
+  //        first bit...
+  return reinterpret_cast(OutAddr) + 1;
+}
+
+/// Store a mutex for each wait_id to resolve race condition with callbacks.
+std::unordered_map Locks;
+std::mutex LocksMutex;
+
+static void ompt_tsan_thread_begin(ompt_thread_t thread_type,
+                                   ompt_data_t *thread_data) {
+  pdp = new DataPool;
+  TsanNewMemory(pdp, sizeof(pdp));
+  tgp = new DataPool;
+  TsanNewMemory(tgp, sizeof(tgp));
+  tdp = new DataPool;
+  TsanNewMemory(tdp, sizeof(tdp));
+  thread_data->value = my_next_id();
+}
+
+static void ompt_tsan_thread_end(ompt_data_t *thread_data) {
+  delete pdp;
+  delete tgp;
+  delete tdp;
+}
+
+/// OMPT event callbacks for handling parallel regions.
+
+static void ompt_tsan_parallel_begin(ompt_data_t *parent_task_data,
+                                     const ompt_frame_t *parent_task_frame,
+                                     ompt_data_t *parallel_data,
+                                     uint32_t requested_team_size,
+                                     int flag,
+                                     const void *codeptr_ra) {
+  ParallelData *Data = new ParallelData;
+  parallel_data->ptr = Data;
+
+  TsanHappensBefore(Data->GetParallelPtr());
+}
+
+static void ompt_tsan_parallel_end(ompt_data_t *parallel_data,
+                                   ompt_data_t *task_data,
+                                   int flag,
+                                   const void *codeptr_ra) {
+  ParallelData *Data = ToParallelData(parallel_data);
+  TsanHappensAfter(Data->GetBarrierPtr(0));
+  TsanHappensAfter(Data->GetBarrierPtr(1));
+
+  delete Data;
+
+#if (LLVM_VERSION >= 40)
+  if (&__archer_get_omp_status) {
+    if (__archer_get_omp_status() == 0 && archer_flags->flush_shadow)
+      __tsan_flush_memory();
+  }
+#endif
+
+}
+
+static void ompt_tsan_implicit_task(ompt_scope_endpoint_t endpoint,
+                                    ompt_data_t *parallel_data,
+                                    ompt_data_t *task_data,
+                                    unsigned int team_size,
+                                    unsigned int thread_num,
+                                    int type) {
+  switch (endpoint) {
+  case ompt_scope_begin:
+    task_data->ptr = new TaskData(ToParallelData(parallel_data));
+    TsanHappensAfter(ToParallelData(parallel_data)->GetParallelPtr());
+    break;
+  case ompt_scope_end:
+    TaskData *Data = ToTaskData(task_data);
+    assert(Data->freed == 0 && "Implicit task end should only be called once!");
+    Data->freed = 1;
+    assert(Data->RefCount == 1 &&
+           "All tasks should have finished at the implicit barrier!");
+    delete Data;
+    break;
+  }
+}
+
+static void ompt_tsan_sync_region(ompt_sync_region_t kind,
+                                  ompt_scope_endpoint_t endpoint,
+                                  ompt_data_t *parallel_data,
+                                  ompt_data_t *task_data,
+                                  const void *codeptr_ra) {
+  TaskData *Data = ToTaskData(task_data);
+  switch (endpoint) {
+  case ompt_scope_begin:
+    switch (kind) {
+      case ompt_sync_region_barrier_implementation:
+      case ompt_sync_region_barrier_implicit:
+      case ompt_sync_region_barrier_explicit:
+      case ompt_sync_region_barrier: {
+        char BarrierIndex = Data->BarrierIndex;
+        TsanHappensBefore(Data->Team->GetBarrierPtr(BarrierIndex));
+
+        if (hasReductionCallback < ompt_set_always) {
+          // We ignore writes inside the barrier. These would either occur during
+          // 1. reductions performed by the runtime which are guaranteed to be
+          // race-free.
+          // 2. execution of another task.
+          // For the latter case we will re-enable tracking in task_switch.
+          Data->InBarrier = true;
+          TsanIgnoreWritesBegin();
+        }
+
+        break;
+      }
+
+      case ompt_sync_region_taskwait:
+        break;
+
+      case ompt_sync_region_taskgroup:
+        Data->TaskGroup = new Taskgroup(Data->TaskGroup);
+        break;
+
+      default:
+        break;
+    }
+    break;
+  case ompt_scope_end:
+    switch (kind) {
+      case ompt_sync_region_barrier_implementation:
+      case ompt_sync_region_barrier_implicit:
+      case ompt_sync_region_barrier_explicit:
+      case ompt_sync_region_barrier: {
+        if (hasReductionCallback < ompt_set_always) {
+          // We want to track writes after the barrier again.
+          Data->InBarrier = false;
+          TsanIgnoreWritesEnd();
+        }
+
+        char BarrierIndex = Data->BarrierIndex;
+        // Barrier will end after it has been entered by all threads.
+        if (parallel_data)
+          TsanHappensAfter(Data->Team->GetBarrierPtr(BarrierIndex));
+
+        // It is not guaranteed that all threads have exited this barrier before
+        // we enter the next one. So we will use a different address.
+        // We are however guaranteed that this current barrier is finished
+        // by the time we exit the next one. So we can then reuse the first
+        // address.
+        Data->BarrierIndex = (BarrierIndex + 1) % 2;
+        break;
+      }
+
+      case ompt_sync_region_taskwait: {
+        if (Data->execution > 1)
+          TsanHappensAfter(Data->GetTaskwaitPtr());
+        break;
+      }
+
+      case ompt_sync_region_taskgroup: {
+        assert(Data->TaskGroup != nullptr &&
+               "Should have at least one taskgroup!");
+
+        TsanHappensAfter(Data->TaskGroup->GetPtr());
+
+        // Delete this allocated taskgroup, all descendent task are finished by
+        // now.
+        Taskgroup *Parent = Data->TaskGroup->Parent;
+        delete Data->TaskGroup;
+        Data->TaskGroup = Parent;
+        break;
+      }
+
+      default:
+        break;
+    }
+    break;
+  }
+}
+
+static void ompt_tsan_reduction(ompt_sync_region_t kind,
+                                ompt_scope_endpoint_t endpoint,
+                                ompt_data_t *parallel_data,
+                                ompt_data_t *task_data,
+                                const void *codeptr_ra) {
+  switch (endpoint) {
+  case ompt_scope_begin:
+    switch (kind) {
+      case ompt_sync_region_reduction:
+        TsanIgnoreWritesBegin();
+        break;
+      default:
+        break;
+    }
+    break;
+  case ompt_scope_end:
+    switch (kind) {
+      case ompt_sync_region_reduction:
+        TsanIgnoreWritesEnd();
+        break;
+      default:
+        break;
+    }
+    break;
+  }
+}
+
+/// OMPT event callbacks for handling tasks.
+
+static void ompt_tsan_task_create(
+    ompt_data_t *parent_task_data, /* id of parent task            */
+    const ompt_frame_t *parent_frame, /* frame data for parent task   */
+    ompt_data_t *new_task_data, /* id of created task           */
+    int type, int has_dependences,
+    const void *codeptr_ra) /* pointer to outlined function */
+{
+  TaskData *Data;
+  assert(new_task_data->ptr == NULL &&
+         "Task data should be initialized to NULL");
+  if (type & ompt_task_initial) {
+    ompt_data_t *parallel_data;
+    int team_size = 1;
+    ompt_get_parallel_info(0, ¶llel_data, &team_size);
+    ParallelData *PData = new ParallelData;
+    parallel_data->ptr = PData;
+
+    Data = new TaskData(PData);
+    new_task_data->ptr = Data;
+  } else if (type & ompt_task_undeferred) {
+    Data = new TaskData(ToTaskData(parent_task_data));
+    new_task_data->ptr = Data;
+    Data->Included = true;
+  } else if (type & ompt_task_explicit || type & ompt_task_target) {
+    Data = new TaskData(ToTaskData(parent_task_data));
+    new_task_data->ptr = Data;
+
+    // Use the newly created address. We cannot use a single address from the
+    // parent because that would declare wrong relationships with other
+    // sibling tasks that may be created before this task is started!
+    TsanHappensBefore(Data->GetTaskPtr());
+    ToTaskData(parent_task_data)->execution++;
+  }
+}
+
+static void ompt_tsan_task_schedule(ompt_data_t *first_task_data,
+                                    ompt_task_status_t prior_task_status,
+                                    ompt_data_t *second_task_data) {
+  TaskData *FromTask = ToTaskData(first_task_data);
+  TaskData *ToTask = ToTaskData(second_task_data);
+
+  if (ToTask->Included && prior_task_status != ompt_task_complete)
+    return; // No further synchronization for begin included tasks
+  if (FromTask->Included && prior_task_status == ompt_task_complete) {
+    // Just delete the task:
+    while (FromTask != nullptr && --FromTask->RefCount == 0) {
+      TaskData *Parent = FromTask->Parent;
+      if (FromTask->DependencyCount > 0) {
+        delete[] FromTask->Dependencies;
+      }
+      delete FromTask;
+      FromTask = Parent;
+    }
+    return;
+  }
+
+  if (ToTask->execution == 0) {
+    ToTask->execution++;
+    // 1. Task will begin execution after it has been created.
+    TsanHappensAfter(ToTask->GetTaskPtr());
+    for (unsigned i = 0; i < ToTask->DependencyCount; i++) {
+      ompt_dependence_t *Dependency = &ToTask->Dependencies[i];
+
+      TsanHappensAfter(Dependency->variable.ptr);
+      // in and inout dependencies are also blocked by prior in dependencies!
+      if (Dependency->dependence_type == ompt_dependence_type_out || Dependency->dependence_type == ompt_dependence_type_inout) {
+        TsanHappensAfter(ToInAddr(Dependency->variable.ptr));
+      }
+    }
+  } else {
+    // 2. Task will resume after it has been switched away.
+    TsanHappensAfter(ToTask->GetTaskPtr());
+  }
+
+  if (prior_task_status != ompt_task_complete) {
+    ToTask->ImplicitTask = FromTask->ImplicitTask;
+    assert(ToTask->ImplicitTask != NULL &&
+           "A task belongs to a team and has an implicit task on the stack");
+  }
+
+  // Task may be resumed at a later point in time.
+  TsanHappensBefore(FromTask->GetTaskPtr());
+
+  if (hasReductionCallback < ompt_set_always && FromTask->InBarrier) {
+    // We want to ignore writes in the runtime code during barriers,
+    // but not when executing tasks with user code!
+    TsanIgnoreWritesEnd();
+  }
+
+  if (prior_task_status == ompt_task_complete) { // task finished
+
+    // Task will finish before a barrier in the surrounding parallel region ...
+    ParallelData *PData = FromTask->Team;
+    TsanHappensBefore(
+        PData->GetBarrierPtr(FromTask->ImplicitTask->BarrierIndex));
+
+    // ... and before an eventual taskwait by the parent thread.
+    TsanHappensBefore(FromTask->Parent->GetTaskwaitPtr());
+
+    if (FromTask->TaskGroup != nullptr) {
+      // This task is part of a taskgroup, so it will finish before the
+      // corresponding taskgroup_end.
+      TsanHappensBefore(FromTask->TaskGroup->GetPtr());
+    }
+    for (unsigned i = 0; i < FromTask->DependencyCount; i++) {
+      ompt_dependence_t *Dependency = &FromTask->Dependencies[i];
+
+      // in dependencies block following inout and out dependencies!
+      TsanHappensBefore(ToInAddr(Dependency->variable.ptr));
+      if (Dependency->dependence_type == ompt_dependence_type_out || Dependency->dependence_type == ompt_dependence_type_inout) {
+        TsanHappensBefore(Dependency->variable.ptr);
+      }
+    }
+    while (FromTask != nullptr && --FromTask->RefCount == 0) {
+      TaskData *Parent = FromTask->Parent;
+      if (FromTask->DependencyCount > 0) {
+        delete[] FromTask->Dependencies;
+      }
+      delete FromTask;
+      FromTask = Parent;
+    }
+  }
+  if (hasReductionCallback < ompt_set_always && ToTask->InBarrier) {
+    // We re-enter runtime code which currently performs a barrier.
+    TsanIgnoreWritesBegin();
+  }
+}
+
+static void ompt_tsan_dependences(ompt_data_t *task_data,
+                                  const ompt_dependence_t *deps,
+                                  int ndeps) {
+  if (ndeps > 0) {
+    // Copy the data to use it in task_switch and task_end.
+    TaskData *Data = ToTaskData(task_data);
+    Data->Dependencies = new ompt_dependence_t[ndeps];
+    std::memcpy(Data->Dependencies, deps,
+                sizeof(ompt_dependence_t) * ndeps);
+    Data->DependencyCount = ndeps;
+
+    // This callback is executed before this task is first started.
+    TsanHappensBefore(Data->GetTaskPtr());
+  }
+}
+
+/// OMPT event callbacks for handling locking.
+static void ompt_tsan_mutex_acquired(ompt_mutex_t kind,
+                                     ompt_wait_id_t wait_id,
+                                     const void *codeptr_ra) {
+
+  // Acquire our own lock to make sure that
+  // 1. the previous release has finished.
+  // 2. the next acquire doesn't start before we have finished our release.
+    LocksMutex.lock();
+    std::mutex &Lock = Locks[wait_id];
+    LocksMutex.unlock();
+
+    Lock.lock();
+    TsanHappensAfter(&Lock);
+}
+
+static void ompt_tsan_mutex_released(ompt_mutex_t kind,
+                                     ompt_wait_id_t wait_id,
+                                     const void *codeptr_ra) {
+    LocksMutex.lock();
+    std::mutex &Lock = Locks[wait_id];
+    LocksMutex.unlock();
+    TsanHappensBefore(&Lock);
+
+    Lock.unlock();
+}
+
+// callback , signature , variable to store result , required support level
+#define SET_OPTIONAL_CALLBACK_T(event, type, result, level)                             \
+  do {                                                                                  \
+    ompt_callback_##type##_t tsan_##event = &ompt_tsan_##event;                         \
+    result = ompt_set_callback(ompt_callback_##event,                                   \
+                                (ompt_callback_t)tsan_##event);                         \
+    if (result < level)                                                                 \
+      printf("Registered callback '" #event "' is not supported at " #level " (%i)\n",  \
+             result);                                                                   \
+  } while (0)
+
+#define SET_CALLBACK_T(event, type)                              \
+  do {                                                           \
+    int res;                                                     \
+    SET_OPTIONAL_CALLBACK_T(event, type, res, ompt_set_always);  \
+  } while (0)
+
+#define SET_CALLBACK(event) SET_CALLBACK_T(event, event)
+
+static int ompt_tsan_initialize(ompt_function_lookup_t lookup,
+                                int device_num,
+                                ompt_data_t *tool_data) {
+  const char *options = getenv("ARCHER_OPTIONS");
+  archer_flags = new ArcherFlags(options);
+
+  ompt_set_callback_t ompt_set_callback =
+      (ompt_set_callback_t)lookup("ompt_set_callback");
+  if (ompt_set_callback == NULL) {
+    std::cerr << "Could not set callback, exiting..." << std::endl;
+    std::exit(1);
+  }
+  ompt_get_parallel_info =
+      (ompt_get_parallel_info_t)lookup("ompt_get_parallel_info");
+  ompt_get_thread_data = (ompt_get_thread_data_t)lookup("ompt_get_thread_data");
+
+  if (ompt_get_parallel_info == NULL) {
+    fprintf(stderr, "Could not get inquiry function 'ompt_get_parallel_info', "
+                    "exiting...\n");
+    exit(1);
+  }
+
+  SET_CALLBACK(thread_begin);
+  SET_CALLBACK(thread_end);
+  SET_CALLBACK(parallel_begin);
+  SET_CALLBACK(implicit_task);
+  SET_CALLBACK(sync_region);
+  SET_CALLBACK(parallel_end);
+
+  SET_CALLBACK(task_create);
+  SET_CALLBACK(task_schedule);
+  SET_CALLBACK(dependences);
+
+  SET_CALLBACK_T(mutex_acquired, mutex);
+  SET_CALLBACK_T(mutex_released, mutex);
+  SET_OPTIONAL_CALLBACK_T(reduction, sync_region, hasReductionCallback, ompt_set_never);
+  return 1; // success
+}
+
+static void ompt_tsan_finalize(ompt_data_t *tool_data) {
+  if (archer_flags->print_max_rss) {
+    struct rusage end;
+    getrusage(RUSAGE_SELF, &end);
+    printf("MAX RSS[KBytes] during execution: %ld\n", end.ru_maxrss);
+  }
+
+  if (archer_flags)
+    delete archer_flags;
+}
+
+extern "C"
+ompt_start_tool_result_t *ompt_start_tool(unsigned int omp_version,
+                                          const char *runtime_version) {
+  const char *options = getenv("ARCHER_OPTIONS");
+  archer_flags = new ArcherFlags(options);
+  if (!archer_flags->enabled)
+  {
+    if (archer_flags->verbose)
+      std::cout << "Archer disabled, stopping operation"
+                << std::endl;
+    delete archer_flags;
+    return NULL;
+  }
+  
+  static ompt_start_tool_result_t ompt_start_tool_result = {
+      &ompt_tsan_initialize, &ompt_tsan_finalize, {0}};
+  runOnTsan=1;
+  RunningOnValgrind();
+  if (!runOnTsan) // if we are not running on TSAN, give a different tool the
+    // chance to be loaded
+  {
+    if (archer_flags->verbose)
+      std::cout << "Archer detected OpenMP application without TSan "
+                   "stopping operation"
+                << std::endl;
+    delete archer_flags;
+    return NULL;
+  }
+
+  if (archer_flags->verbose)
+    std::cout << "Archer detected OpenMP application with TSan, supplying "
+                 "OpenMP synchronization semantics"
+              << std::endl;
+  return &ompt_start_tool_result;
+}
diff --git a/openmp/tools/archer/tests/CMakeLists.txt b/openmp/tools/archer/tests/CMakeLists.txt
new file mode 100644
--- /dev/null
+++ b/openmp/tools/archer/tests/CMakeLists.txt
@@ -0,0 +1,33 @@
+# CMakeLists.txt file for unit testing Archer runtime library.
+include(CheckFunctionExists)
+include(CheckLibraryExists)
+
+# When using libgcc, -latomic may be needed for atomics
+# (but when using compiler-rt, the atomics will be built-in)
+# Note: we can not check for __atomic_load because clang treats it
+# as special built-in and that breaks CMake checks
+check_function_exists(__atomic_load_1 LIBARCHER_HAVE_BUILTIN_ATOMIC)
+if(NOT LIBARCHER_HAVE_BUILTIN_ATOMIC)
+  check_library_exists(atomic __atomic_load_1 "" LIBARCHER_HAVE_LIBATOMIC)
+else()
+  # not needed
+  set(LIBARCHER_HAVE_LIBATOMIC 0)
+endif()
+
+set(LIBARCHER_TEST_PATH ${CMAKE_CURRENT_SOURCE_DIR})
+
+macro(pythonize_bool var)
+  if (${var})
+    set(${var} True)
+  else()
+    set(${var} False)
+  endif()
+endmacro()
+
+pythonize_bool(LIBARCHER_HAVE_LIBATOMIC)
+
+add_openmp_testsuite(check-libarcher "Running libarcher tests" ${CMAKE_CURRENT_BINARY_DIR} DEPENDS archer)
+
+# Configure the lit.site.cfg.in file
+set(AUTO_GEN_COMMENT "## Autogenerated by libarcher configuration.\n# Do not edit!")
+configure_file(lit.site.cfg.in lit.site.cfg @ONLY)
diff --git a/openmp/tools/archer/tests/barrier/barrier.c b/openmp/tools/archer/tests/barrier/barrier.c
new file mode 100644
--- /dev/null
+++ b/openmp/tools/archer/tests/barrier/barrier.c
@@ -0,0 +1,41 @@
+/*
+ * barrier.c -- Archer testcase
+ */
+
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+//
+// See tools/archer/LICENSE.txt for details.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+// RUN: %libarcher-compile-and-run | FileCheck %s
+#include 
+#include 
+
+int main(int argc, char *argv[]) {
+  int var = 0;
+
+#pragma omp parallel num_threads(2) shared(var)
+  {
+    if (omp_get_thread_num() == 0) {
+      var++;
+    }
+
+#pragma omp barrier
+
+    if (omp_get_thread_num() == 1) {
+      var++;
+    }
+  }
+
+  fprintf(stderr, "DONE\n");
+  int error = (var != 2);
+  return error;
+}
+
+// CHECK-NOT: ThreadSanitizer: data race
+// CHECK-NOT: ThreadSanitizer: reported
+// CHECK: DONE
diff --git a/openmp/tools/archer/tests/critical/critical.c b/openmp/tools/archer/tests/critical/critical.c
new file mode 100644
--- /dev/null
+++ b/openmp/tools/archer/tests/critical/critical.c
@@ -0,0 +1,35 @@
+/*
+ * critical.c -- Archer testcase
+ */
+
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+//
+// See tools/archer/LICENSE.txt for details.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+
+// RUN: %libarcher-compile-and-run | FileCheck %s
+#include 
+#include 
+
+int main(int argc, char *argv[]) {
+  int var = 0;
+
+#pragma omp parallel num_threads(8) shared(var)
+  {
+#pragma omp critical
+    { var++; }
+  }
+
+  fprintf(stderr, "DONE\n");
+  int error = (var != 8);
+  return error;
+}
+
+// CHECK-NOT: ThreadSanitizer: data race
+// CHECK-NOT: ThreadSanitizer: reported
+// CHECK: DONE
diff --git a/openmp/tools/archer/tests/critical/lock-nested.c b/openmp/tools/archer/tests/critical/lock-nested.c
new file mode 100644
--- /dev/null
+++ b/openmp/tools/archer/tests/critical/lock-nested.c
@@ -0,0 +1,43 @@
+/*
+ * lock-nested.c -- Archer testcase
+ */
+
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+//
+// See tools/archer/LICENSE.txt for details.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+
+// RUN: %libarcher-compile-and-run | FileCheck %s
+#include 
+#include 
+
+int main(int argc, char *argv[]) {
+  int var = 0;
+
+  omp_nest_lock_t lock;
+  omp_init_nest_lock(&lock);
+
+#pragma omp parallel num_threads(2) shared(var)
+  {
+    omp_set_nest_lock(&lock);
+    omp_set_nest_lock(&lock);
+    var++;
+    omp_unset_nest_lock(&lock);
+    omp_unset_nest_lock(&lock);
+  }
+
+  omp_destroy_nest_lock(&lock);
+
+  fprintf(stderr, "DONE\n");
+  int error = (var != 2);
+  return error;
+}
+
+// CHECK-NOT: ThreadSanitizer: data race
+// CHECK-NOT: ThreadSanitizer: reported
+// CHECK: DONE
diff --git a/openmp/tools/archer/tests/critical/lock.c b/openmp/tools/archer/tests/critical/lock.c
new file mode 100644
--- /dev/null
+++ b/openmp/tools/archer/tests/critical/lock.c
@@ -0,0 +1,41 @@
+/*
+ * lock.c -- Archer testcase
+ */
+
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+//
+// See tools/archer/LICENSE.txt for details.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+
+// RUN: %libarcher-compile-and-run | FileCheck %s
+#include 
+#include 
+
+int main(int argc, char *argv[]) {
+  int var = 0;
+
+  omp_lock_t lock;
+  omp_init_lock(&lock);
+
+#pragma omp parallel num_threads(2) shared(var)
+  {
+    omp_set_lock(&lock);
+    var++;
+    omp_unset_lock(&lock);
+  }
+
+  omp_destroy_lock(&lock);
+
+  fprintf(stderr, "DONE\n");
+  int error = (var != 2);
+  return error;
+}
+
+// CHECK-NOT: ThreadSanitizer: data race
+// CHECK-NOT: ThreadSanitizer: reported
+// CHECK: DONE
diff --git a/openmp/tools/archer/tests/deflake.bash b/openmp/tools/archer/tests/deflake.bash
new file mode 100755
--- /dev/null
+++ b/openmp/tools/archer/tests/deflake.bash
@@ -0,0 +1,17 @@
+#!/usr/bin/env bash
+# This script is used to deflake inherently flaky archer tests.
+# It is invoked from lit tests as:
+# %deflake mybinary
+# which is then substituted by lit to:
+# $(dirname %s)/deflake.bash mybinary
+# The script runs the target program up to 10 times,
+# until it fails (i.e. produces a race report).
+
+for i in $(seq 1 10); do
+    OUT=`$@ 2>&1`
+    if [[ $? != 0 ]]; then
+	echo "$OUT"
+	exit 0
+    fi
+done
+exit 1
diff --git a/openmp/tools/archer/tests/lit.cfg b/openmp/tools/archer/tests/lit.cfg
new file mode 100644
--- /dev/null
+++ b/openmp/tools/archer/tests/lit.cfg
@@ -0,0 +1,117 @@
+# -*- Python -*- vim: set ft=python ts=4 sw=4 expandtab tw=79:
+# Configuration file for the 'lit' test runner.
+
+import os
+import re
+import subprocess
+import lit.formats
+
+# Tell pylint that we know config and lit_config exist somewhere.
+if 'PYLINT_IMPORT' in os.environ:
+    config = object()
+    lit_config = object()
+
+def append_dynamic_library_path(path):
+    if config.operating_system == 'Windows':
+        name = 'PATH'
+        sep = ';'
+    elif config.operating_system == 'Darwin':
+        name = 'DYLD_LIBRARY_PATH'
+        sep = ':'
+    else:
+        name = 'LD_LIBRARY_PATH'
+        sep = ':'
+    if name in config.environment:
+        config.environment[name] = path + sep + config.environment[name]
+    else:
+        config.environment[name] = path
+
+# name: The name of this test suite.
+config.name = 'libarcher'
+
+# suffixes: A list of file extensions to treat as test files.
+config.suffixes = ['.c', '.cpp']
+
+# test_source_root: The root path where tests are located.
+config.test_source_root = os.path.dirname(__file__)
+
+# test_exec_root: The root object directory where output is placed
+config.test_exec_root = config.libarcher_obj_root
+
+# test format
+config.test_format = lit.formats.ShTest()
+
+# compiler flags
+config.test_flags = " -I " + config.test_source_root + \
+    " -I " + config.omp_header_dir + \
+    " -L " + config.omp_library_dir + \
+    " -Wl,-rpath," + config.omp_library_dir + \
+    " " + config.test_extra_flags
+
+config.archer_flags = "-g -O1 -fsanitize=thread"
+
+
+# extra libraries
+libs = ""
+if config.has_libatomic:
+    libs += " -latomic"
+
+# Allow XFAIL to work
+config.target_triple = [ ]
+for feature in config.test_compiler_features:
+    config.available_features.add(feature)
+
+# Setup environment to find dynamic library at runtime
+append_dynamic_library_path(config.omp_library_dir)
+
+# Rpath modifications for Darwin
+if config.operating_system == 'Darwin':
+    config.test_flags += " -Wl,-rpath," + config.omp_library_dir
+
+# Find the SDK on Darwin
+if config.operating_system == 'Darwin':
+  cmd = subprocess.Popen(['xcrun', '--show-sdk-path'],
+                         stdout=subprocess.PIPE, stderr=subprocess.PIPE)
+  out, err = cmd.communicate()
+  out = out.strip()
+  res = cmd.wait()
+  if res == 0 and out:
+    config.test_flags += " -isysroot " + out
+
+if 'Linux' in config.operating_system:
+    config.available_features.add("linux")
+
+# to run with icc INTEL_LICENSE_FILE must be set
+if 'INTEL_LICENSE_FILE' in os.environ:
+    config.environment['INTEL_LICENSE_FILE'] = os.environ['INTEL_LICENSE_FILE']
+
+# Race Tests
+config.substitutions.append(("%libarcher-compile-and-run-race", \
+    "%libarcher-compile && %libarcher-run-race"))
+config.substitutions.append(("%libarcher-compile-and-run", \
+                             "%libarcher-compile && %libarcher-run"))
+config.substitutions.append(("%libarcher-cxx-compile-and-run", \
+    "%libarcher-cxx-compile && %libarcher-run"))
+config.substitutions.append(("%libarcher-cxx-compile", \
+    "%clang-archerXX %openmp_flags %archer_flags %flags -std=c++11 %s -o %t" + libs))
+config.substitutions.append(("%libarcher-compile", \
+                             "%clang-archer %openmp_flags %archer_flags %flags %s -o %t" + libs))
+config.substitutions.append(("%libarcher-run-race", "%suppression %deflake %t 2>&1 | tee %t.log"))
+config.substitutions.append(("%libarcher-run", "%suppression %t 2>&1 | tee %t.log"))
+config.substitutions.append(("%clang-archerXX", config.test_cxx_compiler))
+config.substitutions.append(("%clang-archer", config.test_c_compiler))
+config.substitutions.append(("%openmp_flags", config.test_openmp_flags))
+config.substitutions.append(("%archer_flags", config.archer_flags))
+config.substitutions.append(("%flags", config.test_flags))
+config.substitutions.append(("%suppression", "env TSAN_OPTIONS='ignore_noninstrumented_modules=1'"))
+config.substitutions.append(("%deflake", os.path.join(os.path.dirname(__file__), "deflake.bash")))
+
+config.substitutions.append(("FileCheck", config.test_filecheck))
+config.substitutions.append(("%sort-threads", "sort --numeric-sort --stable"))
+if config.operating_system == 'Windows':
+    # No such environment variable on Windows.
+    config.substitutions.append(("%preload-tool", "true ||"))
+elif config.operating_system == 'Darwin':
+    config.substitutions.append(("%preload-tool", "env DYLD_INSERT_LIBRARIES=%T/tool.so"))
+else:
+    config.substitutions.append(("%preload-tool", "env LD_PRELOAD=%T/tool.so"))
diff --git a/openmp/tools/archer/tests/lit.site.cfg.in b/openmp/tools/archer/tests/lit.site.cfg.in
new file mode 100644
--- /dev/null
+++ b/openmp/tools/archer/tests/lit.site.cfg.in
@@ -0,0 +1,19 @@
+@AUTO_GEN_COMMENT@
+
+config.test_c_compiler = "@OPENMP_TEST_C_COMPILER@"
+config.test_cxx_compiler = "@OPENMP_TEST_CXX_COMPILER@"
+config.test_compiler_features = @OPENMP_TEST_COMPILER_FEATURES@
+config.test_filecheck = "@OPENMP_FILECHECK_EXECUTABLE@"
+config.test_openmp_flags = "@OPENMP_TEST_OPENMP_FLAGS@"
+config.test_extra_flags = "@OPENMP_TEST_FLAGS@"
+config.libomp_obj_root = "@CMAKE_CURRENT_BINARY_DIR@"
+config.omp_library_dir = "@LIBOMP_LIBRARY_DIR@"
+config.omp_header_dir = "@LIBOMP_INCLUDE_DIR@"
+config.operating_system = "@CMAKE_SYSTEM_NAME@"
+config.has_libatomic = @LIBOMP_HAVE_LIBATOMIC@
+
+config.test_archer_flags = "@OPENMP_TEST_ARCHER_FLAGS@"
+config.libarcher_obj_root = "@CMAKE_CURRENT_BINARY_DIR@"
+
+# Let the main config do the real work.
+lit_config.load_config(config, "@CMAKE_CURRENT_SOURCE_DIR@/lit.cfg")
diff --git a/openmp/tools/archer/tests/ompt/ompt-signal.h b/openmp/tools/archer/tests/ompt/ompt-signal.h
new file mode 100644
--- /dev/null
+++ b/openmp/tools/archer/tests/ompt/ompt-signal.h
@@ -0,0 +1,42 @@
+/*
+ * ompt-signal.h -- Header providing low-level synchronization for tests
+ */
+
+//===----------------------------------------------------------------------===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is a copy from runtime/test/ompt/
+//
+//===----------------------------------------------------------------------===//
+
+#if defined(WIN32) || defined(_WIN32)
+#include 
+#define delay() Sleep(1);
+#else
+#include 
+#define delay(t) usleep(t);
+#endif
+
+// These functions are used to provide a signal-wait mechanism to enforce
+// expected scheduling for the test cases.
+// Conditional variable (s) needs to be shared! Initialize to 0
+
+#define OMPT_SIGNAL(s) ompt_signal(&s)
+// inline
+void ompt_signal(int *s) {
+#pragma omp atomic
+  (*s)++;
+}
+
+#define OMPT_WAIT(s, v) ompt_wait(&s, v)
+// wait for s >= v
+// inline
+void ompt_wait(int *s, int v) {
+  int wait = 0;
+  do {
+    delay(10);
+#pragma omp atomic read
+    wait = (*s);
+  } while (wait < v);
+}
diff --git a/openmp/tools/archer/tests/parallel/parallel-firstprivate.c b/openmp/tools/archer/tests/parallel/parallel-firstprivate.c
new file mode 100644
--- /dev/null
+++ b/openmp/tools/archer/tests/parallel/parallel-firstprivate.c
@@ -0,0 +1,32 @@
+/*
+ * parallel-firstprivate.c -- Archer testcase
+ */
+
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+//
+// See tools/archer/LICENSE.txt for details.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+
+// RUN: %libarcher-compile-and-run | FileCheck %s
+#include 
+#include 
+
+int main(int argc, char *argv[]) {
+  int var = 0;
+
+#pragma omp parallel num_threads(2) firstprivate(var)
+  { var = 1; }
+
+  fprintf(stderr, "DONE\n");
+  // var should still be 0!
+  return var;
+}
+
+// CHECK-NOT: ThreadSanitizer: data race
+// CHECK-NOT: ThreadSanitizer: reported
+// CHECK: DONE
diff --git a/openmp/tools/archer/tests/parallel/parallel-simple.c b/openmp/tools/archer/tests/parallel/parallel-simple.c
new file mode 100644
--- /dev/null
+++ b/openmp/tools/archer/tests/parallel/parallel-simple.c
@@ -0,0 +1,38 @@
+/*
+ * parallel-simple.c -- Archer testcase
+ */
+
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+//
+// See tools/archer/LICENSE.txt for details.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+
+// RUN: %libarcher-compile-and-run | FileCheck %s
+#include 
+#include 
+
+int main(int argc, char *argv[]) {
+  int var = 0;
+
+#pragma omp parallel num_threads(2) shared(var)
+  {
+    if (omp_get_thread_num() == 1) {
+      var++;
+    }
+  } // implicit barrier
+
+  var++;
+
+  fprintf(stderr, "DONE\n");
+  int error = (var != 2);
+  return error;
+}
+
+// CHECK-NOT: ThreadSanitizer: data race
+// CHECK-NOT: ThreadSanitizer: reported
+// CHECK: DONE
diff --git a/openmp/tools/archer/tests/parallel/parallel-simple2.c b/openmp/tools/archer/tests/parallel/parallel-simple2.c
new file mode 100644
--- /dev/null
+++ b/openmp/tools/archer/tests/parallel/parallel-simple2.c
@@ -0,0 +1,43 @@
+/*
+ * parallel-simple2.c -- Archer testcase
+ */
+
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+//
+// See tools/archer/LICENSE.txt for details.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+
+// RUN: %libarcher-compile-and-run  | FileCheck %s
+#include 
+#include 
+
+int main(int argc, char *argv[]) {
+  int var = 0;
+
+// Create team of threads so that there is no implicit happens before
+// when creating the thread.
+#pragma omp parallel num_threads(2)
+  {}
+
+  var++;
+
+#pragma omp parallel num_threads(2) shared(var)
+  {
+    if (omp_get_thread_num() == 1) {
+      var++;
+    }
+  } // implicit barrier
+
+  fprintf(stderr, "DONE\n");
+  int error = (var != 2);
+  return error;
+}
+
+// CHECK-NOT: ThreadSanitizer: data race
+// CHECK-NOT: ThreadSanitizer: reported
+// CHECK: DONE
diff --git a/openmp/tools/archer/tests/races/critical-unrelated.c b/openmp/tools/archer/tests/races/critical-unrelated.c
new file mode 100644
--- /dev/null
+++ b/openmp/tools/archer/tests/races/critical-unrelated.c
@@ -0,0 +1,42 @@
+/*
+ * critical-unrelated.c -- Archer testcase
+ */
+
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+//
+// See tools/archer/LICENSE.txt for details.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+
+// RUN: %libarcher-compile-and-run-race | FileCheck %s
+#include 
+#include 
+
+int main(int argc, char *argv[]) {
+  int var = 0;
+
+#pragma omp parallel num_threads(2) shared(var)
+  {
+#pragma omp critical
+    {
+      // Dummy region.
+    }
+
+    var++;
+  }
+
+  fprintf(stderr, "DONE\n");
+}
+
+// CHECK: WARNING: ThreadSanitizer: data race
+// CHECK-NEXT:   {{(Write|Read)}} of size 4
+// CHECK-NEXT: #0 {{.*}}critical-unrelated.c:29
+// CHECK:   Previous write of size 4
+// CHECK-NEXT: #0 {{.*}}critical-unrelated.c:29
+// CHECK: DONE
+// CHECK: ThreadSanitizer: reported 1 warnings
+
diff --git a/openmp/tools/archer/tests/races/lock-nested-unrelated.c b/openmp/tools/archer/tests/races/lock-nested-unrelated.c
new file mode 100644
--- /dev/null
+++ b/openmp/tools/archer/tests/races/lock-nested-unrelated.c
@@ -0,0 +1,48 @@
+/*
+ * lock-nested-unrelated.c -- Archer testcase
+ */
+
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+//
+// See tools/archer/LICENSE.txt for details.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+
+// RUN: %libarcher-compile-and-run-race | FileCheck %s
+#include 
+#include 
+
+int main(int argc, char *argv[]) {
+  int var = 0;
+
+  omp_nest_lock_t lock;
+  omp_init_nest_lock(&lock);
+
+#pragma omp parallel num_threads(2) shared(var)
+  {
+    omp_set_nest_lock(&lock);
+    omp_set_nest_lock(&lock);
+    // Dummy locking.
+    omp_unset_nest_lock(&lock);
+    omp_unset_nest_lock(&lock);
+
+    var++;
+  }
+
+  omp_destroy_nest_lock(&lock);
+
+  fprintf(stderr, "DONE\n");
+}
+
+// CHECK: WARNING: ThreadSanitizer: data race
+// CHECK-NEXT:   {{(Write|Read)}} of size 4
+// CHECK-NEXT: #0 {{.*}}lock-nested-unrelated.c:33
+// CHECK:   Previous write of size 4
+// CHECK-NEXT: #0 {{.*}}lock-nested-unrelated.c:33
+// CHECK: DONE
+// CHECK: ThreadSanitizer: reported 1 warnings
+
diff --git a/openmp/tools/archer/tests/races/lock-unrelated.c b/openmp/tools/archer/tests/races/lock-unrelated.c
new file mode 100644
--- /dev/null
+++ b/openmp/tools/archer/tests/races/lock-unrelated.c
@@ -0,0 +1,48 @@
+/*
+ * lock-unrelated.c -- Archer testcase
+ */
+
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+//
+// See tools/archer/LICENSE.txt for details.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+
+// RUN: %libarcher-compile-and-run-race | FileCheck %s
+#include 
+#include 
+
+int main(int argc, char *argv[]) {
+  int var = 0;
+
+  omp_lock_t lock;
+  omp_init_lock(&lock);
+
+#pragma omp parallel num_threads(2) shared(var)
+  {
+    omp_set_lock(&lock);
+    // Dummy locking.
+    omp_unset_lock(&lock);
+
+    var++;
+  }
+
+  omp_destroy_lock(&lock);
+
+  int error = (var != 2);
+  fprintf(stderr, "DONE\n");
+  return error;
+}
+
+// CHECK: WARNING: ThreadSanitizer: data race
+// CHECK-NEXT:   {{(Write|Read)}} of size 4
+// CHECK-NEXT: #0 {{.*}}lock-unrelated.c:31
+// CHECK:   Previous write of size 4
+// CHECK-NEXT: #0 {{.*}}lock-unrelated.c:31
+// CHECK: DONE
+// CHECK: ThreadSanitizer: reported 1 warnings
+
diff --git a/openmp/tools/archer/tests/races/parallel-simple.c b/openmp/tools/archer/tests/races/parallel-simple.c
new file mode 100644
--- /dev/null
+++ b/openmp/tools/archer/tests/races/parallel-simple.c
@@ -0,0 +1,37 @@
+/*
+ * parallel-simple.c -- Archer testcase
+ */
+
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+//
+// See tools/archer/LICENSE.txt for details.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+
+// RUN: %libarcher-compile-and-run-race | FileCheck %s
+#include 
+#include 
+
+int main(int argc, char *argv[]) {
+  int var = 0;
+
+#pragma omp parallel num_threads(2) shared(var)
+  { var++; }
+
+  int error = (var != 2);
+  fprintf(stderr, "DONE\n");
+  return error;
+}
+
+// CHECK: WARNING: ThreadSanitizer: data race
+// CHECK-NEXT:   {{(Write|Read)}} of size 4
+// CHECK-NEXT: #0 {{.*}}parallel-simple.c:23
+// CHECK:   Previous write of size 4
+// CHECK-NEXT: #0 {{.*}}parallel-simple.c:23
+// CHECK: DONE
+// CHECK: ThreadSanitizer: reported 1 warnings
+
diff --git a/openmp/tools/archer/tests/races/task-dependency.c b/openmp/tools/archer/tests/races/task-dependency.c
new file mode 100644
--- /dev/null
+++ b/openmp/tools/archer/tests/races/task-dependency.c
@@ -0,0 +1,61 @@
+/*
+ * task-deoendency.c -- Archer testcase
+ */
+
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+//
+// See tools/archer/LICENSE.txt for details.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+
+// RUN: %libarcher-compile-and-run-race | FileCheck %s
+#include 
+#include 
+#include 
+#include "ompt/ompt-signal.h"
+
+int main(int argc, char *argv[]) {
+  int var = 0, a = 0;
+
+#pragma omp parallel num_threads(2) shared(var, a)
+#pragma omp master
+  {
+#pragma omp task shared(var, a) depend(out : var)
+    {
+      OMPT_SIGNAL(a);
+      var++;
+    }
+
+#pragma omp task shared(a) depend(in : var)
+    {
+      OMPT_SIGNAL(a);
+      OMPT_WAIT(a, 3);
+    }
+
+#pragma omp task shared(var) // depend(in: var) is missing here!
+    {
+      var++;
+      OMPT_SIGNAL(a);
+    }
+
+    // Give other thread time to steal the task.
+    OMPT_WAIT(a, 2);
+  }
+
+  int error = (var != 2);
+  fprintf(stderr, "DONE\n");
+  return error;
+}
+
+// CHECK: WARNING: ThreadSanitizer: data race
+// CHECK-NEXT:   {{(Write|Read)}} of size 4
+// CHECK-NEXT: #0 {{.*}}task-dependency.c:41
+// CHECK:   Previous write of size 4
+// CHECK-NEXT: #0 {{.*}}task-dependency.c:30
+// CHECK: DONE
+// CHECK: ThreadSanitizer: reported 1 warnings
+
diff --git a/openmp/tools/archer/tests/races/task-taskgroup-unrelated.c b/openmp/tools/archer/tests/races/task-taskgroup-unrelated.c
new file mode 100644
--- /dev/null
+++ b/openmp/tools/archer/tests/races/task-taskgroup-unrelated.c
@@ -0,0 +1,61 @@
+/*
+ * task-taskgroup-unrelated.c -- Archer testcase
+ */
+
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+//
+// See tools/archer/LICENSE.txt for details.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+// RUN: %libarcher-compile-and-run-race | FileCheck %s
+#include 
+#include 
+#include 
+#include "ompt/ompt-signal.h"
+
+int main(int argc, char *argv[]) {
+  int var = 0, a = 0;
+
+#pragma omp parallel num_threads(2) shared(var, a)
+#pragma omp master
+  {
+#pragma omp task shared(var, a)
+    {
+      var++;
+      OMPT_SIGNAL(a);
+      // Give master thread time to execute the task in the taskgroup.
+      OMPT_WAIT(a, 2);
+    }
+
+#pragma omp taskgroup
+    {
+#pragma omp task if (0)
+      {
+        // Dummy task.
+      }
+
+      // Give other threads time to steal the tasks.
+      OMPT_WAIT(a, 1);
+      OMPT_SIGNAL(a);
+    }
+
+    var++;
+  }
+
+  int error = (var != 2);
+  fprintf(stderr, "DONE\n");
+  return error;
+}
+
+// CHECK: WARNING: ThreadSanitizer: data race
+// CHECK-NEXT:   {{(Write|Read)}} of size 4
+// CHECK-NEXT: #0 {{.*}}task-taskgroup-unrelated.c:46
+// CHECK:   Previous write of size 4
+// CHECK-NEXT: #0 {{.*}}task-taskgroup-unrelated.c:28
+// CHECK: DONE
+// CHECK: ThreadSanitizer: reported 1 warnings
+
diff --git a/openmp/tools/archer/tests/races/task-taskwait-nested.c b/openmp/tools/archer/tests/races/task-taskwait-nested.c
new file mode 100644
--- /dev/null
+++ b/openmp/tools/archer/tests/races/task-taskwait-nested.c
@@ -0,0 +1,59 @@
+/*
+ * task-taskwait-nested.c -- Archer testcase
+ */
+
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+//
+// See tools/archer/LICENSE.txt for details.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+
+// RUN: %libarcher-compile-and-run-race | FileCheck %s
+#include 
+#include 
+#include 
+#include "ompt/ompt-signal.h"
+
+int main(int argc, char *argv[]) {
+  int var = 0, a = 0;
+
+#pragma omp parallel num_threads(2) shared(var, a)
+#pragma omp master
+  {
+#pragma omp task shared(var, a)
+    {
+#pragma omp task shared(var, a)
+      {
+        // wait for master to pass the taskwait
+        OMPT_SIGNAL(a);
+        OMPT_WAIT(a, 2);
+        var++;
+      }
+    }
+
+    // Give other thread time to steal the task and execute its child.
+    OMPT_WAIT(a, 1);
+
+// Only directly generated children are guaranteed to be executed.
+#pragma omp taskwait
+    OMPT_SIGNAL(a);
+    var++;
+  }
+
+  int error = (var != 2);
+  fprintf(stderr, "DONE\n");
+  return error;
+}
+
+// CHECK: WARNING: ThreadSanitizer: data race
+// CHECK-NEXT:   {{(Write|Read)}} of size 4
+// CHECK-NEXT: #0 {{.*}}task-taskwait-nested.c:34
+// CHECK:   Previous write of size 4
+// CHECK-NEXT: #0 {{.*}}task-taskwait-nested.c:44
+// CHECK: DONE
+// CHECK: ThreadSanitizer: reported 1 warnings
+
diff --git a/openmp/tools/archer/tests/races/task-two.c b/openmp/tools/archer/tests/races/task-two.c
new file mode 100644
--- /dev/null
+++ b/openmp/tools/archer/tests/races/task-two.c
@@ -0,0 +1,45 @@
+/*
+ * task-two.c -- Archer testcase
+ */
+
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+//
+// See tools/archer/LICENSE.txt for details.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+
+// RUN: %libarcher-compile-and-run-race | FileCheck %s
+#include 
+#include 
+#include 
+
+#define NUM_THREADS 2
+
+int main(int argc, char *argv[]) {
+  int var = 0;
+  int i;
+
+#pragma omp parallel for num_threads(NUM_THREADS) shared(var) schedule(static, \
+                                                                       1)
+  for (i = 0; i < NUM_THREADS; i++) {
+#pragma omp task shared(var) if (0) // the task is inlined an executed locally
+    { var++; }
+  }
+
+  int error = (var != 2);
+  fprintf(stderr, "DONE\n");
+  return error;
+}
+
+// CHECK: WARNING: ThreadSanitizer: data race
+// CHECK-NEXT:   {{(Write|Read)}} of size 4
+// CHECK-NEXT: #0 {{.*}}task-two.c:30
+// CHECK:   Previous write of size 4
+// CHECK-NEXT: #0 {{.*}}task-two.c:30
+// CHECK: DONE
+// CHECK: ThreadSanitizer: reported 1 warnings
+
diff --git a/openmp/tools/archer/tests/reduction/parallel-reduction-nowait.c b/openmp/tools/archer/tests/reduction/parallel-reduction-nowait.c
new file mode 100644
--- /dev/null
+++ b/openmp/tools/archer/tests/reduction/parallel-reduction-nowait.c
@@ -0,0 +1,45 @@
+/*
+ * parallel-reduction-nowait.c -- Archer testcase
+ */
+
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+//
+// See tools/archer/LICENSE.txt for details.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+
+// RUN: %libarcher-compile-and-run | FileCheck %s
+#include 
+#include 
+
+int main(int argc, char *argv[]) {
+  int var = 0, i;
+  int sum1 = 0;
+  int sum2 = 0;
+
+// Number of threads is empirical: We need enough threads so that
+// the reduction is really performed hierarchically in the barrier!
+#pragma omp parallel num_threads(5) reduction(+ : var)
+  {
+#pragma omp for schedule(static) nowait reduction(+ : sum1)
+    for (i = 0; i < 5; i++)
+      sum1 += i;
+#pragma omp for schedule(static) reduction(+ : sum2)
+    for (i = 0; i < 5; i++)
+      sum2 += i;
+
+    var = sum1 + sum2;
+  }
+
+  fprintf(stderr, "DONE\n");
+  int error = (var != 100);
+  return error;
+}
+
+// CHECK-NOT: ThreadSanitizer: data race
+// CHECK-NOT: ThreadSanitizer: reported
+// CHECK: DONE
diff --git a/openmp/tools/archer/tests/reduction/parallel-reduction.c b/openmp/tools/archer/tests/reduction/parallel-reduction.c
new file mode 100644
--- /dev/null
+++ b/openmp/tools/archer/tests/reduction/parallel-reduction.c
@@ -0,0 +1,34 @@
+/*
+ * parallel-reduction.c -- Archer testcase
+ */
+
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+//
+// See tools/archer/LICENSE.txt for details.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+
+// RUN: %libarcher-compile-and-run| FileCheck %s
+#include 
+#include 
+
+int main(int argc, char *argv[]) {
+  int var = 0;
+
+// Number of threads is empirical: We need enough threads so that
+// the reduction is really performed hierarchically in the barrier!
+#pragma omp parallel num_threads(5) reduction(+ : var)
+  { var = 1; }
+
+  fprintf(stderr, "DONE\n");
+  int error = (var != 5);
+  return error;
+}
+
+// CHECK-NOT: ThreadSanitizer: data race
+// CHECK-NOT: ThreadSanitizer: reported
+// CHECK: DONE
diff --git a/openmp/tools/archer/tests/task/task-barrier.c b/openmp/tools/archer/tests/task/task-barrier.c
new file mode 100644
--- /dev/null
+++ b/openmp/tools/archer/tests/task/task-barrier.c
@@ -0,0 +1,51 @@
+/*
+ * task-barrier.c -- Archer testcase
+ */
+
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+//
+// See tools/archer/LICENSE.txt for details.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+
+// RUN: %libarcher-compile-and-run | FileCheck %s
+#include 
+#include 
+#include 
+#include "ompt/ompt-signal.h"
+
+int main(int argc, char *argv[]) {
+  int var = 0, a = 0;
+
+#pragma omp parallel num_threads(2) shared(var, a)
+  {
+#pragma omp master
+    {
+#pragma omp task shared(var)
+      {
+        OMPT_SIGNAL(a);
+        var++;
+      }
+
+      // Give other thread time to steal the task.
+      OMPT_WAIT(a, 1);
+    }
+
+#pragma omp barrier
+
+#pragma omp master
+    { var++; }
+  }
+
+  fprintf(stderr, "DONE\n");
+  int error = (var != 2);
+  return error;
+}
+
+// CHECK-NOT: ThreadSanitizer: data race
+// CHECK-NOT: ThreadSanitizer: reported
+// CHECK: DONE
diff --git a/openmp/tools/archer/tests/task/task-create.c b/openmp/tools/archer/tests/task/task-create.c
new file mode 100644
--- /dev/null
+++ b/openmp/tools/archer/tests/task/task-create.c
@@ -0,0 +1,45 @@
+/*
+ * task-create.c -- Archer testcase
+ */
+
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+//
+// See tools/archer/LICENSE.txt for details.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+
+// RUN: %libarcher-compile-and-run | FileCheck %s
+#include 
+#include 
+#include 
+#include "ompt/ompt-signal.h"
+
+int main(int argc, char *argv[]) {
+  int var = 0, a = 0;
+
+#pragma omp parallel num_threads(2) shared(var, a)
+#pragma omp master
+  {
+    var++;
+#pragma omp task shared(var, a)
+    {
+      var++;
+      OMPT_SIGNAL(a);
+    }
+
+    // Give other thread time to steal the task.
+    OMPT_WAIT(a, 1);
+  }
+
+  fprintf(stderr, "DONE\n");
+  int error = (var != 2);
+  return error;
+}
+
+// CHECK-NOT: ThreadSanitizer: data race
+// CHECK-NOT: ThreadSanitizer: reported
+// CHECK: DONE
diff --git a/openmp/tools/archer/tests/task/task-dependency.c b/openmp/tools/archer/tests/task/task-dependency.c
new file mode 100644
--- /dev/null
+++ b/openmp/tools/archer/tests/task/task-dependency.c
@@ -0,0 +1,53 @@
+/*
+ * task-dependency.c -- Archer testcase
+ */
+
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+//
+// See tools/archer/LICENSE.txt for details.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+
+// RUN: %libarcher-compile-and-run | FileCheck %s
+#include 
+#include 
+#include 
+#include "ompt/ompt-signal.h"
+
+int main(int argc, char *argv[]) {
+  int var = 0, a = 0;
+
+#pragma omp parallel num_threads(2) shared(var, a)
+#pragma omp master
+  {
+#pragma omp task shared(var, a) depend(out : var)
+    {
+      var++;
+      OMPT_SIGNAL(a);
+    }
+
+#pragma omp task shared(var, a) depend(in : var)
+    { OMPT_WAIT(a, 2); }
+
+#pragma omp task shared(var, a) depend(in : var)
+    {
+      OMPT_SIGNAL(a);
+      var++;
+    }
+
+    // Give other thread time to steal the task.
+    OMPT_WAIT(a, 1);
+  }
+
+  fprintf(stderr, "DONE\n");
+  int error = (var != 2);
+  return error;
+}
+
+// CHECK-NOT: ThreadSanitizer: data race
+// CHECK-NOT: ThreadSanitizer: reported
+// CHECK: DONE
diff --git a/openmp/tools/archer/tests/task/task-taskgroup-nested.c b/openmp/tools/archer/tests/task/task-taskgroup-nested.c
new file mode 100644
--- /dev/null
+++ b/openmp/tools/archer/tests/task/task-taskgroup-nested.c
@@ -0,0 +1,52 @@
+/*
+ * task-taskgroup-nested.c -- Archer testcase
+ */
+
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+//
+// See tools/archer/LICENSE.txt for details.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+
+// RUN: %libarcher-compile-and-run | FileCheck %s
+#include 
+#include 
+#include 
+#include "ompt/ompt-signal.h"
+
+int main(int argc, char *argv[]) {
+  int var = 0, a = 0;
+
+#pragma omp parallel num_threads(2) shared(var, a)
+#pragma omp master
+  {
+#pragma omp taskgroup
+    {
+#pragma omp task
+      {
+#pragma omp task shared(var, a)
+        {
+          var++;
+          OMPT_SIGNAL(a);
+        }
+      }
+
+      // Give other thread time to steal the task and execute its child.
+      OMPT_WAIT(a, 1);
+    }
+
+    var++;
+  }
+
+  fprintf(stderr, "DONE\n");
+  int error = (var != 2);
+  return error;
+}
+
+// CHECK-NOT: ThreadSanitizer: data race
+// CHECK-NOT: ThreadSanitizer: reported
+// CHECK: DONE
diff --git a/openmp/tools/archer/tests/task/task-taskgroup.c b/openmp/tools/archer/tests/task/task-taskgroup.c
new file mode 100644
--- /dev/null
+++ b/openmp/tools/archer/tests/task/task-taskgroup.c
@@ -0,0 +1,49 @@
+/*
+ * task-taskgroup.c -- Archer testcase
+ */
+
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+//
+// See tools/archer/LICENSE.txt for details.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+
+// RUN: %libarcher-compile-and-run | FileCheck %s
+#include 
+#include 
+#include 
+#include "ompt/ompt-signal.h"
+
+int main(int argc, char *argv[]) {
+  int var = 0, a = 0;
+
+#pragma omp parallel num_threads(2) shared(var, a)
+#pragma omp master
+  {
+#pragma omp taskgroup
+    {
+#pragma omp task shared(var, a)
+      {
+        var++;
+        OMPT_SIGNAL(a);
+      }
+
+      // Give other thread time to steal the task.
+      OMPT_WAIT(a, 1);
+    }
+
+    var++;
+  }
+
+  fprintf(stderr, "DONE\n");
+  int error = (var != 2);
+  return error;
+}
+
+// CHECK-NOT: ThreadSanitizer: data race
+// CHECK-NOT: ThreadSanitizer: reported
+// CHECK: DONE
diff --git a/openmp/tools/archer/tests/task/task-taskwait-nested.c b/openmp/tools/archer/tests/task/task-taskwait-nested.c
new file mode 100644
--- /dev/null
+++ b/openmp/tools/archer/tests/task/task-taskwait-nested.c
@@ -0,0 +1,52 @@
+/*
+ * task-taskwait-nested.c -- Archer testcase
+ */
+
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+//
+// See tools/archer/LICENSE.txt for details.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+
+// RUN: %libarcher-compile-and-run | FileCheck %s
+#include 
+#include 
+#include 
+#include "ompt/ompt-signal.h"
+
+int main(int argc, char *argv[]) {
+  int var = 0, a = 0;
+
+#pragma omp parallel num_threads(2) shared(var, a)
+#pragma omp master
+  {
+#pragma omp task
+    {
+#pragma omp task shared(var, a)
+      {
+        OMPT_SIGNAL(a);
+        delay(100);
+        var++;
+      }
+#pragma omp taskwait
+    }
+
+    // Give other thread time to steal the task and execute its child.
+    OMPT_WAIT(a, 1);
+
+#pragma omp taskwait
+    var++;
+  }
+
+  fprintf(stderr, "DONE\n");
+  int error = (var != 2);
+  return error;
+}
+
+// CHECK-NOT: ThreadSanitizer: data race
+// CHECK-NOT: ThreadSanitizer: reported
+// CHECK: DONE
diff --git a/openmp/tools/archer/tests/task/task-taskwait.c b/openmp/tools/archer/tests/task/task-taskwait.c
new file mode 100644
--- /dev/null
+++ b/openmp/tools/archer/tests/task/task-taskwait.c
@@ -0,0 +1,49 @@
+/*
+ * task-taskwait.c -- Archer testcase
+ */
+
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+//
+// See tools/archer/LICENSE.txt for details.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+
+// RUN: %libarcher-compile-and-run | FileCheck %s
+#include 
+#include 
+#include 
+#include "ompt/ompt-signal.h"
+
+int main(int argc, char *argv[]) {
+  int var = 0, a = 0;
+
+#pragma omp parallel num_threads(2) shared(var, a)
+#pragma omp master
+  {
+#pragma omp task shared(var, a)
+    {
+      OMPT_SIGNAL(a);
+      OMPT_WAIT(a, 2);
+      delay(100);
+      var++;
+    }
+
+    // Give other thread time to steal the task.
+    OMPT_WAIT(a, 1);
+    OMPT_SIGNAL(a);
+#pragma omp taskwait
+    var++;
+  }
+
+  fprintf(stderr, "DONE\n");
+  int error = (var != 2);
+  return error;
+}
+
+// CHECK-NOT: ThreadSanitizer: data race
+// CHECK-NOT: ThreadSanitizer: reported
+// CHECK: DONE
diff --git a/openmp/tools/archer/tests/worksharing/ordered.c b/openmp/tools/archer/tests/worksharing/ordered.c
new file mode 100644
--- /dev/null
+++ b/openmp/tools/archer/tests/worksharing/ordered.c
@@ -0,0 +1,38 @@
+/*
+ * ordered.c -- Archer testcase
+ */
+
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+//
+// See tools/archer/LICENSE.txt for details.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+
+// RUN: %libarcher-compile-and-run | FileCheck %s
+#include 
+#include 
+
+#define NUM_THREADS 2
+
+int main(int argc, char *argv[]) {
+  int var = 0;
+  int i;
+
+#pragma omp parallel for ordered num_threads(NUM_THREADS) shared(var)
+  for (i = 0; i < NUM_THREADS; i++) {
+#pragma omp ordered
+    { var++; }
+  }
+
+  fprintf(stderr, "DONE\n");
+  int error = (var != 2);
+  return error;
+}
+
+// CHECK-NOT: ThreadSanitizer: data race
+// CHECK-NOT: ThreadSanitizer: reported
+// CHECK: DONE