[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