Skip to content

[TSan] Add instrumentation of AVX2 and AVX512 instructions #74636

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 26 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 3 commits
Commits
Show all changes
26 commits
Select commit Hold shift + click to select a range
5091125
Add simd support to tsan
felilxtomski Nov 29, 2023
e543457
Revert unwanted changes
felilxtomski Dec 6, 2023
0415d2c
Fix format
felilxtomski Dec 6, 2023
893b94f
Cleanup
felilxtomski Dec 7, 2023
1f9ad09
Fix extraction intrinsics in tsan avx512 runtime
felilxtomski Dec 7, 2023
f6368e4
Adapt tsan simd tests to use specific vectorization flags for building
felilxtomski Dec 7, 2023
80554ae
Fix lit config format
felilxtomski Dec 7, 2023
5ce165c
First draft of Instrumentation test
jprotze Dec 7, 2023
fea56d7
Require vectorization support for tsan masked simd tests
felilxtomski Dec 7, 2023
bfa17f8
Add check lines to tsan avx loadstore instrumentation test
felilxtomski Dec 7, 2023
78dbd65
Fix gather & scatter tsan instrumentation function signatures
felilxtomski Dec 8, 2023
420a350
Add test for tsan gather & scatter instrumentation
felilxtomski Dec 8, 2023
f5e62a2
Fix avx2 instrumentation using i8 instead of i4 for bitcast mask
felilxtomski Dec 12, 2023
9702a23
Split TSan avx instrumentation tests in avx2 and avx512 testcases
felilxtomski Dec 12, 2023
e21da01
Remove unused typedefs
felilxtomski Dec 12, 2023
a8891dc
Remove unnecessary casting in tsan avx runtime
felilxtomski Dec 12, 2023
26cd861
Determine intrinsic type via intrinsic id
felilxtomski Dec 12, 2023
d34a62a
Simplify tsan instrumentation access size check
felilxtomski Dec 12, 2023
08ffa12
Fix format
felilxtomski Dec 12, 2023
4770219
Always build tsan avx rtl components with avx flags
felilxtomski Dec 13, 2023
d372015
Fix guard for avx2 tsan rtl component
felilxtomski Dec 13, 2023
fcec776
Check target avx attributes for gather & scatter tsan instrumentation
felilxtomski Dec 13, 2023
dc846ed
Adapt tsan avx instrumentation tests to function attributes
felilxtomski Dec 13, 2023
d1fabd6
Make tsan avx instrumentation checks more robust
felilxtomski Dec 14, 2023
12b0fe9
Add builtin cmake check for host cpu features
felilxtomski Dec 14, 2023
9b970b3
Use host cpu feature check in tsan lit checks
felilxtomski Dec 14, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions compiler-rt/cmake/config-ix.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,8 @@ check_cxx_compiler_flag(-fno-profile-instr-use COMPILER_RT_HAS_FNO_PROFILE_INSTR
check_cxx_compiler_flag(-fno-coverage-mapping COMPILER_RT_HAS_FNO_COVERAGE_MAPPING_FLAG)
check_cxx_compiler_flag("-Werror -mcrc32" COMPILER_RT_HAS_MCRC32_FLAG)
check_cxx_compiler_flag("-Werror -msse4.2" COMPILER_RT_HAS_MSSE4_2_FLAG)
check_cxx_compiler_flag("-Werror -mavx2" COMPILER_RT_HAS_MAVX2_FLAG)
check_cxx_compiler_flag("-Werror -mavx512f" COMPILER_RT_HAS_MAVX512F_FLAG)
check_cxx_compiler_flag(--sysroot=. COMPILER_RT_HAS_SYSROOT_FLAG)
check_cxx_compiler_flag("-Werror -mcrc" COMPILER_RT_HAS_MCRC_FLAG)
check_cxx_compiler_flag(-fno-partial-inlining COMPILER_RT_HAS_FNO_PARTIAL_INLINING_FLAG)
Expand Down
15 changes: 15 additions & 0 deletions compiler-rt/lib/tsan/rtl/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -241,6 +241,17 @@ else()
else()
set(TSAN_ASM_SOURCES)
endif()
add_compiler_rt_object_libraries(RTTSanAVX2
ARCHS ${arch}
SOURCES tsan_interface_avx2.cpp
ADDITIONAL_HEADERS tsan_interface_avx2.h
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Don't we want to export this header always?
The compiler is not necessary used on the machine where the it's built.
If we include it unconditionally, it will also make cmake files simpler.

#CFLAGS ${TSAN_RTL_CFLAGS} $<IF:"$COMPILER_RT_HAS_MAVX2_FLAG","-mavx2","">)
CFLAGS ${TSAN_RTL_CFLAGS} $<IF:$<BOOL:${COMPILER_RT_HAS_MAVX2_FLAG}>,-mavx2,"">)
add_compiler_rt_object_libraries(RTTSanAVX512
ARCHS ${arch}
SOURCES tsan_interface_avx512.cpp
ADDITIONAL_HEADERS tsan_interface_avx512.h
CFLAGS ${TSAN_RTL_CFLAGS} $<IF:$<BOOL:${COMPILER_RT_HAS_MAVX512F_FLAG}>,-mavx512f,"">)
add_compiler_rt_runtime(clang_rt.tsan
STATIC
ARCHS ${arch}
Expand All @@ -252,6 +263,8 @@ else()
$<TARGET_OBJECTS:RTSanitizerCommonSymbolizer.${arch}>
$<TARGET_OBJECTS:RTSanitizerCommonSymbolizerInternal.${arch}>
$<TARGET_OBJECTS:RTUbsan.${arch}>
$<TARGET_OBJECTS:RTTSanAVX2.${arch}>
$<TARGET_OBJECTS:RTTSanAVX512.${arch}>
ADDITIONAL_HEADERS ${TSAN_HEADERS}
CFLAGS ${TSAN_RTL_CFLAGS}
PARENT_TARGET tsan)
Expand All @@ -276,6 +289,8 @@ else()
$<TARGET_OBJECTS:RTSanitizerCommonSymbolizer.${arch}>
$<TARGET_OBJECTS:RTSanitizerCommonSymbolizerInternal.${arch}>
$<TARGET_OBJECTS:RTUbsan.${arch}>
$<TARGET_OBJECTS:RTTSanAVX2.${arch}>
$<TARGET_OBJECTS:RTTSanAVX512.${arch}>
ADDITIONAL_HEADERS ${TSAN_HEADERS}
CFLAGS ${TSAN_RTL_DYNAMIC_CFLAGS}
DEFS SANITIZER_SHARED
Expand Down
41 changes: 33 additions & 8 deletions compiler-rt/lib/tsan/rtl/tsan_interface.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -11,10 +11,11 @@
//===----------------------------------------------------------------------===//

#include "tsan_interface.h"
#include "tsan_interface_ann.h"
#include "tsan_rtl.h"

#include "sanitizer_common/sanitizer_internal_defs.h"
#include "sanitizer_common/sanitizer_ptrauth.h"
#include "tsan_interface_ann.h"
#include "tsan_rtl.h"

#define CALLERPC ((uptr)__builtin_return_address(0))

Expand Down Expand Up @@ -42,18 +43,42 @@ void __tsan_write16_pc(void *addr, void *pc) {

// __tsan_unaligned_read/write calls are emitted by compiler.

void __tsan_unaligned_read16(const void *addr) {
template <unsigned int N>
void __tsan_unaligned_readx(const void *addr) {
uptr pc = CALLERPC;
ThreadState *thr = cur_thread();
UnalignedMemoryAccess(thr, pc, (uptr)addr, 8, kAccessRead);
UnalignedMemoryAccess(thr, pc, (uptr)addr + 8, 8, kAccessRead);
for (unsigned int i = 0; i < N / 8; i++)
UnalignedMemoryAccess(thr, pc, (uptr)addr + (i * 8), 8, kAccessRead);
}

void __tsan_unaligned_write16(void *addr) {
template <unsigned int N>
void __tsan_unaligned_writex(void *addr) {
uptr pc = CALLERPC;
ThreadState *thr = cur_thread();
UnalignedMemoryAccess(thr, pc, (uptr)addr, 8, kAccessWrite);
UnalignedMemoryAccess(thr, pc, (uptr)addr + 8, 8, kAccessWrite);
for (unsigned int i = 0; i < N / 8; i++)
UnalignedMemoryAccess(thr, pc, (uptr)addr + (i * 8), 8, kAccessWrite);
}

void __tsan_unaligned_read16(const void *addr) {
__tsan_unaligned_readx<16>(addr);
}

void __tsan_unaligned_write16(void *addr) { __tsan_unaligned_writex<16>(addr); }

extern "C" void __tsan_unaligned_read32(const void *addr) {
__tsan_unaligned_readx<32>(addr);
}

extern "C" void __tsan_unaligned_write32(void *addr) {
__tsan_unaligned_writex<32>(addr);
}

extern "C" void __tsan_unaligned_read64(const void *addr) {
__tsan_unaligned_readx<64>(addr);
}

extern "C" void __tsan_unaligned_write64(void *addr) {
__tsan_unaligned_writex<64>(addr);
}

extern "C" {
Expand Down
4 changes: 4 additions & 0 deletions compiler-rt/lib/tsan/rtl/tsan_interface.h
Original file line number Diff line number Diff line change
Expand Up @@ -53,11 +53,15 @@ SANITIZER_INTERFACE_ATTRIBUTE void __tsan_unaligned_read2(const void *addr);
SANITIZER_INTERFACE_ATTRIBUTE void __tsan_unaligned_read4(const void *addr);
SANITIZER_INTERFACE_ATTRIBUTE void __tsan_unaligned_read8(const void *addr);
SANITIZER_INTERFACE_ATTRIBUTE void __tsan_unaligned_read16(const void *addr);
SANITIZER_INTERFACE_ATTRIBUTE void __tsan_unaligned_read32(const void *addr);
SANITIZER_INTERFACE_ATTRIBUTE void __tsan_unaligned_read64(const void *addr);

SANITIZER_INTERFACE_ATTRIBUTE void __tsan_unaligned_write2(void *addr);
SANITIZER_INTERFACE_ATTRIBUTE void __tsan_unaligned_write4(void *addr);
SANITIZER_INTERFACE_ATTRIBUTE void __tsan_unaligned_write8(void *addr);
SANITIZER_INTERFACE_ATTRIBUTE void __tsan_unaligned_write16(void *addr);
SANITIZER_INTERFACE_ATTRIBUTE void __tsan_unaligned_write32(void *addr);
SANITIZER_INTERFACE_ATTRIBUTE void __tsan_unaligned_write64(void *addr);

SANITIZER_INTERFACE_ATTRIBUTE void __tsan_read1_pc(void *addr, void *pc);
SANITIZER_INTERFACE_ATTRIBUTE void __tsan_read2_pc(void *addr, void *pc);
Expand Down
27 changes: 27 additions & 0 deletions compiler-rt/lib/tsan/rtl/tsan_interface.inc
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,18 @@ void __tsan_read16(void *addr) {
MemoryAccess16(cur_thread(), CALLERPC, (uptr)addr, kAccessRead);
}

extern "C" void __tsan_read32(void *addr) {
MemoryAccess16(cur_thread(), CALLERPC, (uptr)addr, kAccessRead);
MemoryAccess16(cur_thread(), CALLERPC, (uptr)addr + 16, kAccessRead);
}

extern "C" void __tsan_read64(void *addr) {
MemoryAccess16(cur_thread(), CALLERPC, (uptr)addr, kAccessRead);
MemoryAccess16(cur_thread(), CALLERPC, (uptr)addr + 16, kAccessRead);
MemoryAccess16(cur_thread(), CALLERPC, (uptr)addr + 32, kAccessRead);
MemoryAccess16(cur_thread(), CALLERPC, (uptr)addr + 48, kAccessRead);
}

void __tsan_write1(void *addr) {
MemoryAccess(cur_thread(), CALLERPC, (uptr)addr, 1, kAccessWrite);
}
Expand All @@ -58,6 +70,21 @@ void __tsan_write16(void *addr) {
MemoryAccess16(cur_thread(), CALLERPC, (uptr)addr, kAccessWrite);
}

extern "C" void __tsan_write32(void *addr) {
MemoryAccess16(cur_thread(), CALLERPC, (uptr)addr, kAccessWrite);
MemoryAccess16(cur_thread(), CALLERPC, (uptr)addr + 16, kAccessWrite);
}

extern "C" void __tsan_write64(void *addr) {
MemoryAccess16(cur_thread(), CALLERPC, (uptr)addr, kAccessWrite);
MemoryAccess16(cur_thread(), CALLERPC, (uptr)addr + 16, kAccessWrite);
MemoryAccess16(cur_thread(), CALLERPC, (uptr)addr + 32, kAccessWrite);
MemoryAccess16(cur_thread(), CALLERPC, (uptr)addr + 48, kAccessWrite);
}

// Our vector instructions
// TODO

void __tsan_read1_pc(void *addr, void *pc) {
MemoryAccess(cur_thread(), STRIP_PAC_PC(pc), (uptr)addr, 1, kAccessRead | kAccessExternalPC);
}
Expand Down
37 changes: 37 additions & 0 deletions compiler-rt/lib/tsan/rtl/tsan_interface_avx2.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
#include "tsan_interface_avx2.h"

#include <immintrin.h>
#include <inttypes.h>
#include <stdint.h>
#include <unistd.h>

#include "sanitizer_common/sanitizer_internal_defs.h"
#include "sanitizer_common/sanitizer_ptrauth.h"
#include "tsan_interface_ann.h"
#include "tsan_rtl.h"

#define CALLERPC ((uptr)__builtin_return_address(0))

using namespace __tsan;

#ifdef __AVX__
extern "C" void __tsan_scatter_vector4(__m256i vaddr, int size, uint8_t mask) {
void *addr[4] = {};
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We always cast it to something else and never use it as 'void*', so I would do s/void*/uptr/ to remove at least 1 cast.
Here and below.

_mm256_store_si256((__m256i *)addr, vaddr);
uptr pc = CALLERPC;
ThreadState *thr = cur_thread();
for (int i = 0; i < 4; i++)
if ((mask >> i) & 1)
UnalignedMemoryAccess(thr, pc, (uptr)addr[i], size, kAccessWrite);
}

extern "C" void __tsan_gather_vector4(__m256i vaddr, int size, uint8_t mask) {
void *addr[4] = {};
_mm256_store_si256((__m256i *)addr, vaddr);
uptr pc = CALLERPC;
ThreadState *thr = cur_thread();
for (int i = 0; i < 4; i++)
if ((mask >> i) & 1)
UnalignedMemoryAccess(thr, pc, (uptr)addr[i], size, kAccessRead);
}
#endif /*__AVX__*/
46 changes: 46 additions & 0 deletions compiler-rt/lib/tsan/rtl/tsan_interface_avx2.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
//===-- tsan_interface_avx2.h ------------------------------------- C++ -*-===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
//
// This file is a part of ThreadSanitizer (TSan), a race detector.
//
// The functions declared in this header will be inserted by the instrumentation
// module.
// This header can be included by the instrumented program or by TSan tests.
//===----------------------------------------------------------------------===//
#ifndef TSAN_INTERFACE_AVX2_H
#define TSAN_INTERFACE_AVX2_H

#include <immintrin.h>
#include <sanitizer_common/sanitizer_internal_defs.h>
#include <stdint.h>
using __sanitizer::tid_t;
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This does not seem to be used.

using __sanitizer::uptr;
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This does not seem to be used.


// This header should NOT include any other headers.
// All functions in this header are extern "C" and start with __tsan_.

#ifdef __cplusplus
extern "C" {
#endif

#if !SANITIZER_GO
# ifdef __AVX__
SANITIZER_INTERFACE_ATTRIBUTE void __tsan_scatter_vector4(__m256i vaddr,
int width,
uint8_t mask);
SANITIZER_INTERFACE_ATTRIBUTE void __tsan_gather_vector4(__m256i vaddr,
int width,
uint8_t mask);
# endif /*__AVX__*/
#endif // SANITIZER_GO

#ifdef __cplusplus
} // extern "C"
#endif

#endif /*TSAN_INTERFACE_AVX2_H*/
43 changes: 43 additions & 0 deletions compiler-rt/lib/tsan/rtl/tsan_interface_avx512.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
#include "tsan_interface_avx512.h"

#include <immintrin.h>
#include <inttypes.h>
#include <stdint.h>
#include <unistd.h>

#include "sanitizer_common/sanitizer_internal_defs.h"
#include "sanitizer_common/sanitizer_ptrauth.h"
#include "tsan_interface_ann.h"
#include "tsan_rtl.h"

#define CALLERPC ((uptr)__builtin_return_address(0))

using namespace __tsan;

#ifdef __AVX512F__
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Won't it be better to always compile this file with -mavx512f?

extern "C" void __tsan_scatter_vector8(__m512i vaddr, int size, uint8_t mask) {
void *addr[8] = {};
__m256i v256_1 = _mm512_extracti64x4_epi64(vaddr, 0);
__m256i v256_2 = _mm512_extracti64x4_epi64(vaddr, 4);
_mm256_store_si256((__m256i *)addr, v256_1);
_mm256_store_si256((__m256i *)&(addr[4]), v256_2);
uptr pc = CALLERPC;
ThreadState *thr = cur_thread();
for (int i = 0; i < 8; i++)
if ((mask >> i) & 1)
UnalignedMemoryAccess(thr, pc, (uptr)addr[i], size, kAccessWrite);
}

extern "C" void __tsan_gather_vector8(__m512i vaddr, int size, uint8_t mask) {
void *addr[8] = {};
__m256i v256_1 = _mm512_extracti64x4_epi64(vaddr, 0);
__m256i v256_2 = _mm512_extracti64x4_epi64(vaddr, 4);
_mm256_store_si256((__m256i *)addr, v256_1);
_mm256_store_si256((__m256i *)(&addr[4]), v256_2);
uptr pc = CALLERPC;
ThreadState *thr = cur_thread();
for (int i = 0; i < 8; i++)
if ((mask >> i) & 1)
UnalignedMemoryAccess(thr, pc, (uptr)addr[i], size, kAccessRead);
}
#endif /*__AVX512F__*/
46 changes: 46 additions & 0 deletions compiler-rt/lib/tsan/rtl/tsan_interface_avx512.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
//===-- tsan_interface_avx512.h ----------------------------------- C++ -*-===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
//
// This file is a part of ThreadSanitizer (TSan), a race detector.
//
// The functions declared in this header will be inserted by the instrumentation
// module.
// This header can be included by the instrumented program or by TSan tests.
//===----------------------------------------------------------------------===//
#ifndef TSAN_INTERFACE_AVX512_H
#define TSAN_INTERFACE_AVX512_H

#include <immintrin.h>
#include <sanitizer_common/sanitizer_internal_defs.h>
#include <stdint.h>
using __sanitizer::tid_t;
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This does not seem to be used.

using __sanitizer::uptr;
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This does not seem to be used.


// This header should NOT include any other headers.
// All functions in this header are extern "C" and start with __tsan_.

#ifdef __cplusplus
extern "C" {
#endif

#if !SANITIZER_GO
# ifdef __AVX512F__
SANITIZER_INTERFACE_ATTRIBUTE void __tsan_scatter_vector8(__m512i vaddr,
int width,
uint8_t mask);
SANITIZER_INTERFACE_ATTRIBUTE void __tsan_gather_vector8(__m512i vaddr,
int width,
uint8_t mask);
# endif /*__AVX512F__*/
#endif // SANITIZER_GO

#ifdef __cplusplus
} // extern "C"
#endif

#endif /*TSAN_INTERFACE_AVX512_H*/
45 changes: 45 additions & 0 deletions compiler-rt/test/tsan/simd_broadcast_norace.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
// RUN: %clang_tsan -DSIMDLEN=4 -DTYPE=float -O3 -march=native -fopenmp-simd %s -o %t && %run %t 2>&1 | FileCheck %s
// RUN: %clang_tsan -DSIMDLEN=4 -DTYPE=double -O3 -march=native -fopenmp-simd %s -o %t && %run %t 2>&1 | FileCheck %s
// RUN: %clang_tsan -DSIMDLEN=8 -DTYPE=float -O3 -march=native -fopenmp-simd %s -o %t && %run %t 2>&1 | FileCheck %s
// RUN: %clang_tsan -DSIMDLEN=8 -DTYPE=double -O3 -march=native -fopenmp-simd %s -o %t && %run %t 2>&1 | FileCheck %s
#include "test.h"

#ifndef SIMDLEN
# define SIMDLEN 8
#endif /*SIMDLEN*/
#ifndef TYPE
# define TYPE double
#endif /*TYPE*/
#define LEN 256
#define CHUNK_SIZE 64

TYPE A[2 * LEN];
TYPE c;

void *Thread(intptr_t offset) {
for (intptr_t i = offset; i < LEN; i += (2 * CHUNK_SIZE)) {
#pragma omp simd simdlen(SIMDLEN)
for (intptr_t j = i; j < i + CHUNK_SIZE; j++)
A[j] += c;
}
barrier_wait(&barrier);
return NULL;
}

void *Thread1(void *x) { return Thread(0); }

void *Thread2(void *x) { return Thread(CHUNK_SIZE); }

int main() {
barrier_init(&barrier, 2);
pthread_t t[2];
pthread_create(&t[0], NULL, Thread1, NULL);
pthread_create(&t[1], NULL, Thread2, NULL);
pthread_join(t[0], NULL);
pthread_join(t[1], NULL);
fprintf(stderr, "DONE\n");
return 0;
}

// CHECK-NOT: WARNING: ThreadSanitizer: data race
// CHECK-NOT: SUMMARY: ThreadSanitizer: data race{{.*}}Thread
Loading