[lld] [clang] [llvm] [LTO] Improve diagnostics handling when parsing module-level inline assembly (PR #75726)
https://github.com/yuanfang-chen approved this pull request. LGTM https://github.com/llvm/llvm-project/pull/75726 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [llvm] [LTO] Improve diagnostics handling when parsing module-level inline assembly (PR #75726)
yuanfang-chen wrote: `MachO/lto-module-asm-err.ll` needs update? https://github.com/llvm/llvm-project/pull/75726 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [llvm] [LTO] Improve diagnostics handling when parsing module-level inline assembly (PR #75726)
llvmbot wrote: @llvm/pr-subscribers-clang Author: Fangrui Song (MaskRay) Changes Non-LTO compiles set the buffer name to "" (`AsmPrinter::addInlineAsmDiagBuffer`) and pass diagnostics to `ClangDiagnosticHandler` (through the `MCContext` handler in `MachineModuleInfoWrapperPass::doInitialization`) to ensure that the exit code is 1 in the presence of errors. In contrast, LTO compiles spuriously succeed even if error messages are printed. ``` % cat a.c void _start() {} asm("unknown instruction"); % clang -c a.c :1:1: error: invalid instruction mnemonic 'unknown' 1 | unknown instruction | ^ 1 error generated. % clang -c -flto a.c; echo $? # -flto=thin is the same error: invalid instruction mnemonic 'unknown' unknown instruction ^~~ error: invalid instruction mnemonic 'unknown' unknown instruction ^~~ 0 ``` `CollectAsmSymbols` parses inline assembly and is transitively called by both `ModuleSummaryIndexAnalysis::run` and `WriteBitcodeToFile`, leading to duplicate diagnostics. This patch updates `CollectAsmSymbols` to be similar to non-LTO compiles. ``` % clang -c -flto=thin a.c; echo $? :1:1: error: invalid instruction mnemonic 'unknown' 1 | unknown instruction | ^ 1 errors generated. 1 ``` The `HasErrors` check does not prevent duplicate warnings but assembler warnings are very uncommon. --- Full diff: https://github.com/llvm/llvm-project/pull/75726.diff 4 Files Affected: - (modified) clang/lib/CodeGen/CodeGenAction.cpp (+2) - (modified) clang/test/CodeGen/invalid_global_asm.c (+5) - (modified) llvm/include/llvm/IR/DiagnosticHandler.h (+1) - (modified) llvm/lib/Object/ModuleSymbolTable.cpp (+15-1) ``diff diff --git a/clang/lib/CodeGen/CodeGenAction.cpp b/clang/lib/CodeGen/CodeGenAction.cpp index 753a8fd74fa696..4121a3709bc3af 100644 --- a/clang/lib/CodeGen/CodeGenAction.cpp +++ b/clang/lib/CodeGen/CodeGenAction.cpp @@ -418,6 +418,8 @@ void BackendConsumer::anchor() { } } // namespace clang bool ClangDiagnosticHandler::handleDiagnostics(const DiagnosticInfo &DI) { + if (DI.getSeverity() == DS_Error) +HasErrors = true; BackendCon->DiagnosticHandlerImpl(DI); return true; } diff --git a/clang/test/CodeGen/invalid_global_asm.c b/clang/test/CodeGen/invalid_global_asm.c index 5b7e8b43d752d8..d5645f7fc92bf4 100644 --- a/clang/test/CodeGen/invalid_global_asm.c +++ b/clang/test/CodeGen/invalid_global_asm.c @@ -1,5 +1,10 @@ // REQUIRES: arm-registered-target // RUN: not %clang_cc1 -emit-obj -triple armv6-unknown-unknown -o %t %s 2>&1 | FileCheck %s +// RUN: not %clang_cc1 -emit-obj -triple armv6-unknown-unknown -flto -o %t %s 2>&1 | FileCheck %s + +/// Test the diagnostic behavior considering the whole system including the driver. +// RUN: not %clang --target=armv6-unknown-unknown -c -flto=thin -o %t %s 2>&1 | FileCheck %s #pragma clang diagnostic ignored "-Wmissing-noreturn" __asm__(".Lfoo: movw r2, #:lower16:.Lbar - .Lfoo"); // CHECK: :1:8: error: instruction requires: armv6t2 +// CHECK-NOT: error: diff --git a/llvm/include/llvm/IR/DiagnosticHandler.h b/llvm/include/llvm/IR/DiagnosticHandler.h index 55e5e5975808d9..db7d7444f75f05 100644 --- a/llvm/include/llvm/IR/DiagnosticHandler.h +++ b/llvm/include/llvm/IR/DiagnosticHandler.h @@ -23,6 +23,7 @@ class DiagnosticInfo; /// which remarks are enabled. struct DiagnosticHandler { void *DiagnosticContext = nullptr; + bool HasErrors = false; DiagnosticHandler(void *DiagContext = nullptr) : DiagnosticContext(DiagContext) {} virtual ~DiagnosticHandler() = default; diff --git a/llvm/lib/Object/ModuleSymbolTable.cpp b/llvm/lib/Object/ModuleSymbolTable.cpp index ab073e18cb4668..07f76688fa43e7 100644 --- a/llvm/lib/Object/ModuleSymbolTable.cpp +++ b/llvm/lib/Object/ModuleSymbolTable.cpp @@ -16,6 +16,7 @@ #include "RecordStreamer.h" #include "llvm/ADT/STLExtras.h" #include "llvm/ADT/StringRef.h" +#include "llvm/IR/DiagnosticInfo.h" #include "llvm/IR/Function.h" #include "llvm/IR/GlobalAlias.h" #include "llvm/IR/GlobalValue.h" @@ -68,6 +69,11 @@ void ModuleSymbolTable::addModule(Module *M) { static void initializeRecordStreamer(const Module &M, function_ref Init) { + // This function may be called twice, once for ModuleSummaryIndexAnalysis and + // the other when writing the IR symbol table. If parsing inline assembly has + // caused errors in the first run, suppress the second run. + if (M.getContext().getDiagHandlerPtr()->HasErrors) +return; StringRef InlineAsm = M.getModuleInlineAsm(); if (InlineAsm.empty()) return; @@ -95,7 +101,8 @@ initializeRecordStreamer(const Module &M, if (!MCII) return; - std::unique_ptr Buffer(MemoryBuffer::getMemBuffer(InlineAsm)); + std::unique_ptr Buffer( + MemoryBuffer::getMemBuffer(InlineAsm, "")); SourceMgr SrcMgr; SrcMgr.AddNewSourceBuffer(std::move(Buffer), SMLoc()); @@ -115,6 +122,13 @@ initializeRecordStreamer(const Module &M,
[clang] [llvm] [LTO] Improve diagnostics handling when parsing module-level inline assembly (PR #75726)
https://github.com/MaskRay created https://github.com/llvm/llvm-project/pull/75726 Non-LTO compiles set the buffer name to "" (`AsmPrinter::addInlineAsmDiagBuffer`) and pass diagnostics to `ClangDiagnosticHandler` (through the `MCContext` handler in `MachineModuleInfoWrapperPass::doInitialization`) to ensure that the exit code is 1 in the presence of errors. In contrast, LTO compiles spuriously succeed even if error messages are printed. ``` % cat a.c void _start() {} asm("unknown instruction"); % clang -c a.c :1:1: error: invalid instruction mnemonic 'unknown' 1 | unknown instruction | ^ 1 error generated. % clang -c -flto a.c; echo $? # -flto=thin is the same error: invalid instruction mnemonic 'unknown' unknown instruction ^~~ error: invalid instruction mnemonic 'unknown' unknown instruction ^~~ 0 ``` `CollectAsmSymbols` parses inline assembly and is transitively called by both `ModuleSummaryIndexAnalysis::run` and `WriteBitcodeToFile`, leading to duplicate diagnostics. This patch updates `CollectAsmSymbols` to be similar to non-LTO compiles. ``` % clang -c -flto=thin a.c; echo $? :1:1: error: invalid instruction mnemonic 'unknown' 1 | unknown instruction | ^ 1 errors generated. 1 ``` The `HasErrors` check does not prevent duplicate warnings but assembler warnings are very uncommon. >From ddce8597697261dd48ffd81761518496d391b55e Mon Sep 17 00:00:00 2001 From: Fangrui Song Date: Sun, 10 Dec 2023 10:13:59 -0800 Subject: [PATCH] [LTO] Improve diagnostics handling when parsing module-level inline assembly Non-LTO compiles set the buffer name to "" (`AsmPrinter::addInlineAsmDiagBuffer`) and pass diagnostics to `ClangDiagnosticHandler` (through the `MCContext` handler in `MachineModuleInfoWrapperPass::doInitialization`) to ensure that the exit code is 1 in the presence of errors. In contrast, LTO compiles spuriously succeed even if error messages are printed. ``` % cat a.c void _start() {} asm("unknown instruction"); % clang -c a.c :1:1: error: invalid instruction mnemonic 'unknown' 1 | unknown instruction | ^ 1 error generated. % clang -c -flto a.c; echo $? # -flto=thin is the same error: invalid instruction mnemonic 'unknown' unknown instruction ^~~ error: invalid instruction mnemonic 'unknown' unknown instruction ^~~ 0 ``` `CollectAsmSymbols` parses inline assembly and is transitively called by both `ModuleSummaryIndexAnalysis::run` and `WriteBitcodeToFile`, leading to duplicate diagnostics. This patch updates `CollectAsmSymbols` to be similar to non-LTO compiles. ``` % clang -c -flto=thin a.c; echo $? :1:1: error: invalid instruction mnemonic 'unknown' 1 | unknown instruction | ^ 1 errors generated. 1 ``` The `HasErrors` check does not prevent duplicate warnings but assembler warnings are very uncommon. --- clang/lib/CodeGen/CodeGenAction.cpp | 2 ++ clang/test/CodeGen/invalid_global_asm.c | 5 + llvm/include/llvm/IR/DiagnosticHandler.h | 1 + llvm/lib/Object/ModuleSymbolTable.cpp| 16 +++- 4 files changed, 23 insertions(+), 1 deletion(-) diff --git a/clang/lib/CodeGen/CodeGenAction.cpp b/clang/lib/CodeGen/CodeGenAction.cpp index 753a8fd74fa696..4121a3709bc3af 100644 --- a/clang/lib/CodeGen/CodeGenAction.cpp +++ b/clang/lib/CodeGen/CodeGenAction.cpp @@ -418,6 +418,8 @@ void BackendConsumer::anchor() { } } // namespace clang bool ClangDiagnosticHandler::handleDiagnostics(const DiagnosticInfo &DI) { + if (DI.getSeverity() == DS_Error) +HasErrors = true; BackendCon->DiagnosticHandlerImpl(DI); return true; } diff --git a/clang/test/CodeGen/invalid_global_asm.c b/clang/test/CodeGen/invalid_global_asm.c index 5b7e8b43d752d8..d5645f7fc92bf4 100644 --- a/clang/test/CodeGen/invalid_global_asm.c +++ b/clang/test/CodeGen/invalid_global_asm.c @@ -1,5 +1,10 @@ // REQUIRES: arm-registered-target // RUN: not %clang_cc1 -emit-obj -triple armv6-unknown-unknown -o %t %s 2>&1 | FileCheck %s +// RUN: not %clang_cc1 -emit-obj -triple armv6-unknown-unknown -flto -o %t %s 2>&1 | FileCheck %s + +/// Test the diagnostic behavior considering the whole system including the driver. +// RUN: not %clang --target=armv6-unknown-unknown -c -flto=thin -o %t %s 2>&1 | FileCheck %s #pragma clang diagnostic ignored "-Wmissing-noreturn" __asm__(".Lfoo: movw r2, #:lower16:.Lbar - .Lfoo"); // CHECK: :1:8: error: instruction requires: armv6t2 +// CHECK-NOT: error: diff --git a/llvm/include/llvm/IR/DiagnosticHandler.h b/llvm/include/llvm/IR/DiagnosticHandler.h index 55e5e5975808d9..db7d7444f75f05 100644 --- a/llvm/include/llvm/IR/DiagnosticHandler.h +++ b/llvm/include/llvm/IR/DiagnosticHandler.h @@ -23,6 +23,7 @@ class DiagnosticInfo; /// which remarks are enabled. struct DiagnosticHandler { void *DiagnosticContext = nullptr; + bool HasErrors = false; DiagnosticHandler(void *DiagContext = nullptr) : DiagnosticContext(DiagContext) {} virtual ~DiagnosticHandler() = default; diff --git a/llvm/lib/Obj