My goal is to instrument my initial IR with proper calls to TSan runtime library functions using LLVM opt and TSan passes. In other words, I want to end up with similar TSan instrumentation as when using clang -fsanitize=thread -S -emit-llvm
but by directly using opt and TSan passes instead.
As far as I know, LLVM has two passes for TSan instrumentation: tsan-module
(a module pass) and tsan
(a function pass). Both passes seem to be available by default in opt, i.e. are included in opt -print-passes
report.
I choose tiny_race.c as my sample program, where the main
thread and the thread it spawns (Thread1
) form a data race while accessing a global variable Global
.
Here are the two steps I take to instrument the code my way:
-
Generating the initial LLVM IR for tiny_race.c:
clang -S -emit-llvm tiny_race.c -o tiny_race.ll -
Using LLVM opt to instrument tiny_race.ll with the two TSan passes:
opt -passes=‘tsan-module,tsan’ tiny_race.ll -S -o myInstrumented.ll
The above pass pipeline executes fine but the resulting myInstrumented.ll
lacks most TSan instrumentations. More specifically:
-
Thread1 (child thread) is left completely un-instrumented.
-
main thread only has
@__tsan_func_entry
and@__tsan_func_exit
instrumentations and its accesses toGlobal
are not instrumented.
It might be interesting to mention that my output IR does contain TSan function declarations as expected.
I am using LLVM 16 and I have not modified the two mentioned TSan passes.
Does anyone know why my approach produces a partially-instrumented IR? Am I supposed to use some other passes alongside the two TSan passes I mentioned? Any suggestion is greatly appreciated.