Index: include/llvm/ProfileData/InstrProf.h =================================================================== --- include/llvm/ProfileData/InstrProf.h +++ include/llvm/ProfileData/InstrProf.h @@ -235,6 +235,9 @@ InstrProfValueData ValueData[], uint32_t &ActualNumValueData, uint64_t &TotalC); +/// Checks if the provided Value is an address of the profiler counter. +bool isAddressOfProfileCounter(Value *Addr); + const std::error_category &instrprof_category(); enum class instrprof_error { Index: lib/ProfileData/InstrProf.cpp =================================================================== --- lib/ProfileData/InstrProf.cpp +++ lib/ProfileData/InstrProf.cpp @@ -14,6 +14,7 @@ #include "llvm/ProfileData/InstrProf.h" #include "llvm/ADT/StringExtras.h" +#include "llvm/ADT/Triple.h" #include "llvm/IR/Constants.h" #include "llvm/IR/Function.h" #include "llvm/IR/GlobalVariable.h" @@ -248,6 +249,25 @@ return 0; } +bool isAddressOfProfileCounter(Value *Addr) { + // If this is a GEPCE, just analyze its pointer operand. + const ConstantExpr *CE = dyn_cast(Addr); + if (CE && CE->getOpcode() == Instruction::GetElementPtr) + Addr = CE->getOperand(0); + + // Check if global the address is pointing to is in the + // PGO counters section. + if (GlobalVariable *GV = dyn_cast(Addr)) { + if (GV->hasSection()) { + Triple T = Triple(GV->getParent()->getTargetTriple()); + bool isMachO = T.isOSBinFormatMachO(); + if (getInstrProfCountersSectionName(isMachO).equals(GV->getSection())) + return false; + } + } + return true; +} + instrprof_error InstrProfValueSiteRecord::merge(InstrProfValueSiteRecord &Input, uint64_t Weight) { this->sortByTargetValues(); Index: lib/Transforms/Instrumentation/ThreadSanitizer.cpp =================================================================== --- lib/Transforms/Instrumentation/ThreadSanitizer.cpp +++ lib/Transforms/Instrumentation/ThreadSanitizer.cpp @@ -36,6 +36,7 @@ #include "llvm/IR/Metadata.h" #include "llvm/IR/Module.h" #include "llvm/IR/Type.h" +#include "llvm/ProfileData/InstrProf.h" #include "llvm/Support/CommandLine.h" #include "llvm/Support/Debug.h" #include "llvm/Support/MathExtras.h" @@ -285,10 +286,21 @@ E = Local.rend(); It != E; ++It) { Instruction *I = *It; if (StoreInst *Store = dyn_cast(I)) { - WriteTargets.insert(Store->getPointerOperand()); + Value *Addr = Store->getPointerOperand(); + if (!isAddressOfProfileCounter(Addr)) { + // We should not instrument globals from instruction profiler counters + // since they contain known races. + continue; + } + WriteTargets.insert(Addr); } else { LoadInst *Load = cast(I); Value *Addr = Load->getPointerOperand(); + if (!isAddressOfProfileCounter(Addr)) { + // We should not instrument globals from instruction profiler counters + // since they contain known races. + continue; + } if (WriteTargets.count(Addr)) { // We will write to this temp, so no reason to analyze the read. NumOmittedReadsBeforeWrite++; Index: test/Instrumentation/ThreadSanitizer/do-not-instrument-memory-access.ll =================================================================== --- /dev/null +++ test/Instrumentation/ThreadSanitizer/do-not-instrument-memory-access.ll @@ -0,0 +1,21 @@ +; This test checks that we are not instrumenting unnecessary (and unwanted) +; acesses to globals: +; - Instruction profiler counter instrumentation has known intended races. +; +; RUN: opt < %s -tsan -S | FileCheck %s + +target datalayout = "e-m:o-i64:64-f80:128-n8:16:32:64-S128" +target triple = "x86_64-apple-macosx10.9" + +@__profc_foo = private global [1 x i64] zeroinitializer, section "__DATA,__llvm_prf_cnts", align 8 + +define i32 @foo() sanitize_thread { +entry: + %pgocount = load i64, i64* getelementptr inbounds ([1 x i64], [1 x i64]* @__profc_foo, i64 0, i64 0) + %0 = add i64 %pgocount, 1 + store i64 %0, i64* getelementptr inbounds ([1 x i64], [1 x i64]* @__profc_foo, i64 0, i64 0) + ret i32 1 +} + +; CHECK-NOT: {{call void @__tsan_write}} +; CHECK: __tsan_init