[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
Fri May 1 21:24:08 PDT 2026


https://github.com/jdoerfert created https://github.com/llvm/llvm-project/pull/195408

Allow to instrument unreachable and provide a use case for stack trace printing.

>From 6d46b0bc29a7f5fecf065870288d0c6f89c6dcdb 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     | 20 +++++++++++++++++
 clang/test/Instrumentor/UnreachableRT.json    | 15 +++++++++++++
 clang/test/Instrumentor/lit.local.cfg         |  6 ++++-
 .../llvm/Transforms/IPO/Instrumentor.h        | 22 +++++++++++++++++++
 llvm/lib/Transforms/IPO/Instrumentor.cpp      | 14 +++++++++++-
 6 files changed, 95 insertions(+), 2 deletions(-)
 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..7a716bed62d53
--- /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: not %t 2>&1 | FileCheck %s --check-prefix=FIRST
+// RUN: not %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..4e1d54ee7958a
--- /dev/null
+++ b/clang/test/Instrumentor/UnreachableRT.cpp
@@ -0,0 +1,20 @@
+//===-- examples/Instrumentor/stack_usage.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());
+}
+}
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 af3e3282944b3..9bd809230d14d 100644
--- a/llvm/include/llvm/Transforms/IPO/Instrumentor.h
+++ b/llvm/include/llvm/Transforms/IPO/Instrumentor.h
@@ -647,6 +647,28 @@ struct AllocaIO : public InstructionIO<Instruction::Alloca> {
   }
 };
 
+struct UnreachableIO : public InstructionIO<Instruction::Unreachable> {
+  UnreachableIO() : InstructionIO<Instruction::Unreachable>(/*IsPRE*/ true) {}
+  virtual ~UnreachableIO() {};
+
+  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 *AIC = IConf.allocate<UnreachableIO>();
+    AIC->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 e4ba5c7632c42..0265447832357 100644
--- a/llvm/lib/Transforms/IPO/Instrumentor.cpp
+++ b/llvm/lib/Transforms/IPO/Instrumentor.cpp
@@ -233,7 +233,7 @@ bool InstrumentorImpl::instrumentFunction(Function &Fn) {
   for (auto &It : RPOT) {
     for (auto &I : *It)
       Changed |= instrumentInstruction(I, ICaches);
-    
+
     auto *TI = It->getTerminator();
     if (!TI->getNumSuccessors())
       FinalTIs.push_back(TI);
@@ -349,6 +349,7 @@ BaseConfigurationOption::getStringOption(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,



More information about the llvm-branch-commits mailing list