[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