llvm-project/llvm/lib/IR/IRPrintingPasses.cpp
Stephen Tozer 379628d446
[RemoveDIs] Add flag to preserve the debug info format of input IR (#87379)
This patch adds a new flag: `--preserve-input-debuginfo-format`

This flag instructs the tool to not convert the debug info format
(intrinsics/records) of input IR, but to instead determine the format of
the input IR and overwrite the other format-determining flags so that we
process and output the file in the same format that we received it in.
This flag is turned off by llvm-link, llvm-lto, and llvm-lto2, and
should be turned off by any other tool that expects to parse multiple IR
modules and have their debug info formats match.

The motivation for this flag is to allow tools to not convert the debug
info format - verify-uselistorder and llvm-reduce, and any downstream
tools that seek to test or mutate IR as-is, without applying extraneous
modifications to the input. This is a necessary step to using debug
records by default in all (other) LLVM tools.
2024-04-05 14:18:59 +01:00

144 lines
4.7 KiB
C++

//===--- IRPrintingPasses.cpp - Module and Function printing passes -------===//
//
// 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
//
//===----------------------------------------------------------------------===//
//
// PrintModulePass and PrintFunctionPass implementations for the legacy pass
// manager.
//
//===----------------------------------------------------------------------===//
#include "llvm/IR/IRPrintingPasses.h"
#include "llvm/ADT/StringRef.h"
#include "llvm/IR/Function.h"
#include "llvm/IR/Module.h"
#include "llvm/IR/PrintPasses.h"
#include "llvm/InitializePasses.h"
#include "llvm/Pass.h"
#include "llvm/Support/Debug.h"
#include "llvm/Support/raw_ostream.h"
using namespace llvm;
cl::opt<bool> WriteNewDbgInfoFormat(
"write-experimental-debuginfo",
cl::desc("Write debug info in the new non-intrinsic format. Has no effect "
"if --preserve-input-debuginfo-format=true."),
cl::init(false));
namespace {
class PrintModulePassWrapper : public ModulePass {
raw_ostream &OS;
std::string Banner;
bool ShouldPreserveUseListOrder;
public:
static char ID;
PrintModulePassWrapper() : ModulePass(ID), OS(dbgs()) {}
PrintModulePassWrapper(raw_ostream &OS, const std::string &Banner,
bool ShouldPreserveUseListOrder)
: ModulePass(ID), OS(OS), Banner(Banner),
ShouldPreserveUseListOrder(ShouldPreserveUseListOrder) {}
bool runOnModule(Module &M) override {
// RemoveDIs: Regardless of the format we've processed this module in, use
// `WriteNewDbgInfoFormat` to determine which format we use to write it.
ScopedDbgInfoFormatSetter FormatSetter(M, WriteNewDbgInfoFormat);
// Remove intrinsic declarations when printing in the new format.
// TODO: Move this into Module::setIsNewDbgInfoFormat when we're ready to
// update test output.
if (WriteNewDbgInfoFormat)
M.removeDebugIntrinsicDeclarations();
if (llvm::isFunctionInPrintList("*")) {
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 (!BannerPrinted && !Banner.empty()) {
OS << Banner << "\n";
BannerPrinted = true;
}
F.print(OS);
}
}
}
return false;
}
void getAnalysisUsage(AnalysisUsage &AU) const override {
AU.setPreservesAll();
}
StringRef getPassName() const override { return "Print Module IR"; }
};
class PrintFunctionPassWrapper : public FunctionPass {
raw_ostream &OS;
std::string Banner;
public:
static char ID;
PrintFunctionPassWrapper() : FunctionPass(ID), OS(dbgs()) {}
PrintFunctionPassWrapper(raw_ostream &OS, const std::string &Banner)
: FunctionPass(ID), OS(OS), Banner(Banner) {}
// This pass just prints a banner followed by the function as it's processed.
bool runOnFunction(Function &F) override {
// RemoveDIs: Regardless of the format we've processed this function in, use
// `WriteNewDbgInfoFormat` to determine which format we use to write it.
ScopedDbgInfoFormatSetter FormatSetter(F, WriteNewDbgInfoFormat);
if (isFunctionInPrintList(F.getName())) {
if (forcePrintModuleIR())
OS << Banner << " (function: " << F.getName() << ")\n"
<< *F.getParent();
else
OS << Banner << '\n' << static_cast<Value &>(F);
}
return false;
}
void getAnalysisUsage(AnalysisUsage &AU) const override {
AU.setPreservesAll();
}
StringRef getPassName() const override { return "Print Function IR"; }
};
} // namespace
char PrintModulePassWrapper::ID = 0;
INITIALIZE_PASS(PrintModulePassWrapper, "print-module",
"Print module to stderr", false, true)
char PrintFunctionPassWrapper::ID = 0;
INITIALIZE_PASS(PrintFunctionPassWrapper, "print-function",
"Print function to stderr", false, true)
ModulePass *llvm::createPrintModulePass(llvm::raw_ostream &OS,
const std::string &Banner,
bool ShouldPreserveUseListOrder) {
return new PrintModulePassWrapper(OS, Banner, ShouldPreserveUseListOrder);
}
FunctionPass *llvm::createPrintFunctionPass(llvm::raw_ostream &OS,
const std::string &Banner) {
return new PrintFunctionPassWrapper(OS, Banner);
}
bool llvm::isIRPrintingPass(Pass *P) {
const char *PID = (const char *)P->getPassID();
return (PID == &PrintModulePassWrapper::ID) ||
(PID == &PrintFunctionPassWrapper::ID);
}