[ThreadSanitizer] Add fallback DebugLocation for memintrinsic calls
authorMarco Elver <elver@google.com>
Mon, 17 Jul 2023 14:58:23 +0000 (16:58 +0200)
committerMarco Elver <elver@google.com>
Mon, 17 Jul 2023 15:52:16 +0000 (17:52 +0200)
When building with debug info enabled, some load/store instructions do
not have a DebugLocation attached. When using the default IRBuilder, it
attempts to copy the DebugLocation from the insertion-point instruction.
When there's no DebugLocation, no attempt is made to add one.

Add a fallback DebugLocation with the help of InstrumentationIRBuilder for
memintrinsics. In particular, the compiler may optimize load/store without
debug info into memintrinsics, which then are missing debug info as well.

llvm/lib/Transforms/Instrumentation/ThreadSanitizer.cpp
llvm/test/Instrumentation/ThreadSanitizer/missing_dbg.ll

index f8aa379..9d24c15 100644 (file)
@@ -689,7 +689,7 @@ static ConstantInt *createOrdering(IRBuilder<> *IRB, AtomicOrdering ord) {
 // replaced back with intrinsics. If that becomes wrong at some point,
 // we will need to call e.g. __tsan_memset to avoid the intrinsics.
 bool ThreadSanitizer::instrumentMemIntrinsic(Instruction *I) {
-  IRBuilder<> IRB(I);
+  InstrumentationIRBuilder IRB(I);
   if (MemSetInst *M = dyn_cast<MemSetInst>(I)) {
     IRB.CreateCall(
         MemsetFn,
index 160856d..a9d6bcd 100644 (file)
@@ -9,9 +9,22 @@ entry:
 }
 ; CHECK-LABEL: @with_dbg
 ; CHECK-NEXT:  entry:
-; CHECK:       call void @__tsan_func_entry(ptr %0), !dbg [[DBG:![0-9]+]]
-; CHECK:       call void @__tsan_read4(ptr %a), !dbg [[DBG]]
-; CHECK:       call void @__tsan_func_exit(), !dbg [[DBG]]
+; CHECK:       call void @__tsan_func_entry(ptr %0), !dbg [[DBG1:![0-9]+]]
+; CHECK:       call void @__tsan_read4(ptr %a), !dbg [[DBG1]]
+; CHECK:       call void @__tsan_func_exit(), !dbg [[DBG1]]
+
+declare void @llvm.memcpy.p0.p0.i64(ptr nocapture, ptr nocapture, i64, i1)
+
+define void @memintrinsic(ptr nocapture %x, ptr nocapture %y) sanitize_thread !dbg !7 {
+entry:
+    tail call void @llvm.memcpy.p0.p0.i64(ptr align 4 %x, ptr align 4 %y, i64 16, i1 false)
+    ret void
+}
+; CHECK-LABEL: @memintrinsic
+; CHECK-NEXT:  entry:
+; CHECK:       call void @__tsan_func_entry(ptr %0), !dbg [[DBG2:![0-9]+]]
+; CHECK:       call ptr @__tsan_memcpy(ptr %x, ptr %y, i64 16), !dbg [[DBG2]]
+; CHECK:       call void @__tsan_func_exit(), !dbg [[DBG2]]
 
 define i32 @without_dbg(ptr %a) sanitize_thread {
 entry:
@@ -36,5 +49,7 @@ entry:
 !3 = distinct !DISubprogram(name: "foo", scope: !1, file: !1, line: 190, type: !4, scopeLine: 192, flags: DIFlagPrototyped | DIFlagAllCallsDescribed, spFlags: DISPFlagLocalToUnit | DISPFlagDefinition | DISPFlagOptimized, unit: !0)
 !4 = !DISubroutineType(types: !5)
 !5 = !{}
+!7 = distinct !DISubprogram(name: "foo", scope: !1, file: !1, line: 195, type: !4, scopeLine: 199, flags: DIFlagPrototyped | DIFlagAllCallsDescribed, spFlags: DISPFlagLocalToUnit | DISPFlagDefinition | DISPFlagOptimized, unit: !0)
 
-; CHECK:       [[DBG]] = !DILocation(line: 0, scope: !3)
+; CHECK:       [[DBG1]] = !DILocation(line: 0, scope: !3)
+; CHECK:       [[DBG2]] = !DILocation(line: 0, scope: !7)