[llvm] Add a pass to collect dropped variable statistics (PR #102233)

Adrian Prantl via llvm-commits llvm-commits at lists.llvm.org
Wed Oct 16 13:32:25 PDT 2024


================
@@ -0,0 +1,586 @@
+//===- unittests/IR/DroppedVariableStatsTest.cpp - TimePassesHandler tests
+//----------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/AsmParser/Parser.h"
+#include "llvm/IR/Function.h"
+#include "llvm/IR/InstIterator.h"
+#include "llvm/IR/LegacyPassManager.h"
+#include "llvm/IR/Module.h"
+#include "llvm/Pass.h"
+#include "llvm/PassRegistry.h"
+#include "llvm/Passes/StandardInstrumentations.h"
+#include "llvm/Support/SourceMgr.h"
+#include "gtest/gtest.h"
+#include <gtest/gtest.h>
+#include <llvm/ADT/SmallString.h>
+#include <llvm/IR/LLVMContext.h>
+#include <llvm/IR/Module.h>
+#include <llvm/IR/PassInstrumentation.h>
+#include <llvm/IR/PassManager.h>
+#include <llvm/IR/PassTimingInfo.h>
+#include <llvm/Support/raw_ostream.h>
+
+using namespace llvm;
+namespace llvm {
+void initializePassTest1Pass(PassRegistry &);
+
+static std::unique_ptr<Module> parseIR(LLVMContext &C, const char *IR) {
+  SMDiagnostic Err;
+  std::unique_ptr<Module> Mod = parseAssemblyString(IR, Err, C);
+  if (!Mod)
+    Err.print("AbstractCallSiteTests", errs());
+  return Mod;
+}
+} // namespace llvm
+
+namespace {
+
+// This test ensures that if a #dbg_value and an instruction that exists in the
+// same scope as that #dbg_value are both deleted as a result of an optimization
+// pass, debug information is considered not dropped.
+TEST(DroppedVariableStats, BothDeleted) {
+  PassInstrumentationCallbacks PIC;
+  PassInstrumentation PI(&PIC);
+
+  LLVMContext C;
+
+  const char *IR =
+      "; Function Attrs: mustprogress nounwind ssp uwtable(sync)\n"
+      "define noundef range(i32 -2147483647, -2147483648) i32 @_Z3fooi(i32 "
+      "noundef %x) local_unnamed_addr #0 !dbg !9 {\n"
+      "entry:\n"
+      "#dbg_value(i32 %x, !15, !DIExpression(), !16)\n"
+      "%add = add nsw i32 %x, 1, !dbg !17\n"
+      "ret i32 0\n"
+      "}\n"
+      "!llvm.dbg.cu = !{!0}\n"
+      "!llvm.module.flags = !{!2, !3, !4, !5, !6, !7}\n"
+      "!llvm.ident = !{!8}\n"
+      "!0 = distinct !DICompileUnit(language: DW_LANG_C_plus_plus_14, file: "
+      "!1, producer: \"clang version 20.0.0git "
+      "(git at github.com:llvm/llvm-project.git "
+      "baff49d3a0ef8e0848a726656ebf6e7b310e5113)\", isOptimized: true, "
+      "runtimeVersion: 0, emissionKind: FullDebug, splitDebugInlining: false, "
+      "nameTableKind: Apple, sysroot: \"/\")\n"
+      "!1 = !DIFile(filename: \"/tmp/code.cpp\", directory: "
+      "\"/Users/shubham/Development/llvm-project/build_ninja\", checksumkind: "
+      "CSK_MD5, checksum: \"719364c4b07176af8515cac6bd21008c\")\n"
+      "!2 = !{i32 7, !\"Dwarf Version\", i32 5}\n"
+      "!3 = !{i32 2, !\"Debug Info Version\", i32 3}\n"
+      "!4 = !{i32 1, !\"wchar_size\", i32 4}\n"
+      "!5 = !{i32 8, !\"PIC Level\", i32 2}\n"
+      "!6 = !{i32 7, !\"uwtable\", i32 1}\n"
+      "!7 = !{i32 7, !\"frame-pointer\", i32 1}\n"
+      "!8 = !{!\"clang version 20.0.0git (git at github.com:llvm/llvm-project.git "
+      "baff49d3a0ef8e0848a726656ebf6e7b310e5113)\"}\n"
+      "!9 = distinct !DISubprogram(name: \"foo\", linkageName: \"_Z3fooi\", "
+      "scope: !10, file: !10, line: 1, type: !11, scopeLine: 1, flags: "
+      "DIFlagPrototyped | DIFlagAllCallsDescribed, spFlags: DISPFlagDefinition "
+      "| DISPFlagOptimized, unit: !0, retainedNodes: !14)\n"
+      "!10 = !DIFile(filename: \"/tmp/code.cpp\", directory: \"\", "
+      "checksumkind: CSK_MD5, checksum: \"719364c4b07176af8515cac6bd21008c\")\n"
+      "!11 = !DISubroutineType(types: !12)\n"
+      "!12 = !{!13, !13}\n"
+      "!13 = !DIBasicType(name: \"int\", size: 32, encoding: DW_ATE_signed)\n"
+      "!14 = !{!15}\n"
+      "!15 = !DILocalVariable(name: \"x\", arg: 1, scope: !9, file: !10, line: "
+      "1, type: !13)\n"
+      "!16 = !DILocation(line: 0, scope: !9)\n"
+      "!17 = !DILocation(line: 2, column: 11, scope: !9)\n";
+
+  std::unique_ptr<llvm::Module> M = parseIR(C, IR);
+  ASSERT_TRUE(M);
+
+  DroppedVariableStats Stats(true);
+  Stats.runBeforePass("Test",
+                      llvm::Any(const_cast<const llvm::Module *>(M.get())));
+
+  // Remove instructions
+  for (auto &F : *M.get()) {
+    for (auto &I : instructions(&F)) {
+      I.dropDbgRecords();
+      I.eraseFromParent();
+      break;
+    }
+    break;
+  }
+  PreservedAnalyses PA;
+  Stats.runAfterPass("Test",
+                     llvm::Any(const_cast<const llvm::Module *>(M.get())), PA);
+  ASSERT_EQ(Stats.getPassDroppedVariables(), false);
+}
+
+} // end anonymous namespace
+
+namespace {
+
+// This test ensures that if a #dbg_value is dropped after an optimization pass,
+// but an instruction that shares the same scope as the #dbg_value still exists,
+// debug information is conisdered dropped.
+TEST(DroppedVariableStats, DbgValLost) {
+  PassInstrumentationCallbacks PIC;
+  PassInstrumentation PI(&PIC);
+
+  LLVMContext C;
+
+  const char *IR =
+      "; Function Attrs: mustprogress nounwind ssp uwtable(sync)\n"
+      "define noundef range(i32 -2147483647, -2147483648) i32 @_Z3fooi(i32 "
+      "noundef %x) local_unnamed_addr #0 !dbg !9 {\n"
+      "entry:\n"
+      "#dbg_value(i32 %x, !15, !DIExpression(), !16)\n"
+      "%add = add nsw i32 %x, 1, !dbg !17\n"
+      "ret i32 0\n"
+      "}\n"
+      "!llvm.dbg.cu = !{!0}\n"
+      "!llvm.module.flags = !{!2, !3, !4, !5, !6, !7}\n"
+      "!llvm.ident = !{!8}\n"
+      "!0 = distinct !DICompileUnit(language: DW_LANG_C_plus_plus_14, file: "
+      "!1, producer: \"clang version 20.0.0git "
+      "(git at github.com:llvm/llvm-project.git "
+      "baff49d3a0ef8e0848a726656ebf6e7b310e5113)\", isOptimized: true, "
+      "runtimeVersion: 0, emissionKind: FullDebug, splitDebugInlining: false, "
+      "nameTableKind: Apple, sysroot: \"/\")\n"
+      "!1 = !DIFile(filename: \"/tmp/code.cpp\", directory: "
+      "\"/Users/shubham/Development/llvm-project/build_ninja\", checksumkind: "
+      "CSK_MD5, checksum: \"719364c4b07176af8515cac6bd21008c\")\n"
+      "!2 = !{i32 7, !\"Dwarf Version\", i32 5}\n"
+      "!3 = !{i32 2, !\"Debug Info Version\", i32 3}\n"
+      "!4 = !{i32 1, !\"wchar_size\", i32 4}\n"
+      "!5 = !{i32 8, !\"PIC Level\", i32 2}\n"
+      "!6 = !{i32 7, !\"uwtable\", i32 1}\n"
+      "!7 = !{i32 7, !\"frame-pointer\", i32 1}\n"
+      "!8 = !{!\"clang version 20.0.0git (git at github.com:llvm/llvm-project.git "
+      "baff49d3a0ef8e0848a726656ebf6e7b310e5113)\"}\n"
+      "!9 = distinct !DISubprogram(name: \"foo\", linkageName: \"_Z3fooi\", "
+      "scope: !10, file: !10, line: 1, type: !11, scopeLine: 1, flags: "
+      "DIFlagPrototyped | DIFlagAllCallsDescribed, spFlags: DISPFlagDefinition "
+      "| DISPFlagOptimized, unit: !0, retainedNodes: !14)\n"
+      "!10 = !DIFile(filename: \"/tmp/code.cpp\", directory: \"\", "
+      "checksumkind: CSK_MD5, checksum: \"719364c4b07176af8515cac6bd21008c\")\n"
+      "!11 = !DISubroutineType(types: !12)\n"
+      "!12 = !{!13, !13}\n"
+      "!13 = !DIBasicType(name: \"int\", size: 32, encoding: DW_ATE_signed)\n"
+      "!14 = !{!15}\n"
+      "!15 = !DILocalVariable(name: \"x\", arg: 1, scope: !9, file: !10, line: "
+      "1, type: !13)\n"
+      "!16 = !DILocation(line: 0, scope: !9)\n"
+      "!17 = !DILocation(line: 2, column: 11, scope: !9)\n";
+
+  std::unique_ptr<llvm::Module> M = parseIR(C, IR);
+  ASSERT_TRUE(M);
+
+  DroppedVariableStats Stats(true);
+  Stats.runBeforePass("Test",
+                      llvm::Any(const_cast<const llvm::Module *>(M.get())));
+
+  // Remove instructions
+  for (auto &F : *M.get()) {
+    for (auto &I : instructions(&F)) {
+      I.dropDbgRecords();
+      break;
+    }
+    break;
+  }
+  PreservedAnalyses PA;
+  Stats.runAfterPass("Test",
+                     llvm::Any(const_cast<const llvm::Module *>(M.get())), PA);
+  ASSERT_EQ(Stats.getPassDroppedVariables(), true);
+}
+
+// This test ensures that if a #dbg_value is dropped after an optimization pass,
+// but an instruction that has an unrelated scope as the #dbg_value still
+// exists, debug information is conisdered not dropped.
+TEST(DroppedVariableStats, UnrelatedScopes) {
+  PassInstrumentationCallbacks PIC;
+  PassInstrumentation PI(&PIC);
+
+  LLVMContext C;
+
+  const char *IR =
+      "; Function Attrs: mustprogress nounwind ssp uwtable(sync)\n"
+      "define noundef range(i32 -2147483647, -2147483648) i32 @_Z3fooi(i32 "
+      "noundef %x) local_unnamed_addr #0 !dbg !9 {\n"
+      "entry:\n"
+      "#dbg_value(i32 %x, !15, !DIExpression(), !16)\n"
+      "%add = add nsw i32 %x, 1, !dbg !17\n"
+      "ret i32 0\n"
+      "}\n"
+      "!llvm.dbg.cu = !{!0}\n"
+      "!llvm.module.flags = !{!2, !3, !4, !5, !6, !7}\n"
+      "!llvm.ident = !{!8}\n"
+      "!0 = distinct !DICompileUnit(language: DW_LANG_C_plus_plus_14, file: "
+      "!1, producer: \"clang version 20.0.0git "
+      "(git at github.com:llvm/llvm-project.git "
+      "baff49d3a0ef8e0848a726656ebf6e7b310e5113)\", isOptimized: true, "
+      "runtimeVersion: 0, emissionKind: FullDebug, splitDebugInlining: false, "
+      "nameTableKind: Apple, sysroot: \"/\")\n"
+      "!1 = !DIFile(filename: \"/tmp/code.cpp\", directory: "
+      "\"/Users/shubham/Development/llvm-project/build_ninja\", checksumkind: "
+      "CSK_MD5, checksum: \"719364c4b07176af8515cac6bd21008c\")\n"
+      "!2 = !{i32 7, !\"Dwarf Version\", i32 5}\n"
+      "!3 = !{i32 2, !\"Debug Info Version\", i32 3}\n"
+      "!4 = !{i32 1, !\"wchar_size\", i32 4}\n"
+      "!5 = !{i32 8, !\"PIC Level\", i32 2}\n"
+      "!6 = !{i32 7, !\"uwtable\", i32 1}\n"
+      "!7 = !{i32 7, !\"frame-pointer\", i32 1}\n"
+      "!8 = !{!\"clang version 20.0.0git (git at github.com:llvm/llvm-project.git "
+      "baff49d3a0ef8e0848a726656ebf6e7b310e5113)\"}\n"
+      "!9 = distinct !DISubprogram(name: \"foo\", linkageName: \"_Z3fooi\", "
+      "scope: !10, file: !10, line: 1, type: !11, scopeLine: 1, flags: "
+      "DIFlagPrototyped | DIFlagAllCallsDescribed, spFlags: DISPFlagDefinition "
+      "| DISPFlagOptimized, unit: !0, retainedNodes: !14)\n"
+      "!10 = !DIFile(filename: \"/tmp/code.cpp\", directory: \"\", "
+      "checksumkind: CSK_MD5, checksum: \"719364c4b07176af8515cac6bd21008c\")\n"
+      "!11 = !DISubroutineType(types: !12)\n"
+      "!12 = !{!13, !13}\n"
+      "!13 = !DIBasicType(name: \"int\", size: 32, encoding: DW_ATE_signed)\n"
+      "!14 = !{!15}\n"
+      "!15 = !DILocalVariable(name: \"x\", arg: 1, scope: !9, file: !10, line: "
+      "1, type: !13)\n"
+      "!16 = !DILocation(line: 0, scope: !9)\n"
+      "!17 = !DILocation(line: 2, column: 11, scope: !18)\n"
+      "!18 = distinct !DISubprogram(name: \"bar\", linkageName: \"_Z3bari\", "
+      "scope: !10, file: !10, line: 11, type: !11, scopeLine: 1, flags: "
+      "DIFlagPrototyped | DIFlagAllCallsDescribed, spFlags: DISPFlagDefinition "
+      "| DISPFlagOptimized, unit: !0, retainedNodes: !14)\n";
+
+  std::unique_ptr<llvm::Module> M = parseIR(C, IR);
+  ASSERT_TRUE(M);
+
+  DroppedVariableStats Stats(true);
+  Stats.runBeforePass("Test",
+                      llvm::Any(const_cast<const llvm::Module *>(M.get())));
+
+  // Remove instructions
+  for (auto &F : *M.get()) {
+    for (auto &I : instructions(&F)) {
+      I.dropDbgRecords();
+      break;
+    }
+    break;
+  }
+  PreservedAnalyses PA;
+  Stats.runAfterPass("Test",
+                     llvm::Any(const_cast<const llvm::Module *>(M.get())), PA);
+  ASSERT_EQ(Stats.getPassDroppedVariables(), false);
+}
+
+// This test ensures that if a #dbg_value is dropped after an optimization pass,
+// but an instruction that has a scope which is a child of the #dbg_value scope
+// still exists, debug information is conisdered dropped.
+TEST(DroppedVariableStats, ChildScopes) {
+  PassInstrumentationCallbacks PIC;
+  PassInstrumentation PI(&PIC);
+
+  LLVMContext C;
+
+  const char *IR =
+      "; Function Attrs: mustprogress nounwind ssp uwtable(sync)\n"
+      "define noundef range(i32 -2147483647, -2147483648) i32 @_Z3fooi(i32 "
+      "noundef %x) local_unnamed_addr #0 !dbg !9 {\n"
+      "entry:\n"
+      "#dbg_value(i32 %x, !15, !DIExpression(), !16)\n"
+      "%add = add nsw i32 %x, 1, !dbg !17\n"
+      "ret i32 0\n"
+      "}\n"
+      "!llvm.dbg.cu = !{!0}\n"
+      "!llvm.module.flags = !{!2, !3, !4, !5, !6, !7}\n"
+      "!llvm.ident = !{!8}\n"
+      "!0 = distinct !DICompileUnit(language: DW_LANG_C_plus_plus_14, file: "
+      "!1, producer: \"clang version 20.0.0git "
+      "(git at github.com:llvm/llvm-project.git "
+      "baff49d3a0ef8e0848a726656ebf6e7b310e5113)\", isOptimized: true, "
+      "runtimeVersion: 0, emissionKind: FullDebug, splitDebugInlining: false, "
+      "nameTableKind: Apple, sysroot: \"/\")\n"
+      "!1 = !DIFile(filename: \"/tmp/code.cpp\", directory: "
+      "\"/Users/shubham/Development/llvm-project/build_ninja\", checksumkind: "
+      "CSK_MD5, checksum: \"719364c4b07176af8515cac6bd21008c\")\n"
+      "!2 = !{i32 7, !\"Dwarf Version\", i32 5}\n"
+      "!3 = !{i32 2, !\"Debug Info Version\", i32 3}\n"
+      "!4 = !{i32 1, !\"wchar_size\", i32 4}\n"
+      "!5 = !{i32 8, !\"PIC Level\", i32 2}\n"
+      "!6 = !{i32 7, !\"uwtable\", i32 1}\n"
+      "!7 = !{i32 7, !\"frame-pointer\", i32 1}\n"
+      "!8 = !{!\"clang version 20.0.0git (git at github.com:llvm/llvm-project.git "
+      "baff49d3a0ef8e0848a726656ebf6e7b310e5113)\"}\n"
+      "!9 = distinct !DISubprogram(name: \"foo\", linkageName: \"_Z3fooi\", "
+      "scope: !10, file: !10, line: 1, type: !11, scopeLine: 1, flags: "
+      "DIFlagPrototyped | DIFlagAllCallsDescribed, spFlags: DISPFlagDefinition "
+      "| DISPFlagOptimized, unit: !0, retainedNodes: !14)\n"
+      "!10 = !DIFile(filename: \"/tmp/code.cpp\", directory: \"\", "
+      "checksumkind: CSK_MD5, checksum: \"719364c4b07176af8515cac6bd21008c\")\n"
+      "!11 = !DISubroutineType(types: !12)\n"
+      "!12 = !{!13, !13}\n"
+      "!13 = !DIBasicType(name: \"int\", size: 32, encoding: DW_ATE_signed)\n"
+      "!14 = !{!15}\n"
+      "!15 = !DILocalVariable(name: \"x\", arg: 1, scope: !9, file: !10, line: "
+      "1, type: !13)\n"
+      "!16 = !DILocation(line: 0, scope: !9)\n"
+      "!17 = !DILocation(line: 2, column: 11, scope: !18)\n"
+      "!18 = distinct !DILexicalBlock(scope: !9, file: !10, line: 10, column: "
+      "28)\n";
+
+  std::unique_ptr<llvm::Module> M = parseIR(C, IR);
+  ASSERT_TRUE(M);
+
+  DroppedVariableStats Stats(true);
+  Stats.runBeforePass("Test",
+                      llvm::Any(const_cast<const llvm::Module *>(M.get())));
+
+  // Remove instructions
----------------
adrian-prantl wrote:

Maybe spell out that this is the "pass" that is being checked.

https://github.com/llvm/llvm-project/pull/102233


More information about the llvm-commits mailing list