[llvm] [LLVM] Parametrize hardcoded behaviors in diagnostics error handling. (PR #156439)

Manuel Carrasco via llvm-commits llvm-commits at lists.llvm.org
Tue Sep 2 03:43:21 PDT 2025


https://github.com/mgcarrasco created https://github.com/llvm/llvm-project/pull/156439

This PR introduces flexibility in configuring diagnostic error handling, previously hardcoded. The introduced changes are as follows:

1. Configurable Exit Behavior: The behavior when encountering the first unhandled diagnostic error is now customizable with `-halt-on-first-diag-error=[exit,abort,none]`. The default remains as exit, which preserves existing behavior.
2. Diagnostic Handler Toggling in llc: The llc tool's diagnostic error handler, which prints all errors, can now be toggled (`-no-diag-handler`). By default, it continues to load as before, ensuring no change to current behavior.

These changes aim to add flexibility while ensuring that default settings do not alter the current behavior of diagnostic error handling.

Motivation:

Providing the option to generate a stack trace on the first diagnostic error is key for fuzzing, as stack traces can help deduplicate test cases. Capturing the stack trace right when the diagnostic error occurs allows a more precise identification.



>From 4410a408b42d58410190e142751eff6bc1cfbb7b Mon Sep 17 00:00:00 2001
From: Manuel Carrasco <Manuel.Carrasco at amd.com>
Date: Tue, 2 Sep 2025 03:16:15 -0700
Subject: [PATCH 1/2] [LLVM] Introduce configurable halt actions on first
 unhandled diagnostic error

---
 llvm/lib/IR/LLVMContext.cpp | 39 +++++++++++++++++++++++++++++++++++--
 1 file changed, 37 insertions(+), 2 deletions(-)

diff --git a/llvm/lib/IR/LLVMContext.cpp b/llvm/lib/IR/LLVMContext.cpp
index 57532cd491dd6..58b33cc852064 100644
--- a/llvm/lib/IR/LLVMContext.cpp
+++ b/llvm/lib/IR/LLVMContext.cpp
@@ -31,6 +31,30 @@
 
 using namespace llvm;
 
+namespace opts {
+
+enum class HaltOnFirstDiagErrorAction {
+  Exit,
+  Abort,
+  None,
+};
+
+static cl::opt<HaltOnFirstDiagErrorAction> HaltOnFirstDiagErrorOpt(
+    "halt-on-first-diag-error",
+    cl::desc(
+        "Halt action to take on the first unhandled diagnostic error reported"),
+    cl::values(
+        clEnumValN(
+            HaltOnFirstDiagErrorAction::Exit, "exit",
+            "Exit with error code 1 on first diagnostic with error severity"),
+        clEnumValN(HaltOnFirstDiagErrorAction::Abort, "abort",
+                   "Abort with a stacktrace immediately on first diagnostic "
+                   "with error severity"),
+        clEnumValN(HaltOnFirstDiagErrorAction::None, "none",
+                   "Do not halt on first diagnostic with error severity")),
+    cl::init(HaltOnFirstDiagErrorAction::Exit), cl::Hidden);
+} // namespace opts
+
 static StringRef knownBundleName(unsigned BundleTagID) {
   switch (BundleTagID) {
   case LLVMContext::OB_deopt:
@@ -264,8 +288,19 @@ void LLVMContext::diagnose(const DiagnosticInfo &DI) {
   errs() << getDiagnosticMessagePrefix(DI.getSeverity()) << ": ";
   DI.print(DP);
   errs() << "\n";
-  if (DI.getSeverity() == DS_Error)
-    exit(1);
+
+  if (DI.getSeverity() == DS_Error) {
+    switch (opts::HaltOnFirstDiagErrorOpt) {
+    case opts::HaltOnFirstDiagErrorAction::Exit:
+      exit(1);
+      break;
+    case opts::HaltOnFirstDiagErrorAction::Abort:
+      abort();
+      break;
+    case opts::HaltOnFirstDiagErrorAction::None:
+      break;
+    }
+  }
 }
 
 //===----------------------------------------------------------------------===//

>From 6b1fa864c0f3812b5945b4bfeea0f1a7718458ae Mon Sep 17 00:00:00 2001
From: Manuel Carrasco <Manuel.Carrasco at amd.com>
Date: Tue, 2 Sep 2025 03:18:04 -0700
Subject: [PATCH 2/2] [llc] Add option to disable llc-specific diagnostic
 handler

---
 llvm/test/tools/llc/no-diagnostic-handler.ll | 25 ++++++++++++++++++++
 llvm/tools/llc/llc.cpp                       | 11 +++++++--
 2 files changed, 34 insertions(+), 2 deletions(-)
 create mode 100644 llvm/test/tools/llc/no-diagnostic-handler.ll

diff --git a/llvm/test/tools/llc/no-diagnostic-handler.ll b/llvm/test/tools/llc/no-diagnostic-handler.ll
new file mode 100644
index 0000000000000..72f4b3cd2b4a2
--- /dev/null
+++ b/llvm/test/tools/llc/no-diagnostic-handler.ll
@@ -0,0 +1,25 @@
+; COM: Test that the default behavior persists (the llc-specific handler prints all errors).
+; RUN: not llc -mtriple=amdgcn -verify-machineinstrs=0 -global-isel=false < %s 2>&1 | FileCheck -check-prefix=ALL-ERRORS %s
+; COM: Do not halt on the first error when the llc-specific handler is not loaded.
+; RUN: not llc -mtriple=amdgcn -verify-machineinstrs=0 -global-isel=false -no-diag-handler -halt-on-first-diag-error=none < %s 2>&1 | FileCheck -check-prefix=ALL-ERRORS %s
+
+; COM: Now halt on the first error by disabling the llc-specific handler and test the different halt actions
+; RUN: not llc -mtriple=amdgcn -verify-machineinstrs=0 -global-isel=false -no-diag-handler -halt-on-first-diag-error=exit < %s 2>&1 | FileCheck -check-prefix=FIRST-ERROR %s
+; COM: Same error message as in -halt-on-first-diag-error=exit but with a crash.
+; RUN: not --crash llc -mtriple=amdgcn -verify-machineinstrs=0 -global-isel=false -no-diag-handler -halt-on-first-diag-error=abort < %s 2>&1 | FileCheck -check-prefix=FIRST-ERROR %s
+
+; ALL-ERRORS: error: <unknown>:0:0: in function illegal_vgpr_to_sgpr_copy_i32 void (): illegal VGPR to SGPR copy
+; FIRST-ERROR: error: <unknown>:0:0: in function illegal_vgpr_to_sgpr_copy_i32 void (): illegal VGPR to SGPR copy
+define amdgpu_kernel void @illegal_vgpr_to_sgpr_copy_i32() #0 {
+  %vgpr = call i32 asm sideeffect "; def $0", "=${v1}"()
+  call void asm sideeffect "; use $0", "${s9}"(i32 %vgpr)
+  ret void
+}
+
+; ALL-ERRORS: error: <unknown>:0:0: in function illegal_vgpr_to_sgpr_copy_v2i32 void (): illegal VGPR to SGPR copy
+; FIRST-ERROR-NOT: error: <unknown>:0:0: in function illegal_vgpr_to_sgpr_copy_v2i32 void (): illegal VGPR to SGPR copy
+define amdgpu_kernel void @illegal_vgpr_to_sgpr_copy_v2i32() #0 {
+  %vgpr = call <2 x i32> asm sideeffect "; def $0", "=${v[0:1]}"()
+  call void asm sideeffect "; use $0", "${s[10:11]}"(<2 x i32> %vgpr)
+  ret void
+}
diff --git a/llvm/tools/llc/llc.cpp b/llvm/tools/llc/llc.cpp
index b3d7185e7f144..06be15500028a 100644
--- a/llvm/tools/llc/llc.cpp
+++ b/llvm/tools/llc/llc.cpp
@@ -213,6 +213,11 @@ static cl::opt<std::string> PassPipeline(
 static cl::alias PassPipeline2("p", cl::aliasopt(PassPipeline),
                                cl::desc("Alias for -passes"));
 
+static cl::opt<bool>
+    NoDiagHandler("no-diag-handler",
+                  cl::desc("Do not load the llc-specific diagnostic handler."),
+                  cl::init(false), cl::Hidden);
+
 namespace {
 
 std::vector<std::string> &getRunPassNames() {
@@ -384,8 +389,10 @@ int main(int argc, char **argv) {
   LLVMContext Context;
   Context.setDiscardValueNames(DiscardValueNames);
 
-  // Set a diagnostic handler that doesn't exit on the first error
-  Context.setDiagnosticHandler(std::make_unique<LLCDiagnosticHandler>());
+  if (!NoDiagHandler) {
+    // Set a diagnostic handler that doesn't exit on the first error
+    Context.setDiagnosticHandler(std::make_unique<LLCDiagnosticHandler>());
+  }
 
   Expected<std::unique_ptr<ToolOutputFile>> RemarksFileOrErr =
       setupLLVMOptimizationRemarks(Context, RemarksFilename, RemarksPasses,



More information about the llvm-commits mailing list