[llvm] [opt] Do not exit on first emitError (PR #194858)
Arseniy Obolenskiy via llvm-commits
llvm-commits at lists.llvm.org
Wed Apr 29 21:34:28 PDT 2026
https://github.com/aobolensk updated https://github.com/llvm/llvm-project/pull/194858
>From d4276202fae2921f382ca131894e852b04bccad0 Mon Sep 17 00:00:00 2001
From: Arseniy Obolenskiy <arseniy.obolenskiy at amd.com>
Date: Wed, 29 Apr 2026 15:22:20 +0200
Subject: [PATCH 1/4] [opt] Do not exit on first emitError
- opt default diagnostic handler calls exit(1) on the first emitError, so later passes don't run and behavior diverges from llc
- set OptDiagnosticHandler that collects all the errors and then exits with non-zero exit code after reporting them
- Fix 2 issues related to the behavior change:
* IR2VecPrinterPass asserted on an invalid vocabulary after the analysis already emitted an error
* InlinerPass::getAdvisor overwrote OwnedAdvisor with the null result of getReplayInlineAdvisor on a missing replay file
related to #142014
---
llvm/lib/Analysis/IR2Vec.cpp | 3 +-
llvm/lib/Transforms/IPO/Inliner.cpp | 20 +++++++------
.../AtomicExpand/AMDGPU/unaligned-atomic.ll | 2 +-
.../NVPTX/safestack-libcall-error.ll | 4 +--
llvm/test/tools/opt/diagnostic-handler.ll | 28 +++++++++++++++++++
llvm/tools/opt/NewPMDriver.cpp | 24 ++++++++++++++++
llvm/tools/opt/NewPMDriver.h | 10 +++++++
llvm/tools/opt/optdriver.cpp | 9 ++++++
8 files changed, 87 insertions(+), 13 deletions(-)
create mode 100644 llvm/test/tools/opt/diagnostic-handler.ll
diff --git a/llvm/lib/Analysis/IR2Vec.cpp b/llvm/lib/Analysis/IR2Vec.cpp
index 55b10c3cf2bc8..e24a08b3b8a65 100644
--- a/llvm/lib/Analysis/IR2Vec.cpp
+++ b/llvm/lib/Analysis/IR2Vec.cpp
@@ -671,7 +671,8 @@ IR2VecVocabAnalysis::run(Module &M, ModuleAnalysisManager &AM) {
PreservedAnalyses IR2VecPrinterPass::run(Module &M,
ModuleAnalysisManager &MAM) {
auto &Vocabulary = MAM.getResult<IR2VecVocabAnalysis>(M);
- assert(Vocabulary.isValid() && "IR2Vec Vocabulary is invalid");
+ if (!Vocabulary.isValid())
+ return PreservedAnalyses::all();
for (Function &F : M) {
auto Emb = Embedder::create(IR2VecEmbeddingKind, F, Vocabulary);
diff --git a/llvm/lib/Transforms/IPO/Inliner.cpp b/llvm/lib/Transforms/IPO/Inliner.cpp
index 7985e74cc5389..ed3fb61a1dfa9 100644
--- a/llvm/lib/Transforms/IPO/Inliner.cpp
+++ b/llvm/lib/Transforms/IPO/Inliner.cpp
@@ -163,14 +163,18 @@ InlinerPass::getAdvisor(const ModuleAnalysisManagerCGSCCProxy::Result &MAM,
InlineContext{LTOPhase, InlinePass::CGSCCInliner});
if (!CGSCCInlineReplayFile.empty())
- OwnedAdvisor = getReplayInlineAdvisor(
- M, FAM, M.getContext(), std::move(OwnedAdvisor),
- ReplayInlinerSettings{CGSCCInlineReplayFile,
- CGSCCInlineReplayScope,
- CGSCCInlineReplayFallback,
- {CGSCCInlineReplayFormat}},
- /*EmitRemarks=*/true,
- InlineContext{LTOPhase, InlinePass::ReplayCGSCCInliner});
+ if (auto ReplayAdvisor = getReplayInlineAdvisor(
+ M, FAM, M.getContext(),
+ std::make_unique<DefaultInlineAdvisor>(
+ M, FAM, getInlineParams(),
+ InlineContext{LTOPhase, InlinePass::CGSCCInliner}),
+ ReplayInlinerSettings{CGSCCInlineReplayFile,
+ CGSCCInlineReplayScope,
+ CGSCCInlineReplayFallback,
+ {CGSCCInlineReplayFormat}},
+ /*EmitRemarks=*/true,
+ InlineContext{LTOPhase, InlinePass::ReplayCGSCCInliner}))
+ OwnedAdvisor = std::move(ReplayAdvisor);
return *OwnedAdvisor;
}
diff --git a/llvm/test/Transforms/AtomicExpand/AMDGPU/unaligned-atomic.ll b/llvm/test/Transforms/AtomicExpand/AMDGPU/unaligned-atomic.ll
index f8f81d0103f83..4ad087181968b 100644
--- a/llvm/test/Transforms/AtomicExpand/AMDGPU/unaligned-atomic.ll
+++ b/llvm/test/Transforms/AtomicExpand/AMDGPU/unaligned-atomic.ll
@@ -6,7 +6,7 @@ define i32 @atomic_load_global_align1(ptr addrspace(1) %ptr) {
ret i32 %val
}
-; FIXME: 2nd error not emitted in next function
+; CHECK: error: unsupported atomic store: instruction alignment 1 is smaller than the required 4-byte alignment for this atomic operation
define void @atomic_store_global_align1(ptr addrspace(1) %ptr, i32 %val) {
store atomic i32 %val, ptr addrspace(1) %ptr monotonic, align 1
ret void
diff --git a/llvm/test/Transforms/SafeStack/NVPTX/safestack-libcall-error.ll b/llvm/test/Transforms/SafeStack/NVPTX/safestack-libcall-error.ll
index e8287639b969a..b8960f5c07898 100644
--- a/llvm/test/Transforms/SafeStack/NVPTX/safestack-libcall-error.ll
+++ b/llvm/test/Transforms/SafeStack/NVPTX/safestack-libcall-error.ll
@@ -1,9 +1,7 @@
; RUN: not opt -disable-output -mtriple=nvptx64-- -mcpu=sm_90 -passes='require<libcall-lowering-info>,safe-stack' %s 2>&1 | FileCheck --implicit-check-not=error %s
; CHECK: error: no location available for safestack pointer address
-
-; FIXME: If opt had more reasonable error handling behavior, this should emit 2 errors
-; xCHECK: error: no libcall available for stackprotector check fail
+; CHECK: error: no libcall available for stackprotector check fail
define void @foo(i32 %t) #0 {
%vla = alloca i32, i32 %t, align 4
call void @baz(ptr %vla)
diff --git a/llvm/test/tools/opt/diagnostic-handler.ll b/llvm/test/tools/opt/diagnostic-handler.ll
new file mode 100644
index 0000000000000..127a6ab8710fc
--- /dev/null
+++ b/llvm/test/tools/opt/diagnostic-handler.ll
@@ -0,0 +1,28 @@
+; Verify that opt's diagnostic handler does not exit on the first error
+; reported via LLVMContext::emitError. opt should continue to run remaining
+; passes (so the print-module pass at the end of the pipeline still emits
+; the module to stdout), then return a non-zero exit status.
+;
+; Without the OptDiagnosticHandler, the first emitError would invoke
+; exit(1) from LLVMContext::diagnose() and the print-module pass would
+; never run, so stdout would be empty.
+
+; RUN: not opt -S -passes='module(sancov-module),print<module-debuginfo>' \
+; RUN: -sanitizer-coverage-level=1 -sanitizer-coverage-stack-depth %s \
+; RUN: >%t.out 2>%t.err
+; RUN: FileCheck --check-prefix=ERR --input-file=%t.err %s
+; RUN: FileCheck --check-prefix=OUT --input-file=%t.out %s
+
+; sancov-module emits an error when '__sancov_lowest_stack' has the wrong
+; type. The pass returns safely and the pipeline continues.
+ at __sancov_lowest_stack = thread_local global i32 0
+
+define i32 @f() {
+ ret i32 0
+}
+
+; ERR: error: '__sancov_lowest_stack' should not be declared by the user
+
+; The print-module pass after sancov-module still runs, proving opt did
+; not exit on the first emitError.
+; OUT: define i32 @f()
diff --git a/llvm/tools/opt/NewPMDriver.cpp b/llvm/tools/opt/NewPMDriver.cpp
index 2f57ae6d045e3..569426a7fd504 100644
--- a/llvm/tools/opt/NewPMDriver.cpp
+++ b/llvm/tools/opt/NewPMDriver.cpp
@@ -23,6 +23,8 @@
#include "llvm/Bitcode/BitcodeWriterPass.h"
#include "llvm/CodeGen/LibcallLoweringInfo.h"
#include "llvm/Config/llvm-config.h"
+#include "llvm/IR/DiagnosticInfo.h"
+#include "llvm/IR/DiagnosticPrinter.h"
#include "llvm/IR/Dominators.h"
#include "llvm/IR/LLVMContext.h"
#include "llvm/IR/Module.h"
@@ -238,6 +240,22 @@ static cl::opt<bool> DisableLoopUnrolling(
"disable-loop-unrolling",
cl::desc("Disable loop unrolling in all relevant passes"), cl::init(false));
+bool OptDiagnosticHandler::handleDiagnostics(const DiagnosticInfo &DI) {
+ DiagnosticHandler::handleDiagnostics(DI);
+ // Mirror the filtering performed by LLVMContext::diagnose's default path:
+ // optimization remarks are gated by the -pass-remarks* flags (isEnabled),
+ // and verbose remarks additionally require hotness data.
+ if (auto *Remark = dyn_cast<DiagnosticInfoOptimizationBase>(&DI))
+ if (!Remark->isEnabled() || (Remark->isVerbose() && !Remark->getHotness()))
+ return true;
+
+ DiagnosticPrinterRawOStream DP(errs());
+ errs() << LLVMContext::getDiagnosticMessagePrefix(DI.getSeverity()) << ": ";
+ DI.print(DP);
+ errs() << "\n";
+ return true;
+}
+
template <typename PassManagerT>
bool tryParsePipelineText(PassBuilder &PB,
const cl::opt<std::string> &PipelineOpt) {
@@ -573,6 +591,12 @@ bool llvm::runPassPipeline(
// Now that we have all of the passes ready, run them.
MPM.run(M, MAM);
+ // If a pass reported an error via LLVMContext::emitError, fail without
+ // writing the output module.
+ if (auto *DH = M.getContext().getDiagHandlerPtr())
+ if (DH->HasErrors)
+ return false;
+
// Declare success.
if (OK != OK_NoOutput) {
Out->keep();
diff --git a/llvm/tools/opt/NewPMDriver.h b/llvm/tools/opt/NewPMDriver.h
index 042d5d4bbfe47..0c60ace68c561 100644
--- a/llvm/tools/opt/NewPMDriver.h
+++ b/llvm/tools/opt/NewPMDriver.h
@@ -20,6 +20,7 @@
#ifndef LLVM_TOOLS_OPT_NEWPMDRIVER_H
#define LLVM_TOOLS_OPT_NEWPMDRIVER_H
+#include "llvm/IR/DiagnosticHandler.h"
#include "llvm/Support/CommandLine.h"
namespace llvm {
@@ -31,6 +32,15 @@ class TargetMachine;
class ToolOutputFile;
class TargetLibraryInfoImpl;
+/// A custom diagnostic handler for opt that consumes diagnostics so that the
+/// default LLVMContext::diagnose() does not call exit() on the first error.
+/// opt can then drain remaining diagnostics from a single pass run and report
+/// them all, mirroring llc's behavior so that opt remains a faithful test
+/// driver for passes that report errors via LLVMContext::emitError.
+struct OptDiagnosticHandler : public DiagnosticHandler {
+ bool handleDiagnostics(const DiagnosticInfo &DI) override;
+};
+
extern cl::opt<bool> DebugifyEach;
extern cl::opt<std::string> DebugifyExport;
diff --git a/llvm/tools/opt/optdriver.cpp b/llvm/tools/opt/optdriver.cpp
index 3e5b1f95b1de9..2e24c2e353ef1 100644
--- a/llvm/tools/opt/optdriver.cpp
+++ b/llvm/tools/opt/optdriver.cpp
@@ -538,6 +538,10 @@ optMain(int argc, char **argv,
if (!DisableDITypeMap)
Context.enableDebugTypeODRUniquing();
+ // Set a diagnostic handler that doesn't exit on the first error so that opt
+ // can drain remaining diagnostics from a single pass run, mirroring llc.
+ Context.setDiagnosticHandler(std::make_unique<OptDiagnosticHandler>());
+
Expected<LLVMRemarkFileHandle> RemarksFileOrErr =
setupLLVMOptimizationRemarks(Context, RemarksFilename, RemarksPasses,
RemarksFormat, RemarksWithHotness,
@@ -974,6 +978,11 @@ optMain(int argc, char **argv,
if (DebugifyEach && !DebugifyExport.empty())
exportDebugifyStats(DebugifyExport, Passes.getDebugifyStatsMap());
+ // If a pass reported an error via LLVMContext::emitError, fail without
+ // writing the output module.
+ if (Context.getDiagHandlerPtr()->HasErrors)
+ return 1;
+
// Declare success.
if (!NoOutput)
Out->keep();
>From 1643a12a2a952f08ec5decb0b63d3a1e0dd42668 Mon Sep 17 00:00:00 2001
From: Arseniy Obolenskiy <arseniy.obolenskiy at amd.com>
Date: Wed, 29 Apr 2026 18:47:25 +0200
Subject: [PATCH 2/4] Address review comments
---
llvm/lib/IR/LLVMContext.cpp | 2 --
llvm/test/tools/opt/diagnostic-handler.ll | 13 +++++-------
llvm/tools/opt/NewPMDriver.cpp | 21 ++-----------------
llvm/tools/opt/NewPMDriver.h | 10 ---------
llvm/tools/opt/optdriver.cpp | 4 ----
llvm/unittests/Analysis/MLModelRunnerTest.cpp | 20 ++++++++++++++++++
6 files changed, 27 insertions(+), 43 deletions(-)
diff --git a/llvm/lib/IR/LLVMContext.cpp b/llvm/lib/IR/LLVMContext.cpp
index 10aba759185a7..48bd85e812a5c 100644
--- a/llvm/lib/IR/LLVMContext.cpp
+++ b/llvm/lib/IR/LLVMContext.cpp
@@ -268,8 +268,6 @@ void LLVMContext::diagnose(const DiagnosticInfo &DI) {
errs() << getDiagnosticMessagePrefix(DI.getSeverity()) << ": ";
DI.print(DP);
errs() << "\n";
- if (DI.getSeverity() == DS_Error)
- exit(1);
}
//===----------------------------------------------------------------------===//
diff --git a/llvm/test/tools/opt/diagnostic-handler.ll b/llvm/test/tools/opt/diagnostic-handler.ll
index 127a6ab8710fc..3eb9da827288e 100644
--- a/llvm/test/tools/opt/diagnostic-handler.ll
+++ b/llvm/test/tools/opt/diagnostic-handler.ll
@@ -1,11 +1,8 @@
-; Verify that opt's diagnostic handler does not exit on the first error
-; reported via LLVMContext::emitError. opt should continue to run remaining
-; passes (so the print-module pass at the end of the pipeline still emits
-; the module to stdout), then return a non-zero exit status.
-;
-; Without the OptDiagnosticHandler, the first emitError would invoke
-; exit(1) from LLVMContext::diagnose() and the print-module pass would
-; never run, so stdout would be empty.
+; Verify that LLVMContext's default diagnostic handler does not exit on
+; the first error reported via LLVMContext::emitError. opt should continue
+; to run remaining passes (so the print-module pass at the end of the
+; pipeline still emits the module to stdout), then return a non-zero exit
+; status because the handler's HasErrors flag was set.
; RUN: not opt -S -passes='module(sancov-module),print<module-debuginfo>' \
; RUN: -sanitizer-coverage-level=1 -sanitizer-coverage-stack-depth %s \
diff --git a/llvm/tools/opt/NewPMDriver.cpp b/llvm/tools/opt/NewPMDriver.cpp
index 569426a7fd504..c303048137648 100644
--- a/llvm/tools/opt/NewPMDriver.cpp
+++ b/llvm/tools/opt/NewPMDriver.cpp
@@ -23,8 +23,6 @@
#include "llvm/Bitcode/BitcodeWriterPass.h"
#include "llvm/CodeGen/LibcallLoweringInfo.h"
#include "llvm/Config/llvm-config.h"
-#include "llvm/IR/DiagnosticInfo.h"
-#include "llvm/IR/DiagnosticPrinter.h"
#include "llvm/IR/Dominators.h"
#include "llvm/IR/LLVMContext.h"
#include "llvm/IR/Module.h"
@@ -240,22 +238,6 @@ static cl::opt<bool> DisableLoopUnrolling(
"disable-loop-unrolling",
cl::desc("Disable loop unrolling in all relevant passes"), cl::init(false));
-bool OptDiagnosticHandler::handleDiagnostics(const DiagnosticInfo &DI) {
- DiagnosticHandler::handleDiagnostics(DI);
- // Mirror the filtering performed by LLVMContext::diagnose's default path:
- // optimization remarks are gated by the -pass-remarks* flags (isEnabled),
- // and verbose remarks additionally require hotness data.
- if (auto *Remark = dyn_cast<DiagnosticInfoOptimizationBase>(&DI))
- if (!Remark->isEnabled() || (Remark->isVerbose() && !Remark->getHotness()))
- return true;
-
- DiagnosticPrinterRawOStream DP(errs());
- errs() << LLVMContext::getDiagnosticMessagePrefix(DI.getSeverity()) << ": ";
- DI.print(DP);
- errs() << "\n";
- return true;
-}
-
template <typename PassManagerT>
bool tryParsePipelineText(PassBuilder &PB,
const cl::opt<std::string> &PipelineOpt) {
@@ -593,9 +575,10 @@ bool llvm::runPassPipeline(
// If a pass reported an error via LLVMContext::emitError, fail without
// writing the output module.
- if (auto *DH = M.getContext().getDiagHandlerPtr())
+ if (auto *DH = M.getContext().getDiagHandlerPtr()) {
if (DH->HasErrors)
return false;
+ }
// Declare success.
if (OK != OK_NoOutput) {
diff --git a/llvm/tools/opt/NewPMDriver.h b/llvm/tools/opt/NewPMDriver.h
index 0c60ace68c561..042d5d4bbfe47 100644
--- a/llvm/tools/opt/NewPMDriver.h
+++ b/llvm/tools/opt/NewPMDriver.h
@@ -20,7 +20,6 @@
#ifndef LLVM_TOOLS_OPT_NEWPMDRIVER_H
#define LLVM_TOOLS_OPT_NEWPMDRIVER_H
-#include "llvm/IR/DiagnosticHandler.h"
#include "llvm/Support/CommandLine.h"
namespace llvm {
@@ -32,15 +31,6 @@ class TargetMachine;
class ToolOutputFile;
class TargetLibraryInfoImpl;
-/// A custom diagnostic handler for opt that consumes diagnostics so that the
-/// default LLVMContext::diagnose() does not call exit() on the first error.
-/// opt can then drain remaining diagnostics from a single pass run and report
-/// them all, mirroring llc's behavior so that opt remains a faithful test
-/// driver for passes that report errors via LLVMContext::emitError.
-struct OptDiagnosticHandler : public DiagnosticHandler {
- bool handleDiagnostics(const DiagnosticInfo &DI) override;
-};
-
extern cl::opt<bool> DebugifyEach;
extern cl::opt<std::string> DebugifyExport;
diff --git a/llvm/tools/opt/optdriver.cpp b/llvm/tools/opt/optdriver.cpp
index 2e24c2e353ef1..3119db716d509 100644
--- a/llvm/tools/opt/optdriver.cpp
+++ b/llvm/tools/opt/optdriver.cpp
@@ -538,10 +538,6 @@ optMain(int argc, char **argv,
if (!DisableDITypeMap)
Context.enableDebugTypeODRUniquing();
- // Set a diagnostic handler that doesn't exit on the first error so that opt
- // can drain remaining diagnostics from a single pass run, mirroring llc.
- Context.setDiagnosticHandler(std::make_unique<OptDiagnosticHandler>());
-
Expected<LLVMRemarkFileHandle> RemarksFileOrErr =
setupLLVMOptimizationRemarks(Context, RemarksFilename, RemarksPasses,
RemarksFormat, RemarksWithHotness,
diff --git a/llvm/unittests/Analysis/MLModelRunnerTest.cpp b/llvm/unittests/Analysis/MLModelRunnerTest.cpp
index 3137455fdf3bd..62f90699c8718 100644
--- a/llvm/unittests/Analysis/MLModelRunnerTest.cpp
+++ b/llvm/unittests/Analysis/MLModelRunnerTest.cpp
@@ -12,6 +12,10 @@
#include "llvm/Analysis/NoInferenceModelRunner.h"
#include "llvm/Analysis/ReleaseModeModelRunner.h"
#include "llvm/Config/llvm-config.h" // for LLVM_ON_UNIX
+#include "llvm/IR/DiagnosticHandler.h"
+#include "llvm/IR/DiagnosticInfo.h"
+#include "llvm/IR/DiagnosticPrinter.h"
+#include "llvm/IR/LLVMContext.h"
#include "llvm/Support/BinaryByteStream.h"
#include "llvm/Support/ErrorHandling.h"
#include "llvm/Support/FileSystem.h"
@@ -192,10 +196,25 @@ TEST(ReleaseModeRunner, ExtraFeaturesOutOfOrder) {
EXPECT_EQ(*Evaluator->getTensor<int64_t>(2), -3);
}
+namespace {
+struct AbortOnErrorDiagnosticHandler : public DiagnosticHandler {
+ bool handleDiagnostics(const DiagnosticInfo &DI) override {
+ DiagnosticPrinterRawOStream DP(errs());
+ errs() << LLVMContext::getDiagnosticMessagePrefix(DI.getSeverity()) << ": ";
+ DI.print(DP);
+ errs() << '\n';
+ if (DI.getSeverity() == DS_Error)
+ std::abort();
+ return true;
+ }
+};
+} // namespace
+
// We expect an error to be reported early if the user tried to specify a model
// selector, but the model in fact doesn't support that.
TEST(ReleaseModelRunner, ModelSelectorNoInputFeaturePresent) {
LLVMContext Ctx;
+ Ctx.setDiagnosticHandler(std::make_unique<AbortOnErrorDiagnosticHandler>());
std::vector<TensorSpec> Inputs{TensorSpec::createSpec<int64_t>("a", {1}),
TensorSpec::createSpec<int64_t>("b", {1})};
EXPECT_DEATH((void)std::make_unique<ReleaseModeModelRunner<AdditionAOTModel>>(
@@ -206,6 +225,7 @@ TEST(ReleaseModelRunner, ModelSelectorNoInputFeaturePresent) {
TEST(ReleaseModelRunner, ModelSelectorNoSelectorGiven) {
LLVMContext Ctx;
+ Ctx.setDiagnosticHandler(std::make_unique<AbortOnErrorDiagnosticHandler>());
std::vector<TensorSpec> Inputs{TensorSpec::createSpec<int64_t>("a", {1}),
TensorSpec::createSpec<int64_t>("b", {1})};
EXPECT_DEATH(
>From 32191bea9a7aacbaabe644ea1f0c47e0e78aef07 Mon Sep 17 00:00:00 2001
From: Arseniy Obolenskiy <arseniy.obolenskiy at amd.com>
Date: Wed, 29 Apr 2026 20:05:04 +0200
Subject: [PATCH 3/4] Address review comments
---
llvm/include/llvm/Analysis/IR2Vec.h | 2 +-
llvm/lib/Analysis/IR2Vec.cpp | 23 ++++++++-----------
llvm/lib/Analysis/ReplayInlineAdvisor.cpp | 13 ++++-------
llvm/lib/Transforms/IPO/Inliner.cpp | 20 +++++++---------
llvm/test/Analysis/IR2Vec/basic-vocab.ll | 8 +++----
.../Transforms/Inline/cgscc-inline-replay.ll | 2 +-
.../Transforms/SampleProfile/inline-replay.ll | 2 +-
7 files changed, 29 insertions(+), 41 deletions(-)
diff --git a/llvm/include/llvm/Analysis/IR2Vec.h b/llvm/include/llvm/Analysis/IR2Vec.h
index 968873c918393..c2d5c7ca3c021 100644
--- a/llvm/include/llvm/Analysis/IR2Vec.h
+++ b/llvm/include/llvm/Analysis/IR2Vec.h
@@ -639,7 +639,7 @@ class LLVM_ABI FlowAwareEmbedder : public Embedder {
class IR2VecVocabAnalysis : public AnalysisInfoMixin<IR2VecVocabAnalysis> {
std::optional<ir2vec::VocabStorage> Vocab;
- void emitError(Error Err, LLVMContext &Ctx);
+ void emitError(Error Err);
public:
LLVM_ABI static AnalysisKey Key;
diff --git a/llvm/lib/Analysis/IR2Vec.cpp b/llvm/lib/Analysis/IR2Vec.cpp
index e24a08b3b8a65..b1c12ddf5be3d 100644
--- a/llvm/lib/Analysis/IR2Vec.cpp
+++ b/llvm/lib/Analysis/IR2Vec.cpp
@@ -632,34 +632,30 @@ Expected<Vocabulary> Vocabulary::fromFile(StringRef VocabFilePath,
// IR2VecVocabAnalysis
//===----------------------------------------------------------------------===//
-void IR2VecVocabAnalysis::emitError(Error Err, LLVMContext &Ctx) {
+void IR2VecVocabAnalysis::emitError(Error Err) {
handleAllErrors(std::move(Err), [&](const ErrorInfoBase &EI) {
- Ctx.emitError("Error reading vocabulary: " + EI.message());
+ reportFatalUsageError(Twine("Error reading vocabulary: ") + EI.message());
});
}
IR2VecVocabAnalysis::Result
IR2VecVocabAnalysis::run(Module &M, ModuleAnalysisManager &AM) {
- auto Ctx = &M.getContext();
// If vocabulary is already populated by the constructor, use it.
if (Vocab.has_value())
return Vocabulary(std::move(Vocab.value()));
// Otherwise, try to read from the vocabulary file specified via CLI.
- if (VocabFile.empty()) {
+ if (VocabFile.empty())
// FIXME: Use default vocabulary
- Ctx->emitError("IR2Vec vocabulary file path not specified; You may need to "
- "set it using --ir2vec-vocab-path");
- return Vocabulary(); // Return invalid result
- }
+ reportFatalUsageError(
+ "IR2Vec vocabulary file path not specified; You may need to "
+ "set it using --ir2vec-vocab-path");
// Use the static factory method to load the vocabulary.
auto VocabOrErr =
Vocabulary::fromFile(VocabFile, OpcWeight, TypeWeight, ArgWeight);
- if (!VocabOrErr) {
- emitError(VocabOrErr.takeError(), *Ctx);
- return Vocabulary();
- }
+ if (!VocabOrErr)
+ emitError(VocabOrErr.takeError());
return std::move(*VocabOrErr);
}
@@ -671,8 +667,7 @@ IR2VecVocabAnalysis::run(Module &M, ModuleAnalysisManager &AM) {
PreservedAnalyses IR2VecPrinterPass::run(Module &M,
ModuleAnalysisManager &MAM) {
auto &Vocabulary = MAM.getResult<IR2VecVocabAnalysis>(M);
- if (!Vocabulary.isValid())
- return PreservedAnalyses::all();
+ assert(Vocabulary.isValid() && "IR2Vec Vocabulary is invalid");
for (Function &F : M) {
auto Emb = Embedder::create(IR2VecEmbeddingKind, F, Vocabulary);
diff --git a/llvm/lib/Analysis/ReplayInlineAdvisor.cpp b/llvm/lib/Analysis/ReplayInlineAdvisor.cpp
index 6db5737ef4268..73149233abdf1 100644
--- a/llvm/lib/Analysis/ReplayInlineAdvisor.cpp
+++ b/llvm/lib/Analysis/ReplayInlineAdvisor.cpp
@@ -15,6 +15,7 @@
#include "llvm/Analysis/ReplayInlineAdvisor.h"
#include "llvm/Analysis/OptimizationRemarkEmitter.h"
+#include "llvm/Support/ErrorHandling.h"
#include "llvm/Support/LineIterator.h"
#include "llvm/Support/MemoryBuffer.h"
#include <memory>
@@ -33,10 +34,8 @@ ReplayInlineAdvisor::ReplayInlineAdvisor(
auto BufferOrErr = MemoryBuffer::getFileOrSTDIN(ReplaySettings.ReplayFile);
std::error_code EC = BufferOrErr.getError();
- if (EC) {
- Context.emitError("Could not open remarks file: " + EC.message());
- return;
- }
+ if (EC)
+ reportFatalUsageError("Could not open remarks file: " + Twine(EC.message()));
// Example for inline remarks to parse:
// main:3:1.1: '_Z3subii' inlined into 'main' at callsite sum:1 @
@@ -62,10 +61,8 @@ ReplayInlineAdvisor::ReplayInlineAdvisor(
auto CallSite = Pair.second.split(";").first;
- if (Callee.empty() || Caller.empty() || CallSite.empty()) {
- Context.emitError("Invalid remark format: " + Line);
- return;
- }
+ if (Callee.empty() || Caller.empty() || CallSite.empty())
+ reportFatalUsageError("Invalid remark format: " + Twine(Line));
std::string Combined = (Callee + CallSite).str();
InlineSitesFromRemarks[Combined] = IsPositiveRemark;
diff --git a/llvm/lib/Transforms/IPO/Inliner.cpp b/llvm/lib/Transforms/IPO/Inliner.cpp
index ed3fb61a1dfa9..7985e74cc5389 100644
--- a/llvm/lib/Transforms/IPO/Inliner.cpp
+++ b/llvm/lib/Transforms/IPO/Inliner.cpp
@@ -163,18 +163,14 @@ InlinerPass::getAdvisor(const ModuleAnalysisManagerCGSCCProxy::Result &MAM,
InlineContext{LTOPhase, InlinePass::CGSCCInliner});
if (!CGSCCInlineReplayFile.empty())
- if (auto ReplayAdvisor = getReplayInlineAdvisor(
- M, FAM, M.getContext(),
- std::make_unique<DefaultInlineAdvisor>(
- M, FAM, getInlineParams(),
- InlineContext{LTOPhase, InlinePass::CGSCCInliner}),
- ReplayInlinerSettings{CGSCCInlineReplayFile,
- CGSCCInlineReplayScope,
- CGSCCInlineReplayFallback,
- {CGSCCInlineReplayFormat}},
- /*EmitRemarks=*/true,
- InlineContext{LTOPhase, InlinePass::ReplayCGSCCInliner}))
- OwnedAdvisor = std::move(ReplayAdvisor);
+ OwnedAdvisor = getReplayInlineAdvisor(
+ M, FAM, M.getContext(), std::move(OwnedAdvisor),
+ ReplayInlinerSettings{CGSCCInlineReplayFile,
+ CGSCCInlineReplayScope,
+ CGSCCInlineReplayFallback,
+ {CGSCCInlineReplayFormat}},
+ /*EmitRemarks=*/true,
+ InlineContext{LTOPhase, InlinePass::ReplayCGSCCInliner});
return *OwnedAdvisor;
}
diff --git a/llvm/test/Analysis/IR2Vec/basic-vocab.ll b/llvm/test/Analysis/IR2Vec/basic-vocab.ll
index eeeee831814a8..78b5ae0b5001e 100644
--- a/llvm/test/Analysis/IR2Vec/basic-vocab.ll
+++ b/llvm/test/Analysis/IR2Vec/basic-vocab.ll
@@ -18,10 +18,10 @@ entry:
ret float %add
}
-; INCORRECT-VOCAB1-CHECK: error: Error reading vocabulary: Missing 'Opcodes' section in vocabulary file
+; INCORRECT-VOCAB1-CHECK: LLVM ERROR: Error reading vocabulary: Missing 'Opcodes' section in vocabulary file
-; INCORRECT-VOCAB2-CHECK: error: Error reading vocabulary: Missing 'Types' section in vocabulary file
+; INCORRECT-VOCAB2-CHECK: LLVM ERROR: Error reading vocabulary: Missing 'Types' section in vocabulary file
-; INCORRECT-VOCAB3-CHECK: error: Error reading vocabulary: Missing 'Arguments' section in vocabulary file
+; INCORRECT-VOCAB3-CHECK: LLVM ERROR: Error reading vocabulary: Missing 'Arguments' section in vocabulary file
-; INCORRECT-VOCAB4-CHECK: error: Error reading vocabulary: Vocabulary sections have different dimensions
+; INCORRECT-VOCAB4-CHECK: LLVM ERROR: Error reading vocabulary: Vocabulary sections have different dimensions
diff --git a/llvm/test/Transforms/Inline/cgscc-inline-replay.ll b/llvm/test/Transforms/Inline/cgscc-inline-replay.ll
index eae1437ef0e33..5df4c89a74616 100644
--- a/llvm/test/Transforms/Inline/cgscc-inline-replay.ll
+++ b/llvm/test/Transforms/Inline/cgscc-inline-replay.ll
@@ -59,7 +59,7 @@
; REPLAY-FUNCTION-NEVER: '_Z3subii' inlined into '_Z3sumii' with (cost={{[-0-9]+}}
; REPLAY-FUNCTION-NEVER-NOT: '_Z3sumii' inlined into 'main'
-; REPLAY-ERROR: error: Could not open remarks file:
+; REPLAY-ERROR: LLVM ERROR: Could not open remarks file:
; REPLAY-ERROR-SCOPE: for the --cgscc-inline-replay-scope option: Cannot find option named 'function'!
; REPLAY-ERROR-FALLBACK: for the --cgscc-inline-replay-fallback option: Cannot find option named 'original'!
; REPLAY-ERROR-FORMAT: for the --cgscc-inline-replay-format option: Cannot find option named 'line'!
diff --git a/llvm/test/Transforms/SampleProfile/inline-replay.ll b/llvm/test/Transforms/SampleProfile/inline-replay.ll
index 56a3e6fe7eb8f..f655defbc91b7 100644
--- a/llvm/test/Transforms/SampleProfile/inline-replay.ll
+++ b/llvm/test/Transforms/SampleProfile/inline-replay.ll
@@ -98,7 +98,7 @@
; REPLAY-ALL-FUNCTION-ALWAYS: '_Z3subii' inlined into 'main' to match profiling context with (cost=always)
; REPLAY-ALL-FUNCTION-ALWAYS: '_Z3subii' inlined into '_Z3sumii' to match profiling context with (cost={{[-0-9]+}}
-; REPLAY-ERROR: error: Could not open remarks file:
+; REPLAY-ERROR: LLVM ERROR: Could not open remarks file:
; REPLAY-ERROR-SCOPE: for the --sample-profile-inline-replay-scope option: Cannot find option named 'function'!
; REPLAY-ERROR-FALLBACK: for the --sample-profile-inline-replay-fallback option: Cannot find option named 'original'!
; REPLAY-ERROR-FORMAT: for the --sample-profile-inline-replay-format option: Cannot find option named 'line'!
>From a03d47cde78755e33308cf2070fe83158e15d88a Mon Sep 17 00:00:00 2001
From: Arseniy Obolenskiy <arseniy.obolenskiy at amd.com>
Date: Thu, 30 Apr 2026 06:34:15 +0200
Subject: [PATCH 4/4] Lowercase for error messages + fmt fix
---
llvm/lib/Analysis/IR2Vec.cpp | 2 +-
llvm/lib/Analysis/ReplayInlineAdvisor.cpp | 5 +++--
llvm/test/Analysis/IR2Vec/basic-vocab.ll | 8 ++++----
llvm/test/Transforms/Inline/cgscc-inline-replay.ll | 2 +-
llvm/test/Transforms/SampleProfile/inline-replay.ll | 2 +-
5 files changed, 10 insertions(+), 9 deletions(-)
diff --git a/llvm/lib/Analysis/IR2Vec.cpp b/llvm/lib/Analysis/IR2Vec.cpp
index b1c12ddf5be3d..07d0c372cabcc 100644
--- a/llvm/lib/Analysis/IR2Vec.cpp
+++ b/llvm/lib/Analysis/IR2Vec.cpp
@@ -634,7 +634,7 @@ Expected<Vocabulary> Vocabulary::fromFile(StringRef VocabFilePath,
void IR2VecVocabAnalysis::emitError(Error Err) {
handleAllErrors(std::move(Err), [&](const ErrorInfoBase &EI) {
- reportFatalUsageError(Twine("Error reading vocabulary: ") + EI.message());
+ reportFatalUsageError(Twine("error reading vocabulary: ") + EI.message());
});
}
diff --git a/llvm/lib/Analysis/ReplayInlineAdvisor.cpp b/llvm/lib/Analysis/ReplayInlineAdvisor.cpp
index 73149233abdf1..7253478a0eedf 100644
--- a/llvm/lib/Analysis/ReplayInlineAdvisor.cpp
+++ b/llvm/lib/Analysis/ReplayInlineAdvisor.cpp
@@ -35,7 +35,8 @@ ReplayInlineAdvisor::ReplayInlineAdvisor(
auto BufferOrErr = MemoryBuffer::getFileOrSTDIN(ReplaySettings.ReplayFile);
std::error_code EC = BufferOrErr.getError();
if (EC)
- reportFatalUsageError("Could not open remarks file: " + Twine(EC.message()));
+ reportFatalUsageError("could not open remarks file: " +
+ Twine(EC.message()));
// Example for inline remarks to parse:
// main:3:1.1: '_Z3subii' inlined into 'main' at callsite sum:1 @
@@ -62,7 +63,7 @@ ReplayInlineAdvisor::ReplayInlineAdvisor(
auto CallSite = Pair.second.split(";").first;
if (Callee.empty() || Caller.empty() || CallSite.empty())
- reportFatalUsageError("Invalid remark format: " + Twine(Line));
+ reportFatalUsageError("invalid remark format: " + Twine(Line));
std::string Combined = (Callee + CallSite).str();
InlineSitesFromRemarks[Combined] = IsPositiveRemark;
diff --git a/llvm/test/Analysis/IR2Vec/basic-vocab.ll b/llvm/test/Analysis/IR2Vec/basic-vocab.ll
index 78b5ae0b5001e..af5633b3c0596 100644
--- a/llvm/test/Analysis/IR2Vec/basic-vocab.ll
+++ b/llvm/test/Analysis/IR2Vec/basic-vocab.ll
@@ -18,10 +18,10 @@ entry:
ret float %add
}
-; INCORRECT-VOCAB1-CHECK: LLVM ERROR: Error reading vocabulary: Missing 'Opcodes' section in vocabulary file
+; INCORRECT-VOCAB1-CHECK: LLVM ERROR: error reading vocabulary: Missing 'Opcodes' section in vocabulary file
-; INCORRECT-VOCAB2-CHECK: LLVM ERROR: Error reading vocabulary: Missing 'Types' section in vocabulary file
+; INCORRECT-VOCAB2-CHECK: LLVM ERROR: error reading vocabulary: Missing 'Types' section in vocabulary file
-; INCORRECT-VOCAB3-CHECK: LLVM ERROR: Error reading vocabulary: Missing 'Arguments' section in vocabulary file
+; INCORRECT-VOCAB3-CHECK: LLVM ERROR: error reading vocabulary: Missing 'Arguments' section in vocabulary file
-; INCORRECT-VOCAB4-CHECK: LLVM ERROR: Error reading vocabulary: Vocabulary sections have different dimensions
+; INCORRECT-VOCAB4-CHECK: LLVM ERROR: error reading vocabulary: Vocabulary sections have different dimensions
diff --git a/llvm/test/Transforms/Inline/cgscc-inline-replay.ll b/llvm/test/Transforms/Inline/cgscc-inline-replay.ll
index 5df4c89a74616..59e71f8ce4dd1 100644
--- a/llvm/test/Transforms/Inline/cgscc-inline-replay.ll
+++ b/llvm/test/Transforms/Inline/cgscc-inline-replay.ll
@@ -59,7 +59,7 @@
; REPLAY-FUNCTION-NEVER: '_Z3subii' inlined into '_Z3sumii' with (cost={{[-0-9]+}}
; REPLAY-FUNCTION-NEVER-NOT: '_Z3sumii' inlined into 'main'
-; REPLAY-ERROR: LLVM ERROR: Could not open remarks file:
+; REPLAY-ERROR: LLVM ERROR: could not open remarks file:
; REPLAY-ERROR-SCOPE: for the --cgscc-inline-replay-scope option: Cannot find option named 'function'!
; REPLAY-ERROR-FALLBACK: for the --cgscc-inline-replay-fallback option: Cannot find option named 'original'!
; REPLAY-ERROR-FORMAT: for the --cgscc-inline-replay-format option: Cannot find option named 'line'!
diff --git a/llvm/test/Transforms/SampleProfile/inline-replay.ll b/llvm/test/Transforms/SampleProfile/inline-replay.ll
index f655defbc91b7..d8bd33ac31bbc 100644
--- a/llvm/test/Transforms/SampleProfile/inline-replay.ll
+++ b/llvm/test/Transforms/SampleProfile/inline-replay.ll
@@ -98,7 +98,7 @@
; REPLAY-ALL-FUNCTION-ALWAYS: '_Z3subii' inlined into 'main' to match profiling context with (cost=always)
; REPLAY-ALL-FUNCTION-ALWAYS: '_Z3subii' inlined into '_Z3sumii' to match profiling context with (cost={{[-0-9]+}}
-; REPLAY-ERROR: LLVM ERROR: Could not open remarks file:
+; REPLAY-ERROR: LLVM ERROR: could not open remarks file:
; REPLAY-ERROR-SCOPE: for the --sample-profile-inline-replay-scope option: Cannot find option named 'function'!
; REPLAY-ERROR-FALLBACK: for the --sample-profile-inline-replay-fallback option: Cannot find option named 'original'!
; REPLAY-ERROR-FORMAT: for the --sample-profile-inline-replay-format option: Cannot find option named 'line'!
More information about the llvm-commits
mailing list