[llvm-branch-commits] [clang] [llvm] [Instrumentor] Add unreachable support; unreachable stack trace printing (PR #195408)
Johannes Doerfert via llvm-branch-commits
llvm-branch-commits at lists.llvm.org
Thu May 7 19:47:20 PDT 2026
https://github.com/jdoerfert updated https://github.com/llvm/llvm-project/pull/195408
>From fbbd98d9d7c10a40ce23db795aabbe1d084764d2 Mon Sep 17 00:00:00 2001
From: Johannes Doerfert <jdoerfert.llvm at gmail.com>
Date: Fri, 1 May 2026 21:21:25 -0700
Subject: [PATCH] [Instrumentor] Add unreachable support; unreachable stack
trace printing
Allow to instrument unreachable and provide a use case for stack trace
printing.
---
.../Instrumentor/InstrumentorUnreachable.cpp | 20 ++++++++++++++++++
clang/test/Instrumentor/UnreachableRT.cpp | 21 +++++++++++++++++++
clang/test/Instrumentor/UnreachableRT.json | 15 +++++++++++++
clang/test/Instrumentor/lit.local.cfg | 6 +++++-
.../llvm/Transforms/IPO/Instrumentor.h | 21 +++++++++++++++++++
llvm/lib/Transforms/IPO/Instrumentor.cpp | 12 +++++++++++
.../Instrumentor/default_config.json | 5 +++++
7 files changed, 99 insertions(+), 1 deletion(-)
create mode 100644 clang/test/Instrumentor/InstrumentorUnreachable.cpp
create mode 100644 clang/test/Instrumentor/UnreachableRT.cpp
create mode 100644 clang/test/Instrumentor/UnreachableRT.json
diff --git a/clang/test/Instrumentor/InstrumentorUnreachable.cpp b/clang/test/Instrumentor/InstrumentorUnreachable.cpp
new file mode 100644
index 0000000000000..0caf07a1e9496
--- /dev/null
+++ b/clang/test/Instrumentor/InstrumentorUnreachable.cpp
@@ -0,0 +1,20 @@
+// NOTE: Assertions have been autogenerated by utils/update_test_checks.py
+// RUN: %clangxx -O0 -I%llvm_bin_dir/include/ -I%llvm_src_dir/include/ %S/UnreachableRT.cpp -o %t.UnreachableRT.o -c
+// RUN: %clangxx -O0 -L%llvm_bin_dir/lib -lLLVMSupport -lLLVMDemangle -mllvm -enable-instrumentor -mllvm -instrumentor-read-config-file=%S/UnreachableRT.json %t.UnreachableRT.o -o %t %s
+// RUN: %t 2>&1 | FileCheck %s --check-prefix=FIRST
+// RUN: %t arg 2>&1 | FileCheck %s --check-prefix=SECOND
+
+static int foobar() {
+ __builtin_unreachable();
+}
+
+
+int main(int argc, char **argv) {
+ if (argc > 1)
+ foobar();
+ else
+ __builtin_unreachable();
+}
+
+// FIRST: Hit unreachable #1
+// SECOND: Hit unreachable #2
diff --git a/clang/test/Instrumentor/UnreachableRT.cpp b/clang/test/Instrumentor/UnreachableRT.cpp
new file mode 100644
index 0000000000000..a608060128e57
--- /dev/null
+++ b/clang/test/Instrumentor/UnreachableRT.cpp
@@ -0,0 +1,21 @@
+//===---- Instrumentor/UnreachableRT.c - An example Instrumentor use -----===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/Support/Signals.h"
+#include "llvm/Support/raw_ostream.h"
+
+extern "C" {
+void __unreachable_pre_unreachable(int64_t ID) {
+ llvm::errs() << "Hit unreachable #" << ID << "\n";
+ llvm::sys::PrintStackTrace(llvm::errs());
+ std::exit(0);
+}
+}
diff --git a/clang/test/Instrumentor/UnreachableRT.json b/clang/test/Instrumentor/UnreachableRT.json
new file mode 100644
index 0000000000000..9f4b1b76ef4b4
--- /dev/null
+++ b/clang/test/Instrumentor/UnreachableRT.json
@@ -0,0 +1,15 @@
+{
+ "configuration": {
+ "runtime_prefix": "__unreachable_",
+ "runtime_prefix.description": "The runtime API prefix.",
+ "demangle_function_names": true,
+ "demangle_function_names.description": "Demangle functions names passed to the runtime."
+ },
+ "instruction_pre": {
+ "unreachable": {
+ "enabled": true,
+ "id": true,
+ "id.description": "A unique ID associated with the given instrumentor call"
+ }
+ }
+}
diff --git a/clang/test/Instrumentor/lit.local.cfg b/clang/test/Instrumentor/lit.local.cfg
index afb6cf1a99e25..ae3b82b9dc78e 100644
--- a/clang/test/Instrumentor/lit.local.cfg
+++ b/clang/test/Instrumentor/lit.local.cfg
@@ -1,2 +1,6 @@
+
config.suffixes.add(".cpp")
-config.excludes = ["StackUsageRT.cpp"]
+config.excludes = ["StackUsageRT.cpp", "UnreachableRT.cpp"]
+
+config.substitutions.append(("%llvm_bin_dir", config.llvm_obj_root))
+config.substitutions.append(("%llvm_src_dir", config.llvm_src_root))
diff --git a/llvm/include/llvm/Transforms/IPO/Instrumentor.h b/llvm/include/llvm/Transforms/IPO/Instrumentor.h
index 701498bb830b9..796104944f7a1 100644
--- a/llvm/include/llvm/Transforms/IPO/Instrumentor.h
+++ b/llvm/include/llvm/Transforms/IPO/Instrumentor.h
@@ -649,6 +649,27 @@ struct AllocaIO final : public InstructionIO<Instruction::Alloca> {
}
};
+struct UnreachableIO final : public InstructionIO<Instruction::Unreachable> {
+ UnreachableIO() : InstructionIO<Instruction::Unreachable>(/*IsPRE*/ true) {}
+
+ enum ConfigKind {
+ PassId,
+ NumConfig,
+ };
+
+ using ConfigTy = BaseConfigTy<ConfigKind>;
+ ConfigTy Config;
+
+ void init(InstrumentationConfig &IConf, LLVMContext &Ctx,
+ ConfigTy *UserConfig = nullptr);
+
+ static void populate(InstrumentationConfig &IConf, LLVMContext &Ctx,
+ ConfigTy *UserConfig = nullptr) {
+ auto *PreIO = IConf.allocate<UnreachableIO>();
+ PreIO->init(IConf, Ctx, UserConfig);
+ }
+};
+
/// The instrumentation opportunity for store instructions.
struct StoreIO : public InstructionIO<Instruction::Store> {
virtual ~StoreIO() {};
diff --git a/llvm/lib/Transforms/IPO/Instrumentor.cpp b/llvm/lib/Transforms/IPO/Instrumentor.cpp
index 3ba1a2b00a5f8..e42befada5ab2 100644
--- a/llvm/lib/Transforms/IPO/Instrumentor.cpp
+++ b/llvm/lib/Transforms/IPO/Instrumentor.cpp
@@ -353,6 +353,7 @@ BaseConfigurationOption::createStringOption(InstrumentationConfig &IConf,
void InstrumentationConfig::populate(InstrumentorIRBuilderTy &IIRB) {
/// List of all instrumentation opportunities.
FunctionIO::populate(*this, IIRB.Ctx);
+ UnreachableIO::populate(*this, IIRB.Ctx);
AllocaIO::populate(*this, IIRB.Ctx);
LoadIO::populate(*this, IIRB);
StoreIO::populate(*this, IIRB);
@@ -747,6 +748,17 @@ Value *FunctionIO::isMainFunction(Value &V, Type &Ty,
///}
+/// UnreachableIO
+///{
+void UnreachableIO::init(InstrumentationConfig &IConf, LLVMContext &Ctx,
+ ConfigTy *UserConfig) {
+ if (UserConfig)
+ Config = *UserConfig;
+ addCommonArgs(IConf, Ctx, Config.has(PassId));
+ IConf.addChoice(*this, Ctx);
+}
+///}
+
/// AllocaIO
///{
void AllocaIO::init(InstrumentationConfig &IConf, LLVMContext &Ctx,
diff --git a/llvm/test/Instrumentation/Instrumentor/default_config.json b/llvm/test/Instrumentation/Instrumentor/default_config.json
index 336dc20cfd5e0..01dd8f8a8f720 100644
--- a/llvm/test/Instrumentation/Instrumentor/default_config.json
+++ b/llvm/test/Instrumentation/Instrumentor/default_config.json
@@ -49,6 +49,11 @@
}
},
"instruction_pre": {
+ "unreachable": {
+ "enabled": true,
+ "id": true,
+ "id.description": "A unique ID associated with the given instrumentor call"
+ },
"load": {
"enabled": true,
"pointer": true,
More information about the llvm-branch-commits
mailing list