diff --git a/llvm/lib/IR/LLVMContext.cpp b/llvm/lib/IR/LLVMContext.cpp index 57532cd491dd6..94257a101db51 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 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: @@ -242,6 +266,19 @@ LLVMContext::getDiagnosticMessagePrefix(DiagnosticSeverity Severity) { llvm_unreachable("Unknown DiagnosticSeverity"); } +static void handleHaltOnFirstDiagError() { + switch (opts::HaltOnFirstDiagErrorOpt) { + case opts::HaltOnFirstDiagErrorAction::Exit: + std::exit(1); + break; + case opts::HaltOnFirstDiagErrorAction::Abort: + std::abort(); + break; + default: + break; + } +} + void LLVMContext::diagnose(const DiagnosticInfo &DI) { if (auto *OptDiagBase = dyn_cast(&DI)) if (LLVMRemarkStreamer *RS = getLLVMRemarkStreamer()) @@ -264,8 +301,10 @@ 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) { + handleHaltOnFirstDiagError(); + } } //===----------------------------------------------------------------------===// 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: :0:0: in function illegal_vgpr_to_sgpr_copy_i32 void (): illegal VGPR to SGPR copy +; FIRST-ERROR: error: :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: :0:0: in function illegal_vgpr_to_sgpr_copy_v2i32 void (): illegal VGPR to SGPR copy +; FIRST-ERROR-NOT: error: :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 PassPipeline( static cl::alias PassPipeline2("p", cl::aliasopt(PassPipeline), cl::desc("Alias for -passes")); +static cl::opt + NoDiagHandler("no-diag-handler", + cl::desc("Do not load the llc-specific diagnostic handler."), + cl::init(false), cl::Hidden); + namespace { std::vector &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()); + if (!NoDiagHandler) { + // Set a diagnostic handler that doesn't exit on the first error + Context.setDiagnosticHandler(std::make_unique()); + } Expected> RemarksFileOrErr = setupLLVMOptimizationRemarks(Context, RemarksFilename, RemarksPasses,