llvm.org GIT mirror llvm / cff60c1
[tsan] two more compile-time optimizations: - don't isntrument reads from constant globals. Saves ~1.5% of instrumented instructions on CPU2006 (counting static instructions, not their execution). - don't insrument reads from vtable (which is a global constant too). Saves ~5%. I did not measure the run-time impact of this, but it is certainly non-negative. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@154444 91177308-0d34-0410-b5e6-96231b3b80d8 Kostya Serebryany 7 years ago
2 changed file(s) with 103 addition(s) and 11 deletion(s). Raw diff Collapse all Expand all
5757 size_t NumOmittedReadsBeforeWrite;
5858 size_t NumAccessesWithBadSize;
5959 size_t NumInstrumentedVtableWrites;
60 size_t NumOmittedReadsFromConstantGlobals;
61 size_t NumOmittedReadsFromVtable;
6062 };
6163
6264 /// ThreadSanitizer: instrument the code in module to find races.
7173 private:
7274 void choseInstructionsToInstrument(SmallVectorImpl &Local,
7375 SmallVectorImpl &All);
76 bool addrPointsToConstantData(Value *Addr);
7477
7578 TargetData *TD;
7679 OwningPtr BL;
144147 << "; vt " << stats.NumInstrumentedVtableWrites
145148 << "; bs " << stats.NumAccessesWithBadSize
146149 << "; rbw " << stats.NumOmittedReadsBeforeWrite
150 << "; rcg " << stats.NumOmittedReadsFromConstantGlobals
151 << "; rvt " << stats.NumOmittedReadsFromVtable
147152 << "\n";
148153 }
149154 return true;
155 }
156
157 static bool isVtableAccess(Instruction *I) {
158 if (MDNode *Tag = I->getMetadata(LLVMContext::MD_tbaa)) {
159 if (Tag->getNumOperands() < 1) return false;
160 if (MDString *Tag1 = dyn_cast(Tag->getOperand(0))) {
161 if (Tag1->getString() == "vtable pointer") return true;
162 }
163 }
164 return false;
165 }
166
167 bool ThreadSanitizer::addrPointsToConstantData(Value *Addr) {
168 // If this is a GEP, just analyze its pointer operand.
169 if (GetElementPtrInst *GEP = dyn_cast(Addr))
170 Addr = GEP->getPointerOperand();
171
172 if (GlobalVariable *GV = dyn_cast(Addr)) {
173 if (GV->isConstant()) {
174 // Reads from constant globals can not race with any writes.
175 stats.NumOmittedReadsFromConstantGlobals++;
176 return true;
177 }
178 } else if(LoadInst *L = dyn_cast(Addr)) {
179 if (isVtableAccess(L)) {
180 // Reads from a vtable pointer can not race with any writes.
181 stats.NumOmittedReadsFromVtable++;
182 return true;
183 }
184 }
185 return false;
150186 }
151187
152188 // Instrumenting some of the accesses may be proven redundant.
172208 WriteTargets.insert(Store->getPointerOperand());
173209 } else {
174210 LoadInst *Load = cast(I);
175 if (WriteTargets.count(Load->getPointerOperand())) {
211 Value *Addr = Load->getPointerOperand();
212 if (WriteTargets.count(Addr)) {
176213 // We will write to this temp, so no reason to analyze the read.
177214 stats.NumOmittedReadsBeforeWrite++;
215 continue;
216 }
217 if (addrPointsToConstantData(Addr)) {
218 // Addr points to some constant data -- it can not race with any writes.
178219 continue;
179220 }
180221 }
233274 Res = true;
234275 }
235276 return Res;
236 }
237
238 static bool isVtableAccess(Instruction *I) {
239 if (MDNode *Tag = I->getMetadata(LLVMContext::MD_tbaa)) {
240 if (Tag->getNumOperands() < 1) return false;
241 if (MDString *Tag1 = dyn_cast(Tag->getOperand(0))) {
242 if (Tag1->getString() == "vtable pointer") return true;
243 }
244 }
245 return false;
246277 }
247278
248279 bool ThreadSanitizer::instrumentLoadOrStore(Instruction *I) {
0 ; RUN: opt < %s -tsan -S | FileCheck %s
1 ; Check that tsan does not instrument reads from constant globals.
2
3 target datalayout = "e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f32:32:32-f64:64:64-v64:64:64-v128:128:128-a0:0:64-s0:64:64-f80:128:128-n8:16:32:64-S128"
4
5 @const_global = external constant i32
6 define i32 @read_from_const_global() nounwind uwtable readnone {
7 entry:
8 %0 = load i32* @const_global, align 4
9 ret i32 %0
10 }
11 ; CHECK: define i32 @read_from_const_global
12 ; CHECK-NOT: __tsan
13 ; CHECK: ret i32
14
15 @non_const_global = global i32 0, align 4
16 define i32 @read_from_non_const_global() nounwind uwtable readonly {
17 entry:
18 %0 = load i32* @non_const_global, align 4
19 ret i32 %0
20 }
21
22 ; CHECK: define i32 @read_from_non_const_global
23 ; CHECK: __tsan_read
24 ; CHECK: ret i32
25
26 @const_global_array = external constant [10 x i32]
27 define i32 @read_from_const_global_array(i32 %idx) nounwind uwtable readnone {
28 entry:
29 %idxprom = sext i32 %idx to i64
30 %arrayidx = getelementptr inbounds [10 x i32]* @const_global_array, i64 0, i64 %idxprom
31 %0 = load i32* %arrayidx, align 4
32 ret i32 %0
33 }
34
35 ; CHECK: define i32 @read_from_const_global_array
36 ; CHECK-NOT: __tsan
37 ; CHECK: ret i32
38
39 %struct.Foo = type { i32 (...)** }
40 define void @call_virtual_func(%struct.Foo* %f) uwtable {
41 entry:
42 %0 = bitcast %struct.Foo* %f to void (%struct.Foo*)***
43 %vtable = load void (%struct.Foo*)*** %0, align 8, !tbaa !3
44 %1 = load void (%struct.Foo*)** %vtable, align 8
45 call void %1(%struct.Foo* %f)
46 ret void
47 }
48
49 ; CHECK: define void @call_virtual_func
50 ; CHECK: __tsan_read
51 ; CHECK: = load
52 ; CHECK-NOT: __tsan_read
53 ; CHECK: = load
54 ; CHECK: ret void
55
56 !0 = metadata !{metadata !"int", metadata !1}
57 !1 = metadata !{metadata !"omnipotent char", metadata !2}
58 !2 = metadata !{metadata !"Simple C/C++ TBAA", null}
59 !3 = metadata !{metadata !"vtable pointer", metadata !2}
60