[llvm] [IR] Filter dumps by source location (PR #203393)
Yaxun Liu via llvm-commits
llvm-commits at lists.llvm.org
Thu Jun 11 13:48:34 PDT 2026
https://github.com/yxsamliu created https://github.com/llvm/llvm-project/pull/203393
[IR] Filter dumps by source location
Large dumps from `-print-after-all` can be hard to use when only a few source lines matter. Function filtering can still print too much and can miss code after inlining.
Add `-filter-print-source-locs` to limit dumps to IR or machine code with matching debug locations. The option accepts selected lines and ranges, and works with legacy and new print paths.
>From 3b4ba261fa51b49eb18175354700753e9b906fc5 Mon Sep 17 00:00:00 2001
From: "Yaxun (Sam) Liu" <yaxun.liu at amd.com>
Date: Wed, 10 Jun 2026 21:49:36 -0400
Subject: [PATCH] [IR] Filter dumps by source location
Large dumps from `-print-after-all` can be hard to use when only a few source lines matter. Function filtering can still print too much and can miss code after inlining.
Add `-filter-print-source-locs` to limit dumps to IR or machine code with matching debug locations. The option accepts selected lines and ranges, and works with legacy and new print paths.
---
llvm/include/llvm/IR/PrintPasses.h | 12 ++
llvm/lib/Analysis/CallGraphSCCPass.cpp | 7 +-
llvm/lib/Analysis/LoopPass.cpp | 20 +-
llvm/lib/Analysis/RegionPass.cpp | 17 +-
.../CodeGen/MachineFunctionPrinterPass.cpp | 16 +-
llvm/lib/IR/IRPrintingPasses.cpp | 6 +-
llvm/lib/IR/PrintPasses.cpp | 185 ++++++++++++++++--
llvm/lib/IRPrinter/IRPrintingPasses.cpp | 6 +-
llvm/lib/Passes/StandardInstrumentations.cpp | 90 +++++----
.../CodeGen/X86/source-loc-print-filter.ll | 49 +++++
llvm/test/Other/source-loc-print-filter.ll | 97 +++++++++
11 files changed, 444 insertions(+), 61 deletions(-)
create mode 100644 llvm/test/CodeGen/X86/source-loc-print-filter.ll
create mode 100644 llvm/test/Other/source-loc-print-filter.ll
diff --git a/llvm/include/llvm/IR/PrintPasses.h b/llvm/include/llvm/IR/PrintPasses.h
index 0aa1b379c35cf..c5c3b43871467 100644
--- a/llvm/include/llvm/IR/PrintPasses.h
+++ b/llvm/include/llvm/IR/PrintPasses.h
@@ -15,6 +15,9 @@
namespace llvm {
+class DebugLoc;
+class Function;
+
enum class ChangePrinter {
None,
Verbose,
@@ -61,6 +64,15 @@ bool isFilterPassesEmpty();
// Returns true if we should print the function.
bool isFunctionInPrintList(StringRef FunctionName);
+// Returns true if -filter-print-source-locs is empty or contains the source
+// location.
+bool isSourceLocInPrintList(const DebugLoc &Loc);
+bool isSourceLocFilterEmpty();
+
+// Returns true if the function passes the function-name and source-location
+// print filters.
+bool shouldPrintFunction(const Function &F);
+
// Ensure temporary files exist, creating or re-using them. \p FD contains
// file descriptors (-1 indicates that the file should be created) and
// \p SR contains the corresponding initial content. \p FileName will have
diff --git a/llvm/lib/Analysis/CallGraphSCCPass.cpp b/llvm/lib/Analysis/CallGraphSCCPass.cpp
index 3fd2fe02f6688..75eb2c2e0a70d 100644
--- a/llvm/lib/Analysis/CallGraphSCCPass.cpp
+++ b/llvm/lib/Analysis/CallGraphSCCPass.cpp
@@ -683,7 +683,8 @@ namespace {
};
bool NeedModule = llvm::forcePrintModuleIR();
- if (isFunctionInPrintList("*") && NeedModule) {
+ if (isFunctionInPrintList("*") && isSourceLocFilterEmpty() &&
+ NeedModule) {
PrintBannerOnce();
OS << "\n";
SCC.getCallGraph().getModule().print(OS, nullptr);
@@ -692,14 +693,14 @@ namespace {
bool FoundFunction = false;
for (CallGraphNode *CGN : SCC) {
if (Function *F = CGN->getFunction()) {
- if (!F->isDeclaration() && isFunctionInPrintList(F->getName())) {
+ if (!F->isDeclaration() && shouldPrintFunction(*F)) {
FoundFunction = true;
if (!NeedModule) {
PrintBannerOnce();
F->print(OS);
}
}
- } else if (isFunctionInPrintList("*")) {
+ } else if (isFunctionInPrintList("*") && isSourceLocFilterEmpty()) {
PrintBannerOnce();
OS << "\nPrinting <null> Function\n";
}
diff --git a/llvm/lib/Analysis/LoopPass.cpp b/llvm/lib/Analysis/LoopPass.cpp
index 85c15c5721cd6..d6525643f9e3a 100644
--- a/llvm/lib/Analysis/LoopPass.cpp
+++ b/llvm/lib/Analysis/LoopPass.cpp
@@ -31,6 +31,21 @@ using namespace llvm;
namespace {
+bool shouldPrintLoop(const Loop &L) {
+ Function *F = L.getHeader()->getParent();
+ if (!isFunctionInPrintList(F->getName()))
+ return false;
+
+ if (isSourceLocFilterEmpty())
+ return true;
+
+ for (const BasicBlock *BB : L.blocks())
+ for (const Instruction &I : *BB)
+ if (isSourceLocInPrintList(I.getDebugLoc()))
+ return true;
+ return false;
+}
+
/// PrintLoopPass - Print a Function corresponding to a Loop.
///
class PrintLoopPassWrapper : public LoopPass {
@@ -48,11 +63,8 @@ class PrintLoopPassWrapper : public LoopPass {
}
bool runOnLoop(Loop *L, LPPassManager &) override {
- auto BBI = llvm::find_if(L->blocks(), [](BasicBlock *BB) { return BB; });
- if (BBI != L->blocks().end() &&
- isFunctionInPrintList((*BBI)->getParent()->getName())) {
+ if (shouldPrintLoop(*L))
printLoop(*L, OS, Banner);
- }
return false;
}
diff --git a/llvm/lib/Analysis/RegionPass.cpp b/llvm/lib/Analysis/RegionPass.cpp
index ae1d84659de86..63b7f8c6fc6d2 100644
--- a/llvm/lib/Analysis/RegionPass.cpp
+++ b/llvm/lib/Analysis/RegionPass.cpp
@@ -172,6 +172,21 @@ void RGPassManager::dumpPassStructure(unsigned Offset) {
}
namespace {
+bool shouldPrintRegion(const Region &R) {
+ if (!isFunctionInPrintList(R.getEntry()->getParent()->getName()))
+ return false;
+
+ if (isSourceLocFilterEmpty())
+ return true;
+
+ for (const BasicBlock *BB : R.blocks())
+ if (BB)
+ for (const Instruction &I : *BB)
+ if (isSourceLocInPrintList(I.getDebugLoc()))
+ return true;
+ return false;
+}
+
//===----------------------------------------------------------------------===//
// PrintRegionPass
class PrintRegionPass : public RegionPass {
@@ -189,7 +204,7 @@ class PrintRegionPass : public RegionPass {
}
bool runOnRegion(Region *R, RGPassManager &RGM) override {
- if (!isFunctionInPrintList(R->getEntry()->getParent()->getName()))
+ if (!shouldPrintRegion(*R))
return false;
Out << Banner;
for (const auto *BB : R->blocks()) {
diff --git a/llvm/lib/CodeGen/MachineFunctionPrinterPass.cpp b/llvm/lib/CodeGen/MachineFunctionPrinterPass.cpp
index 5111322023d04..e42f12db1aa8d 100644
--- a/llvm/lib/CodeGen/MachineFunctionPrinterPass.cpp
+++ b/llvm/lib/CodeGen/MachineFunctionPrinterPass.cpp
@@ -22,6 +22,20 @@
using namespace llvm;
namespace {
+bool shouldPrintMachineFunction(const MachineFunction &MF) {
+ if (!isFunctionInPrintList(MF.getName()))
+ return false;
+
+ if (isSourceLocFilterEmpty())
+ return true;
+
+ for (const MachineBasicBlock &MBB : MF)
+ for (const MachineInstr &MI : MBB)
+ if (isSourceLocInPrintList(MI.getDebugLoc()))
+ return true;
+ return false;
+}
+
/// MachineFunctionPrinterPass - This is a pass to dump the IR of a
/// MachineFunction.
///
@@ -44,7 +58,7 @@ struct MachineFunctionPrinterPass : public MachineFunctionPass {
}
bool runOnMachineFunction(MachineFunction &MF) override {
- if (!isFunctionInPrintList(MF.getName()))
+ if (!shouldPrintMachineFunction(MF))
return false;
OS << "# " << Banner << ":\n";
auto *SIWrapper = getAnalysisIfAvailable<SlotIndexesWrapperPass>();
diff --git a/llvm/lib/IR/IRPrintingPasses.cpp b/llvm/lib/IR/IRPrintingPasses.cpp
index 43671b0b9a1a3..d00f57a63e6c4 100644
--- a/llvm/lib/IR/IRPrintingPasses.cpp
+++ b/llvm/lib/IR/IRPrintingPasses.cpp
@@ -40,14 +40,14 @@ class PrintModulePassWrapper : public ModulePass {
ShouldPreserveUseListOrder(ShouldPreserveUseListOrder) {}
bool runOnModule(Module &M) override {
- if (llvm::isFunctionInPrintList("*")) {
+ if (llvm::isFunctionInPrintList("*") && isSourceLocFilterEmpty()) {
if (!Banner.empty())
OS << Banner << "\n";
M.print(OS, nullptr, ShouldPreserveUseListOrder);
} else {
bool BannerPrinted = false;
for (const auto &F : M.functions()) {
- if (llvm::isFunctionInPrintList(F.getName())) {
+ if (shouldPrintFunction(F)) {
if (!BannerPrinted && !Banner.empty()) {
OS << Banner << "\n";
BannerPrinted = true;
@@ -79,7 +79,7 @@ class PrintFunctionPassWrapper : public FunctionPass {
// This pass just prints a banner followed by the function as it's processed.
bool runOnFunction(Function &F) override {
- if (isFunctionInPrintList(F.getName())) {
+ if (shouldPrintFunction(F)) {
if (forcePrintModuleIR())
OS << Banner << " (function: " << F.getName() << ")\n"
<< *F.getParent();
diff --git a/llvm/lib/IR/PrintPasses.cpp b/llvm/lib/IR/PrintPasses.cpp
index 74d97d1fe5835..f3006bfee20bd 100644
--- a/llvm/lib/IR/PrintPasses.cpp
+++ b/llvm/lib/IR/PrintPasses.cpp
@@ -7,13 +7,23 @@
//===----------------------------------------------------------------------===//
#include "llvm/IR/PrintPasses.h"
+#include "llvm/ADT/SmallVector.h"
+#include "llvm/ADT/StringExtras.h"
+#include "llvm/IR/BasicBlock.h"
+#include "llvm/IR/DebugInfoMetadata.h"
+#include "llvm/IR/DebugLoc.h"
+#include "llvm/IR/Function.h"
+#include "llvm/IR/Instruction.h"
#include "llvm/Support/CommandLine.h"
#include "llvm/Support/Errc.h"
+#include "llvm/Support/ErrorHandling.h"
#include "llvm/Support/FileSystem.h"
#include "llvm/Support/IOSandbox.h"
#include "llvm/Support/MemoryBuffer.h"
+#include "llvm/Support/Path.h"
#include "llvm/Support/Program.h"
#include <unordered_set>
+#include <vector>
using namespace llvm;
@@ -41,23 +51,24 @@ static cl::opt<bool> PrintAfterAll("print-after-all",
// this option. -filter-passes will limit the output to the named passes that
// actually change the IR and other passes are reported as filtered out. The
// specified passes will either be reported as making no changes (with no IR
-// reported) or the changed IR will be reported. Also, the -filter-print-funcs
-// and -print-module-scope options will do similar filtering based on function
-// name, reporting changed IRs as functions(or modules if -print-module-scope is
-// specified) for a particular function or indicating that the IR has been
-// filtered out. The extra options can be combined, allowing only changed IRs
-// for certain passes on certain functions to be reported in different formats,
-// with the rest being reported as filtered out. The -print-before-changed
+// reported) or the changed IR will be reported. Also, the -filter-print-funcs,
+// -filter-print-source-locs and -print-module-scope options will do similar
+// filtering based on function name or source location, reporting changed IRs as
+// functions(or modules if -print-module-scope is specified) for a particular
+// function or indicating that the IR has been filtered out. The extra options
+// can be combined, allowing only changed IRs for certain passes on certain
+// functions or source locations to be reported in different formats, with the
+// rest being reported as filtered out. The -print-before-changed
// option will print the IR as it was before each pass that changed it. The
// optional value of quiet will only report when the IR changes, suppressing all
// other messages, including the initial IR. The values "diff" and "diff-quiet"
// will present the changes in a form similar to a patch, in either verbose or
// quiet mode, respectively. The lines that are removed and added are prefixed
-// with '-' and '+', respectively. The -filter-print-funcs and -filter-passes
-// can be used to filter the output. This reporter relies on the linux diff
-// utility to do comparisons and insert the prefixes. For systems that do not
-// have the necessary facilities, the error message will be shown in place of
-// the expected output.
+// with '-' and '+', respectively. The -filter-print-funcs,
+// -filter-print-source-locs and -filter-passes can be used to filter the
+// output. This reporter relies on the linux diff utility to do comparisons and
+// insert the prefixes. For systems that do not have the necessary facilities,
+// the error message will be shown in place of the expected output.
cl::opt<ChangePrinter> llvm::PrintChanged(
"print-changed", cl::desc("Print changed IRs"), cl::Hidden,
cl::ValueOptional, cl::init(ChangePrinter::None),
@@ -110,6 +121,10 @@ static cl::list<std::string>
"options"),
cl::CommaSeparated, cl::Hidden);
+static cl::list<std::string> PrintSourceLocs(
+ "filter-print-source-locs", cl::value_desc("file:line[,line-line][,line]"),
+ cl::desc("Only print IR containing matching source locations"), cl::Hidden);
+
/// This is a helper to determine whether to print IR before or
/// after a pass.
@@ -162,7 +177,151 @@ bool llvm::isFunctionInPrintList(StringRef FunctionName) {
static std::unordered_set<std::string> PrintFuncNames(PrintFuncsList.begin(),
PrintFuncsList.end());
return PrintFuncNames.empty() ||
- PrintFuncNames.count(std::string(FunctionName));
+ PrintFuncNames.count(std::string(FunctionName)) ||
+ PrintFuncNames.count("*");
+}
+
+namespace {
+
+struct PrintLineRange {
+ unsigned First;
+ unsigned Last;
+};
+
+struct PrintSourceLocSpec {
+ std::string File;
+ SmallVector<PrintLineRange, 4> Lines;
+};
+
+[[noreturn]] void reportBadLocSpec(StringRef Spec) {
+ report_fatal_error(Twine("Invalid -filter-print-source-locs value '") + Spec +
+ "'. Expected file:line[,line-line][,line].");
+}
+
+std::string normalizeSlashes(StringRef Path) {
+ std::string Result = Path.str();
+ for (char &C : Result)
+ if (C == '\\')
+ C = '/';
+ return Result;
+}
+
+bool parseLine(StringRef LineText, unsigned &Line) {
+ return !LineText.empty() && !LineText.getAsInteger(10, Line);
+}
+
+PrintLineRange parseLineRange(StringRef RangeText, StringRef FullSpec) {
+ auto [FirstText, LastText] = RangeText.split('-');
+
+ unsigned First;
+ if (!parseLine(FirstText, First))
+ reportBadLocSpec(FullSpec);
+
+ if (LastText.empty())
+ return {First, First};
+
+ unsigned Last;
+ if (!parseLine(LastText, Last) || Last < First)
+ reportBadLocSpec(FullSpec);
+
+ return {First, Last};
+}
+
+std::vector<PrintSourceLocSpec> parseSourceLocSpecs() {
+ std::vector<PrintSourceLocSpec> Result;
+ for (const std::string &RawSpec : PrintSourceLocs) {
+ StringRef Spec(RawSpec);
+ auto [File, LineSpec] = Spec.rsplit(':');
+ if (File.empty() || LineSpec.empty())
+ reportBadLocSpec(Spec);
+
+ PrintSourceLocSpec Parsed;
+ Parsed.File = normalizeSlashes(File);
+ for (StringRef RangeText : llvm::split(LineSpec, ",")) {
+ Parsed.Lines.push_back(parseLineRange(RangeText, Spec));
+ }
+ Result.push_back(std::move(Parsed));
+ }
+ return Result;
+}
+
+ArrayRef<PrintSourceLocSpec> getSourceLocSpecs() {
+ static const std::vector<PrintSourceLocSpec> Specs = parseSourceLocSpecs();
+ return Specs;
+}
+
+std::string makeDebugLocPath(StringRef Directory, StringRef Filename) {
+ std::string NormalizedFilename = normalizeSlashes(Filename);
+ if (Directory.empty() || sys::path::is_absolute(NormalizedFilename))
+ return NormalizedFilename;
+
+ std::string NormalizedDirectory = normalizeSlashes(Directory);
+ if (NormalizedDirectory.empty())
+ return NormalizedFilename;
+ if (NormalizedDirectory.back() == '/')
+ return NormalizedDirectory + NormalizedFilename;
+ return NormalizedDirectory + "/" + NormalizedFilename;
+}
+
+bool matchesFile(StringRef SpecFile, StringRef Directory, StringRef Filename) {
+ std::string LocFile = normalizeSlashes(Filename);
+ std::string LocPath = makeDebugLocPath(Directory, Filename);
+
+ if (SpecFile == LocFile || SpecFile == LocPath)
+ return true;
+
+ StringRef LocFileRef(LocFile);
+ StringRef LocPathRef(LocPath);
+ if (sys::path::filename(LocFileRef) == SpecFile)
+ return true;
+
+ std::string Suffix = (Twine("/") + SpecFile).str();
+ return LocFileRef.ends_with(Suffix) || LocPathRef.ends_with(Suffix);
+}
+
+bool matchesLine(ArrayRef<PrintLineRange> Ranges, unsigned Line) {
+ return any_of(Ranges, [Line](const PrintLineRange &Range) {
+ return Range.First <= Line && Line <= Range.Last;
+ });
+}
+
+bool matchesSourceLocSpec(const DebugLoc &Loc, const PrintSourceLocSpec &Spec) {
+ auto *Scope = dyn_cast_or_null<DIScope>(Loc.getScope());
+ return Scope &&
+ matchesFile(Spec.File, Scope->getDirectory(), Scope->getFilename()) &&
+ matchesLine(Spec.Lines, Loc.getLine());
+}
+
+} // namespace
+
+bool llvm::isSourceLocInPrintList(const DebugLoc &Loc) {
+ ArrayRef<PrintSourceLocSpec> Specs = getSourceLocSpecs();
+ if (Specs.empty())
+ return true;
+
+ for (DebugLoc CurLoc = Loc; CurLoc; CurLoc = CurLoc.getInlinedAt()) {
+ if (any_of(Specs, [&CurLoc](const PrintSourceLocSpec &Spec) {
+ return matchesSourceLocSpec(CurLoc, Spec);
+ }))
+ return true;
+ }
+ return false;
+}
+
+bool llvm::isSourceLocFilterEmpty() { return PrintSourceLocs.empty(); }
+
+bool llvm::shouldPrintFunction(const Function &F) {
+ if (!isFunctionInPrintList(F.getName()))
+ return false;
+
+ if (isSourceLocFilterEmpty())
+ return true;
+
+ for (const BasicBlock &BB : F)
+ for (const Instruction &I : BB)
+ if (isSourceLocInPrintList(I.getDebugLoc()))
+ return true;
+ return false;
}
std::error_code cleanUpTempFilesImpl(ArrayRef<std::string> FileName,
diff --git a/llvm/lib/IRPrinter/IRPrintingPasses.cpp b/llvm/lib/IRPrinter/IRPrintingPasses.cpp
index adb192ac4a916..343d8b2b6d74b 100644
--- a/llvm/lib/IRPrinter/IRPrintingPasses.cpp
+++ b/llvm/lib/IRPrinter/IRPrintingPasses.cpp
@@ -32,14 +32,14 @@ PrintModulePass::PrintModulePass(raw_ostream &OS, const std::string &Banner,
EmitSummaryIndex(EmitSummaryIndex) {}
PreservedAnalyses PrintModulePass::run(Module &M, ModuleAnalysisManager &AM) {
- if (llvm::isFunctionInPrintList("*")) {
+ if (llvm::isFunctionInPrintList("*") && isSourceLocFilterEmpty()) {
if (!Banner.empty())
OS << Banner << "\n";
M.print(OS, nullptr, ShouldPreserveUseListOrder);
} else {
bool BannerPrinted = false;
for (const auto &F : M.functions()) {
- if (llvm::isFunctionInPrintList(F.getName())) {
+ if (shouldPrintFunction(F)) {
if (!BannerPrinted && !Banner.empty()) {
OS << Banner << "\n";
BannerPrinted = true;
@@ -67,7 +67,7 @@ PrintFunctionPass::PrintFunctionPass(raw_ostream &OS, const std::string &Banner)
PreservedAnalyses PrintFunctionPass::run(Function &F,
FunctionAnalysisManager &) {
- if (isFunctionInPrintList(F.getName())) {
+ if (shouldPrintFunction(F)) {
if (forcePrintModuleIR())
OS << Banner << " (function: " << F.getName() << ")\n" << *F.getParent();
else
diff --git a/llvm/lib/Passes/StandardInstrumentations.cpp b/llvm/lib/Passes/StandardInstrumentations.cpp
index 19e72a8612c4a..9732323d7e77e 100644
--- a/llvm/lib/Passes/StandardInstrumentations.cpp
+++ b/llvm/lib/Passes/StandardInstrumentations.cpp
@@ -18,11 +18,15 @@
#include "llvm/Analysis/LazyCallGraph.h"
#include "llvm/Analysis/LoopInfo.h"
#include "llvm/CodeGen/MIRPrinter.h"
+#include "llvm/CodeGen/MachineBasicBlock.h"
#include "llvm/CodeGen/MachineFunction.h"
+#include "llvm/CodeGen/MachineInstr.h"
#include "llvm/CodeGen/MachineModuleInfo.h"
#include "llvm/CodeGen/MachineVerifier.h"
+#include "llvm/IR/BasicBlock.h"
#include "llvm/IR/Constants.h"
#include "llvm/IR/Function.h"
+#include "llvm/IR/Instruction.h"
#include "llvm/IR/Module.h"
#include "llvm/IR/PassInstrumentation.h"
#include "llvm/IR/PassManager.h"
@@ -159,6 +163,39 @@ static cl::opt<std::string>
cl::desc("exe called with module IR after each pass that "
"changes it"));
+bool loopContainsPrintSourceLoc(const Loop &L) {
+ const Function *F = L.getHeader()->getParent();
+ if (!isFunctionInPrintList(F->getName()))
+ return false;
+
+ if (isSourceLocFilterEmpty())
+ return true;
+
+ for (const BasicBlock *BB : L.blocks())
+ for (const Instruction &I : *BB)
+ if (isSourceLocInPrintList(I.getDebugLoc()))
+ return true;
+ return false;
+}
+
+bool shouldGenerateData(const Function &F) {
+ return !F.isDeclaration() && shouldPrintFunction(F);
+}
+
+bool shouldGenerateData(const MachineFunction &MF) {
+ if (!isFunctionInPrintList(MF.getName()))
+ return false;
+
+ if (isSourceLocFilterEmpty())
+ return true;
+
+ for (const MachineBasicBlock &MBB : MF)
+ for (const MachineInstr &MI : MBB)
+ if (isSourceLocInPrintList(MI.getDebugLoc()))
+ return true;
+ return false;
+}
+
/// Extract Module out of \p IR unit. May return nullptr if \p IR does not match
/// certain global filters. Will never return nullptr if \p Force is true.
const Module *unwrapModule(Any IR, bool Force = false) {
@@ -166,7 +203,7 @@ const Module *unwrapModule(Any IR, bool Force = false) {
return M;
if (const auto *F = unwrapIR<Function>(IR)) {
- if (!Force && !isFunctionInPrintList(F->getName()))
+ if (!Force && !shouldGenerateData(*F))
return nullptr;
return F->getParent();
@@ -175,7 +212,7 @@ const Module *unwrapModule(Any IR, bool Force = false) {
if (const auto *C = unwrapIR<LazyCallGraph::SCC>(IR)) {
for (const LazyCallGraph::Node &N : *C) {
const Function &F = N.getFunction();
- if (Force || (!F.isDeclaration() && isFunctionInPrintList(F.getName()))) {
+ if (Force || (!F.isDeclaration() && shouldGenerateData(F))) {
return F.getParent();
}
}
@@ -185,13 +222,13 @@ const Module *unwrapModule(Any IR, bool Force = false) {
if (const auto *L = unwrapIR<Loop>(IR)) {
const Function *F = L->getHeader()->getParent();
- if (!Force && !isFunctionInPrintList(F->getName()))
+ if (!Force && !loopContainsPrintSourceLoc(*L))
return nullptr;
return F->getParent();
}
if (const auto *MF = unwrapIR<MachineFunction>(IR)) {
- if (!Force && !isFunctionInPrintList(MF->getName()))
+ if (!Force && !shouldGenerateData(*MF))
return nullptr;
return MF->getFunction().getParent();
}
@@ -200,13 +237,14 @@ const Module *unwrapModule(Any IR, bool Force = false) {
}
void printIR(raw_ostream &OS, const Function *F) {
- if (!isFunctionInPrintList(F->getName()))
+ if (!shouldPrintFunction(*F))
return;
OS << *F;
}
void printIR(raw_ostream &OS, const Module *M) {
- if (isFunctionInPrintList("*") || forcePrintModuleIR()) {
+ if ((isFunctionInPrintList("*") && isSourceLocFilterEmpty()) ||
+ forcePrintModuleIR()) {
M->print(OS, nullptr);
} else {
for (const auto &F : M->functions()) {
@@ -218,21 +256,20 @@ void printIR(raw_ostream &OS, const Module *M) {
void printIR(raw_ostream &OS, const LazyCallGraph::SCC *C) {
for (const LazyCallGraph::Node &N : *C) {
const Function &F = N.getFunction();
- if (!F.isDeclaration() && isFunctionInPrintList(F.getName())) {
+ if (!F.isDeclaration() && shouldGenerateData(F)) {
F.print(OS);
}
}
}
void printIR(raw_ostream &OS, const Loop *L) {
- const Function *F = L->getHeader()->getParent();
- if (!isFunctionInPrintList(F->getName()))
+ if (!loopContainsPrintSourceLoc(*L))
return;
printLoop(const_cast<Loop &>(*L), OS);
}
void printIR(raw_ostream &OS, const MachineFunction *MF) {
- if (!isFunctionInPrintList(MF->getName()))
+ if (!shouldGenerateData(*MF))
return;
MF->print(OS);
}
@@ -259,18 +296,15 @@ std::string getIRName(Any IR) {
bool moduleContainsFilterPrintFunc(const Module &M) {
return any_of(M.functions(),
- [](const Function &F) {
- return isFunctionInPrintList(F.getName());
- }) ||
- isFunctionInPrintList("*");
+ [](const Function &F) { return shouldPrintFunction(F); }) ||
+ (isFunctionInPrintList("*") && isSourceLocFilterEmpty());
}
bool sccContainsFilterPrintFunc(const LazyCallGraph::SCC &C) {
- return any_of(C,
- [](const LazyCallGraph::Node &N) {
- return isFunctionInPrintList(N.getName());
- }) ||
- isFunctionInPrintList("*");
+ return any_of(C, [](const LazyCallGraph::Node &N) {
+ const Function &F = N.getFunction();
+ return !F.isDeclaration() && shouldGenerateData(F);
+ });
}
bool shouldPrintIR(Any IR) {
@@ -278,16 +312,16 @@ bool shouldPrintIR(Any IR) {
return moduleContainsFilterPrintFunc(*M);
if (const auto *F = unwrapIR<Function>(IR))
- return isFunctionInPrintList(F->getName());
+ return shouldPrintFunction(*F);
if (const auto *C = unwrapIR<LazyCallGraph::SCC>(IR))
return sccContainsFilterPrintFunc(*C);
if (const auto *L = unwrapIR<Loop>(IR))
- return isFunctionInPrintList(L->getHeader()->getParent()->getName());
+ return loopContainsPrintSourceLoc(*L);
if (const auto *MF = unwrapIR<MachineFunction>(IR))
- return isFunctionInPrintList(MF->getName());
+ return shouldGenerateData(*MF);
llvm_unreachable("Unknown wrapped IR type");
}
@@ -364,9 +398,7 @@ const Module *getModuleForComparison(Any IR) {
return nullptr;
}
-bool isInterestingFunction(const Function &F) {
- return isFunctionInPrintList(F.getName());
-}
+bool isInterestingFunction(const Function &F) { return shouldGenerateData(F); }
// Return true when this is a pass on IR for which printing
// of changes is desired.
@@ -715,14 +747,6 @@ template <typename T> void IRComparer<T>::analyzeIR(Any IR, IRDataT<T> &Data) {
llvm_unreachable("Unknown IR unit");
}
-static bool shouldGenerateData(const Function &F) {
- return !F.isDeclaration() && isFunctionInPrintList(F.getName());
-}
-
-static bool shouldGenerateData(const MachineFunction &MF) {
- return isFunctionInPrintList(MF.getName());
-}
-
template <typename T>
template <typename FunctionT>
bool IRComparer<T>::generateFunctionData(IRDataT<T> &Data, const FunctionT &F) {
diff --git a/llvm/test/CodeGen/X86/source-loc-print-filter.ll b/llvm/test/CodeGen/X86/source-loc-print-filter.ll
new file mode 100644
index 0000000000000..8d20fa90e028e
--- /dev/null
+++ b/llvm/test/CodeGen/X86/source-loc-print-filter.ll
@@ -0,0 +1,49 @@
+; RUN: llc -mtriple=x86_64 -O2 -print-after-all \
+; RUN: -filter-print-source-locs=source.c:10 -o /dev/null < %s 2>&1 \
+; RUN: | FileCheck %s --check-prefix=MATCH
+
+; RUN: llc -mtriple=x86_64 -O2 -print-after-all \
+; RUN: -filter-print-funcs=* -filter-print-source-locs=source.c:10 \
+; RUN: -o /dev/null < %s 2>&1 | FileCheck %s --check-prefix=MATCH
+
+; RUN: llc -mtriple=x86_64 -O2 -print-after-all \
+; RUN: -filter-print-source-locs=source.c:999 -o /dev/null < %s 2>&1 \
+; RUN: | FileCheck %s --allow-empty --check-prefix=EMPTY
+
+; MATCH: IR Dump After
+; MATCH: define i32 @foo
+; MATCH-NOT: define i32 @bar
+; MATCH: Machine code for function foo
+; MATCH-NOT: Machine code for function bar
+
+; EMPTY-NOT: IR Dump After
+; EMPTY-NOT: Machine code for function
+
+define i32 @foo() !dbg !5 {
+entry:
+ %sum = add i32 1, 2, !dbg !10
+ ret i32 %sum, !dbg !11
+}
+
+define i32 @bar() !dbg !12 {
+entry:
+ %sum = add i32 3, 4, !dbg !13
+ ret i32 %sum, !dbg !14
+}
+
+!llvm.dbg.cu = !{!0}
+!llvm.module.flags = !{!2, !3}
+
+!0 = distinct !DICompileUnit(language: DW_LANG_C99, file: !1, producer: "test", isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug)
+!1 = !DIFile(filename: "source.c", directory: "/tmp")
+!2 = !{i32 7, !"Dwarf Version", i32 5}
+!3 = !{i32 2, !"Debug Info Version", i32 3}
+!4 = !DISubroutineType(types: !15)
+!5 = distinct !DISubprogram(name: "foo", scope: !1, file: !1, line: 9, type: !4, scopeLine: 9, spFlags: DISPFlagDefinition, unit: !0)
+!10 = !DILocation(line: 10, column: 7, scope: !5)
+!11 = !DILocation(line: 11, column: 3, scope: !5)
+!12 = distinct !DISubprogram(name: "bar", scope: !1, file: !1, line: 19, type: !4, scopeLine: 19, spFlags: DISPFlagDefinition, unit: !0)
+!13 = !DILocation(line: 20, column: 7, scope: !12)
+!14 = !DILocation(line: 21, column: 3, scope: !12)
+!15 = !{!16}
+!16 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed)
diff --git a/llvm/test/Other/source-loc-print-filter.ll b/llvm/test/Other/source-loc-print-filter.ll
new file mode 100644
index 0000000000000..022fa58753111
--- /dev/null
+++ b/llvm/test/Other/source-loc-print-filter.ll
@@ -0,0 +1,97 @@
+; Check separated lines and ranges.
+; RUN: opt < %s 2>&1 -disable-output -passes=forceattrs -print-after-all \
+; RUN: -filter-print-source-locs=source.c:10,30-32 \
+; RUN: | FileCheck %s --check-prefix=RANGE
+
+; Check path suffix matching.
+; RUN: opt < %s 2>&1 -disable-output -passes=forceattrs -print-after-all \
+; RUN: -filter-print-source-locs=dir/source.c:31 \
+; RUN: | FileCheck %s --check-prefix=SUFFIX
+
+; Check function pass filtering.
+; RUN: opt < %s 2>&1 -disable-output -passes='function(no-op-function)' \
+; RUN: -print-after-all -filter-print-source-locs=source.c:10 \
+; RUN: | FileCheck %s --check-prefix=FUNCTION
+
+; Check that an explicit function wildcard still respects the source location
+; filter.
+; RUN: opt < %s 2>&1 -disable-output -passes=forceattrs -print-after-all \
+; RUN: -filter-print-funcs=* -filter-print-source-locs=source.c:10 \
+; RUN: | FileCheck %s --check-prefix=WILDCARD
+
+; Check that a missing source location suppresses the dump.
+; RUN: opt < %s 2>&1 -disable-output -passes=forceattrs -print-after-all \
+; RUN: -filter-print-source-locs=missing.c:10 \
+; RUN: | FileCheck %s --allow-empty --check-prefix=EMPTY
+
+; Check that the explicit print pass uses the same filter.
+; RUN: opt < %s 2>&1 -disable-output -passes=print \
+; RUN: -filter-print-funcs=* -filter-print-source-locs=source.c:10 \
+; RUN: | FileCheck %s --check-prefix=PRINT-PASS
+
+; RANGE: IR Dump After {{Force set function attributes|ForceFunctionAttrsPass}}
+; RANGE: define i32 @foo
+; RANGE-NOT: define i32 @bar
+; RANGE: define i32 @baz
+; RANGE-NOT: IR Dump After {{Force set function attributes|ForceFunctionAttrsPass}}
+
+; SUFFIX: IR Dump After {{Force set function attributes|ForceFunctionAttrsPass}}
+; SUFFIX-NOT: define i32 @foo
+; SUFFIX-NOT: define i32 @bar
+; SUFFIX: define i32 @baz
+; SUFFIX-NOT: IR Dump After {{Force set function attributes|ForceFunctionAttrsPass}}
+
+; FUNCTION: IR Dump After NoOpFunctionPass on foo
+; FUNCTION-NEXT: define i32 @foo
+; FUNCTION-NOT: IR Dump After NoOpFunctionPass on bar
+; FUNCTION-NOT: IR Dump After NoOpFunctionPass on baz
+
+; WILDCARD: IR Dump After {{Force set function attributes|ForceFunctionAttrsPass}}
+; WILDCARD: define i32 @foo
+; WILDCARD-NOT: define i32 @bar
+; WILDCARD-NOT: define i32 @baz
+; WILDCARD-NOT: IR Dump After {{Force set function attributes|ForceFunctionAttrsPass}}
+
+; EMPTY-NOT: IR Dump After {{Force set function attributes|ForceFunctionAttrsPass}}
+
+; PRINT-PASS: define i32 @foo
+; PRINT-PASS-NOT: define i32 @bar
+; PRINT-PASS-NOT: define i32 @baz
+
+define i32 @foo() !dbg !5 {
+entry:
+ %sum = add i32 1, 2, !dbg !10
+ ret i32 %sum, !dbg !11
+}
+
+define i32 @bar() !dbg !12 {
+entry:
+ %sum = add i32 3, 4, !dbg !13
+ ret i32 %sum, !dbg !14
+}
+
+define i32 @baz() !dbg !15 {
+entry:
+ %sum = add i32 5, 6, !dbg !16
+ ret i32 %sum, !dbg !17
+}
+
+!llvm.dbg.cu = !{!0}
+!llvm.module.flags = !{!2, !3}
+
+!0 = distinct !DICompileUnit(language: DW_LANG_C99, file: !1, producer: "test", isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug)
+!1 = !DIFile(filename: "source.c", directory: "/tmp/dir")
+!2 = !{i32 7, !"Dwarf Version", i32 5}
+!3 = !{i32 2, !"Debug Info Version", i32 3}
+!4 = !DISubroutineType(types: !18)
+!5 = distinct !DISubprogram(name: "foo", scope: !1, file: !1, line: 9, type: !4, scopeLine: 9, spFlags: DISPFlagDefinition, unit: !0)
+!10 = !DILocation(line: 10, column: 7, scope: !5)
+!11 = !DILocation(line: 11, column: 3, scope: !5)
+!12 = distinct !DISubprogram(name: "bar", scope: !1, file: !1, line: 19, type: !4, scopeLine: 19, spFlags: DISPFlagDefinition, unit: !0)
+!13 = !DILocation(line: 20, column: 7, scope: !12)
+!14 = !DILocation(line: 21, column: 3, scope: !12)
+!15 = distinct !DISubprogram(name: "baz", scope: !1, file: !1, line: 29, type: !4, scopeLine: 29, spFlags: DISPFlagDefinition, unit: !0)
+!16 = !DILocation(line: 31, column: 7, scope: !15)
+!17 = !DILocation(line: 32, column: 3, scope: !15)
+!18 = !{!19}
+!19 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed)
More information about the llvm-commits
mailing list