1*349cc55cSDimitry Andric //===-- tsan_vector_clock.cpp ---------------------------------------------===//
2*349cc55cSDimitry Andric //
3*349cc55cSDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4*349cc55cSDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
5*349cc55cSDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6*349cc55cSDimitry Andric //
7*349cc55cSDimitry Andric //===----------------------------------------------------------------------===//
8*349cc55cSDimitry Andric //
9*349cc55cSDimitry Andric // This file is a part of ThreadSanitizer (TSan), a race detector.
10*349cc55cSDimitry Andric //
11*349cc55cSDimitry Andric //===----------------------------------------------------------------------===//
12*349cc55cSDimitry Andric #include "tsan_vector_clock.h"
13*349cc55cSDimitry Andric 
14*349cc55cSDimitry Andric #include "sanitizer_common/sanitizer_placement_new.h"
15*349cc55cSDimitry Andric #include "tsan_mman.h"
16*349cc55cSDimitry Andric 
17*349cc55cSDimitry Andric namespace __tsan {
18*349cc55cSDimitry Andric 
19*349cc55cSDimitry Andric #if TSAN_VECTORIZE
20*349cc55cSDimitry Andric const uptr kVectorClockSize = kThreadSlotCount * sizeof(Epoch) / sizeof(m128);
21*349cc55cSDimitry Andric #endif
22*349cc55cSDimitry Andric 
VectorClock()23*349cc55cSDimitry Andric VectorClock::VectorClock() { Reset(); }
24*349cc55cSDimitry Andric 
Reset()25*349cc55cSDimitry Andric void VectorClock::Reset() {
26*349cc55cSDimitry Andric #if !TSAN_VECTORIZE
27*349cc55cSDimitry Andric   for (uptr i = 0; i < kThreadSlotCount; i++)
28*349cc55cSDimitry Andric     clk_[i] = kEpochZero;
29*349cc55cSDimitry Andric #else
30*349cc55cSDimitry Andric   m128 z = _mm_setzero_si128();
31*349cc55cSDimitry Andric   m128* vclk = reinterpret_cast<m128*>(clk_);
32*349cc55cSDimitry Andric   for (uptr i = 0; i < kVectorClockSize; i++) _mm_store_si128(&vclk[i], z);
33*349cc55cSDimitry Andric #endif
34*349cc55cSDimitry Andric }
35*349cc55cSDimitry Andric 
Acquire(const VectorClock * src)36*349cc55cSDimitry Andric void VectorClock::Acquire(const VectorClock* src) {
37*349cc55cSDimitry Andric   if (!src)
38*349cc55cSDimitry Andric     return;
39*349cc55cSDimitry Andric #if !TSAN_VECTORIZE
40*349cc55cSDimitry Andric   for (uptr i = 0; i < kThreadSlotCount; i++)
41*349cc55cSDimitry Andric     clk_[i] = max(clk_[i], src->clk_[i]);
42*349cc55cSDimitry Andric #else
43*349cc55cSDimitry Andric   m128* __restrict vdst = reinterpret_cast<m128*>(clk_);
44*349cc55cSDimitry Andric   m128 const* __restrict vsrc = reinterpret_cast<m128 const*>(src->clk_);
45*349cc55cSDimitry Andric   for (uptr i = 0; i < kVectorClockSize; i++) {
46*349cc55cSDimitry Andric     m128 s = _mm_load_si128(&vsrc[i]);
47*349cc55cSDimitry Andric     m128 d = _mm_load_si128(&vdst[i]);
48*349cc55cSDimitry Andric     m128 m = _mm_max_epu16(s, d);
49*349cc55cSDimitry Andric     _mm_store_si128(&vdst[i], m);
50*349cc55cSDimitry Andric   }
51*349cc55cSDimitry Andric #endif
52*349cc55cSDimitry Andric }
53*349cc55cSDimitry Andric 
AllocClock(VectorClock ** dstp)54*349cc55cSDimitry Andric static VectorClock* AllocClock(VectorClock** dstp) {
55*349cc55cSDimitry Andric   if (UNLIKELY(!*dstp))
56*349cc55cSDimitry Andric     *dstp = New<VectorClock>();
57*349cc55cSDimitry Andric   return *dstp;
58*349cc55cSDimitry Andric }
59*349cc55cSDimitry Andric 
Release(VectorClock ** dstp) const60*349cc55cSDimitry Andric void VectorClock::Release(VectorClock** dstp) const {
61*349cc55cSDimitry Andric   VectorClock* dst = AllocClock(dstp);
62*349cc55cSDimitry Andric   dst->Acquire(this);
63*349cc55cSDimitry Andric }
64*349cc55cSDimitry Andric 
ReleaseStore(VectorClock ** dstp) const65*349cc55cSDimitry Andric void VectorClock::ReleaseStore(VectorClock** dstp) const {
66*349cc55cSDimitry Andric   VectorClock* dst = AllocClock(dstp);
67*349cc55cSDimitry Andric   *dst = *this;
68*349cc55cSDimitry Andric }
69*349cc55cSDimitry Andric 
operator =(const VectorClock & other)70*349cc55cSDimitry Andric VectorClock& VectorClock::operator=(const VectorClock& other) {
71*349cc55cSDimitry Andric #if !TSAN_VECTORIZE
72*349cc55cSDimitry Andric   for (uptr i = 0; i < kThreadSlotCount; i++)
73*349cc55cSDimitry Andric     clk_[i] = other.clk_[i];
74*349cc55cSDimitry Andric #else
75*349cc55cSDimitry Andric   m128* __restrict vdst = reinterpret_cast<m128*>(clk_);
76*349cc55cSDimitry Andric   m128 const* __restrict vsrc = reinterpret_cast<m128 const*>(other.clk_);
77*349cc55cSDimitry Andric   for (uptr i = 0; i < kVectorClockSize; i++) {
78*349cc55cSDimitry Andric     m128 s = _mm_load_si128(&vsrc[i]);
79*349cc55cSDimitry Andric     _mm_store_si128(&vdst[i], s);
80*349cc55cSDimitry Andric   }
81*349cc55cSDimitry Andric #endif
82*349cc55cSDimitry Andric   return *this;
83*349cc55cSDimitry Andric }
84*349cc55cSDimitry Andric 
ReleaseStoreAcquire(VectorClock ** dstp)85*349cc55cSDimitry Andric void VectorClock::ReleaseStoreAcquire(VectorClock** dstp) {
86*349cc55cSDimitry Andric   VectorClock* dst = AllocClock(dstp);
87*349cc55cSDimitry Andric #if !TSAN_VECTORIZE
88*349cc55cSDimitry Andric   for (uptr i = 0; i < kThreadSlotCount; i++) {
89*349cc55cSDimitry Andric     Epoch tmp = dst->clk_[i];
90*349cc55cSDimitry Andric     dst->clk_[i] = clk_[i];
91*349cc55cSDimitry Andric     clk_[i] = max(clk_[i], tmp);
92*349cc55cSDimitry Andric   }
93*349cc55cSDimitry Andric #else
94*349cc55cSDimitry Andric   m128* __restrict vdst = reinterpret_cast<m128*>(dst->clk_);
95*349cc55cSDimitry Andric   m128* __restrict vclk = reinterpret_cast<m128*>(clk_);
96*349cc55cSDimitry Andric   for (uptr i = 0; i < kVectorClockSize; i++) {
97*349cc55cSDimitry Andric     m128 t = _mm_load_si128(&vdst[i]);
98*349cc55cSDimitry Andric     m128 c = _mm_load_si128(&vclk[i]);
99*349cc55cSDimitry Andric     m128 m = _mm_max_epu16(c, t);
100*349cc55cSDimitry Andric     _mm_store_si128(&vdst[i], c);
101*349cc55cSDimitry Andric     _mm_store_si128(&vclk[i], m);
102*349cc55cSDimitry Andric   }
103*349cc55cSDimitry Andric #endif
104*349cc55cSDimitry Andric }
105*349cc55cSDimitry Andric 
ReleaseAcquire(VectorClock ** dstp)106*349cc55cSDimitry Andric void VectorClock::ReleaseAcquire(VectorClock** dstp) {
107*349cc55cSDimitry Andric   VectorClock* dst = AllocClock(dstp);
108*349cc55cSDimitry Andric #if !TSAN_VECTORIZE
109*349cc55cSDimitry Andric   for (uptr i = 0; i < kThreadSlotCount; i++) {
110*349cc55cSDimitry Andric     dst->clk_[i] = max(dst->clk_[i], clk_[i]);
111*349cc55cSDimitry Andric     clk_[i] = dst->clk_[i];
112*349cc55cSDimitry Andric   }
113*349cc55cSDimitry Andric #else
114*349cc55cSDimitry Andric   m128* __restrict vdst = reinterpret_cast<m128*>(dst->clk_);
115*349cc55cSDimitry Andric   m128* __restrict vclk = reinterpret_cast<m128*>(clk_);
116*349cc55cSDimitry Andric   for (uptr i = 0; i < kVectorClockSize; i++) {
117*349cc55cSDimitry Andric     m128 c = _mm_load_si128(&vclk[i]);
118*349cc55cSDimitry Andric     m128 d = _mm_load_si128(&vdst[i]);
119*349cc55cSDimitry Andric     m128 m = _mm_max_epu16(c, d);
120*349cc55cSDimitry Andric     _mm_store_si128(&vdst[i], m);
121*349cc55cSDimitry Andric     _mm_store_si128(&vclk[i], m);
122*349cc55cSDimitry Andric   }
123*349cc55cSDimitry Andric #endif
124*349cc55cSDimitry Andric }
125*349cc55cSDimitry Andric 
126*349cc55cSDimitry Andric }  // namespace __tsan
127