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
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_exitinstrumentations and its accesses to
Globalare 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.