[llvm] [Offload] Add verbose printing of kernel argument types and launch values (PR #215925)

Amadeu Moya via llvm-commits llvm-commits at lists.llvm.org
Thu Aug 13 10:47:35 PDT 2026


Amadeu Moya =?utf-8?q?Sardà?= <moyasarda1 at llnl.gov>,
Amadeu Moya =?utf-8?q?Sardà?= <moyasarda1 at llnl.gov>
Message-ID:
In-Reply-To: <llvm.org/llvm/llvm-project/pull/215925 at github.com>


https://github.com/amad00r updated https://github.com/llvm/llvm-project/pull/215925

>From eea7c0118326e96c057614b1ed0884360b0e5bc4 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Amadeu=20Moya=20Sard=C3=A0?= <moyasarda1 at llnl.gov>
Date: Mon, 3 Aug 2026 14:43:28 -0700
Subject: [PATCH 1/3] Add MaterializeKernelInfo transform pass

This is a utility transform pass that materializes compile-time kernel
argument type information into IR globals. For each kernel function,
the pass emits a constant byte array containing encoded argument type
metadata and marks it as compiler-used so it remains available in the
final image.

The generated metadata can be retrieved by the host at runtime (e.g.
for profiling purposes).
---
 .../llvm/Transforms/Utils/KernelArgInfo.h     | 129 ++++++++++++++++++
 .../Transforms/Utils/MaterializeKernelInfo.h  |  29 ++++
 llvm/lib/Passes/PassBuilder.cpp               |   1 +
 llvm/lib/Passes/PassRegistry.def              |   1 +
 llvm/lib/Transforms/Utils/CMakeLists.txt      |   1 +
 .../Utils/MaterializeKernelInfo.cpp           |  90 ++++++++++++
 .../Util/materialized-kernel-info.ll          |  40 ++++++
 .../llvm/lib/Transforms/Utils/BUILD.gn        |   1 +
 8 files changed, 292 insertions(+)
 create mode 100644 llvm/include/llvm/Transforms/Utils/KernelArgInfo.h
 create mode 100644 llvm/include/llvm/Transforms/Utils/MaterializeKernelInfo.h
 create mode 100644 llvm/lib/Transforms/Utils/MaterializeKernelInfo.cpp
 create mode 100644 llvm/test/Transforms/Util/materialized-kernel-info.ll

diff --git a/llvm/include/llvm/Transforms/Utils/KernelArgInfo.h b/llvm/include/llvm/Transforms/Utils/KernelArgInfo.h
new file mode 100644
index 0000000000000..23527b60f6f68
--- /dev/null
+++ b/llvm/include/llvm/Transforms/Utils/KernelArgInfo.h
@@ -0,0 +1,129 @@
+//===- KernelArgInfo.h - Kernel argument info -----------------*- C++ -*-===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+//
+// This file defines the data structures used to encode kernel information.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_TRANSFORMS_UTILS_KERNELARGINFO_H
+#define LLVM_TRANSFORMS_UTILS_KERNELARGINFO_H
+
+#include "llvm/Support/Endian.h"
+#include <cassert>
+#include <cstdint>
+#include <sstream>
+#include <string>
+
+namespace llvm {
+
+struct KernelArgInfo {
+public:
+  using EncodeType = uint32_t;
+
+private:
+  static constexpr unsigned PayloadShift = 8;
+  static constexpr EncodeType KindMask =
+      static_cast<EncodeType>((1u << PayloadShift) - 1);
+
+  EncodeType Encoded;
+
+public:
+  enum class Kind : uint8_t {
+    Integer = 0,
+    Float = 1,
+    Double = 2,
+    Pointer = 3,
+    Unknown = KindMask,
+  };
+
+private:
+  explicit KernelArgInfo(Kind K, EncodeType Payload)
+      : Encoded((Payload << PayloadShift) | static_cast<EncodeType>(K)) {}
+
+  explicit KernelArgInfo(EncodeType Encoded) : Encoded(Encoded) {}
+
+public:
+  static KernelArgInfo getIntegerTy(EncodeType BitWidth) {
+    return KernelArgInfo(Kind::Integer, BitWidth);
+  }
+
+  static KernelArgInfo getFloatTy() { return KernelArgInfo(Kind::Float, 0); }
+
+  static KernelArgInfo getDoubleTy() { return KernelArgInfo(Kind::Double, 0); }
+
+  static KernelArgInfo getPointerTy() {
+    return KernelArgInfo(Kind::Pointer, 0);
+  }
+
+  static KernelArgInfo getUnknownTy() {
+    return KernelArgInfo(Kind::Unknown, 0);
+  }
+
+  Kind getKind() const { return static_cast<Kind>(Encoded & KindMask); }
+
+  EncodeType getIntegerBitWidth() const { return Encoded >> PayloadShift; }
+
+  EncodeType getEncodedLE() const {
+    EncodeType E;
+    support::endian::write32le(&E, Encoded);
+    return E;
+  }
+
+  static KernelArgInfo fromEncodedLE(const void *P) {
+    return KernelArgInfo(support::endian::read32le(P));
+  }
+
+  std::string typeStr() const {
+    switch (getKind()) {
+    case Kind::Integer:
+      return "i" + std::to_string(getIntegerBitWidth());
+    case Kind::Float:
+      return "float";
+    case Kind::Double:
+      return "double";
+    case Kind::Pointer:
+      return "ptr";
+    case Kind::Unknown:
+      return "unknown";
+    }
+  }
+
+  std::string valueStr(void *Value) const {
+    assert(Value);
+    switch (getKind()) {
+    case Kind::Integer:
+      switch (getIntegerBitWidth()) {
+      case 8:
+        return std::to_string(*reinterpret_cast<uint8_t *>(Value));
+      case 16:
+        return std::to_string(*reinterpret_cast<uint16_t *>(Value));
+      case 32:
+        return std::to_string(*reinterpret_cast<uint32_t *>(Value));
+      case 64:
+        return std::to_string(*reinterpret_cast<uint64_t *>(Value));
+      default:
+        return "<unsupported bit width>";
+      }
+    case Kind::Float:
+      return std::to_string(*reinterpret_cast<float *>(Value));
+    case Kind::Double:
+      return std::to_string(*reinterpret_cast<double *>(Value));
+    case Kind::Pointer: {
+      std::ostringstream oss;
+      oss << *reinterpret_cast<void **>(Value);
+      return oss.str();
+    }
+    case Kind::Unknown:
+      return "<no representation>";
+    }
+  }
+};
+
+} // end namespace llvm
+
+#endif // LLVM_TRANSFORMS_UTILS_KERNELARGINFO_H
diff --git a/llvm/include/llvm/Transforms/Utils/MaterializeKernelInfo.h b/llvm/include/llvm/Transforms/Utils/MaterializeKernelInfo.h
new file mode 100644
index 0000000000000..12c5afd9a97e5
--- /dev/null
+++ b/llvm/include/llvm/Transforms/Utils/MaterializeKernelInfo.h
@@ -0,0 +1,29 @@
+//===- MaterializeKernelInfo.h - Materialize kernel info -------*- C++ -*-===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+//
+// This file declares the MaterializeKernelInfoPass, a module transform that
+// materializes compile-time kernel information so it is available at runtime.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_TRANSFORMS_UTILS_MATERIALIZEKERNELINFO_H
+#define LLVM_TRANSFORMS_UTILS_MATERIALIZEKERNELINFO_H
+
+#include "llvm/IR/PassManager.h"
+
+namespace llvm {
+
+class MaterializeKernelInfoPass
+    : public OptionalPassInfoMixin<MaterializeKernelInfoPass> {
+public:
+  LLVM_ABI PreservedAnalyses run(Module &, ModuleAnalysisManager &);
+};
+
+} // end namespace llvm
+
+#endif // LLVM_TRANSFORMS_UTILS_MATERIALIZEKERNELINFO_H
diff --git a/llvm/lib/Passes/PassBuilder.cpp b/llvm/lib/Passes/PassBuilder.cpp
index 6abaa77f9065f..e677d7926c5cd 100644
--- a/llvm/lib/Passes/PassBuilder.cpp
+++ b/llvm/lib/Passes/PassBuilder.cpp
@@ -385,6 +385,7 @@
 #include "llvm/Transforms/Utils/LowerIFunc.h"
 #include "llvm/Transforms/Utils/LowerInvoke.h"
 #include "llvm/Transforms/Utils/LowerSwitch.h"
+#include "llvm/Transforms/Utils/MaterializeKernelInfo.h"
 #include "llvm/Transforms/Utils/Mem2Reg.h"
 #include "llvm/Transforms/Utils/MetaRenamer.h"
 #include "llvm/Transforms/Utils/MoveAutoInit.h"
diff --git a/llvm/lib/Passes/PassRegistry.def b/llvm/lib/Passes/PassRegistry.def
index 177d8ecd3508d..705db106bafbf 100644
--- a/llvm/lib/Passes/PassRegistry.def
+++ b/llvm/lib/Passes/PassRegistry.def
@@ -111,6 +111,7 @@ MODULE_PASS("jmc-instrumenter", JMCInstrumenterPass())
 MODULE_PASS("lower-emutls", LowerEmuTLSPass())
 MODULE_PASS("lower-global-dtors", LowerGlobalDtorsPass())
 MODULE_PASS("lower-ifunc", LowerIFuncPass())
+MODULE_PASS("materialize-kernel-info", MaterializeKernelInfoPass())
 MODULE_PASS("simplify-type-tests", SimplifyTypeTestsPass())
 MODULE_PASS("lowertypetests", LowerTypeTestsPass())
 MODULE_PASS("fatlto-cleanup", FatLtoCleanup())
diff --git a/llvm/lib/Transforms/Utils/CMakeLists.txt b/llvm/lib/Transforms/Utils/CMakeLists.txt
index 68f48b757eb6d..84cb9c243846c 100644
--- a/llvm/lib/Transforms/Utils/CMakeLists.txt
+++ b/llvm/lib/Transforms/Utils/CMakeLists.txt
@@ -63,6 +63,7 @@ add_llvm_component_library(LLVMTransformUtils
   LowerSwitch.cpp
   LowerVectorIntrinsics.cpp
   MatrixUtils.cpp
+  MaterializeKernelInfo.cpp
   MemoryOpRemark.cpp
   MemoryTaggingSupport.cpp
   Mem2Reg.cpp
diff --git a/llvm/lib/Transforms/Utils/MaterializeKernelInfo.cpp b/llvm/lib/Transforms/Utils/MaterializeKernelInfo.cpp
new file mode 100644
index 0000000000000..cbd801e8458e6
--- /dev/null
+++ b/llvm/lib/Transforms/Utils/MaterializeKernelInfo.cpp
@@ -0,0 +1,90 @@
+//===- MaterializeKernelInfo.cpp - Materialize kernel info ----------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+//
+// This pass materializes compile-time kernel information as IR globals so it is
+// available at runtime, for example to support profiling.
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/Transforms/Utils/MaterializeKernelInfo.h"
+#include "llvm/ADT/ArrayRef.h"
+#include "llvm/ADT/SmallVector.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/IR/Constants.h"
+#include "llvm/IR/DerivedTypes.h"
+#include "llvm/IR/Function.h"
+#include "llvm/IR/GlobalVariable.h"
+#include "llvm/IR/Module.h"
+#include "llvm/IR/Type.h"
+#include "llvm/Transforms/Utils/KernelArgInfo.h"
+#include "llvm/Transforms/Utils/ModuleUtils.h"
+#include <cstdint>
+#include <string>
+
+using namespace llvm;
+
+namespace {
+
+std::string getKernelInfoSymbolName(const Function &F) {
+  return (F.getName() + "_kernel_info").str();
+}
+
+KernelArgInfo getKernelArgInfo(Type *ArgTy) {
+  if (ArgTy->isIntegerTy())
+    return KernelArgInfo::getIntegerTy(cast<IntegerType>(ArgTy)->getBitWidth());
+  if (ArgTy->isFloatTy())
+    return KernelArgInfo::getFloatTy();
+  if (ArgTy->isDoubleTy())
+    return KernelArgInfo::getDoubleTy();
+  if (ArgTy->isPointerTy())
+    return KernelArgInfo::getPointerTy();
+  return KernelArgInfo::getUnknownTy();
+}
+
+GlobalVariable *createKernelInfoGlobal(Module &M, StringRef Name,
+                                       ArrayRef<uint8_t> EncodedKernelInfo) {
+  Constant *Init = ConstantDataArray::get(M.getContext(), EncodedKernelInfo);
+  auto *Ty =
+      ArrayType::get(Type::getInt8Ty(M.getContext()), EncodedKernelInfo.size());
+  return new GlobalVariable(M, Ty, /*isConstant=*/true,
+                            GlobalValue::ExternalLinkage, Init, Name);
+}
+
+bool materializeKernelInfo(Function &F) {
+  // FIXME: does not work when target is CPU. we could add a flag to the
+  // module to know if it is going through the offloading driver.
+  if (!F.hasKernelCallingConv())
+    return false;
+
+  const std::string KernelInfoSymbol = getKernelInfoSymbolName(F);
+  if (F.getParent()->getNamedValue(KernelInfoSymbol))
+    return false;
+
+  SmallVector<KernelArgInfo::EncodeType, 16> EncodedKernelInfo;
+  for (const Argument &Arg : F.args())
+    EncodedKernelInfo.emplace_back(
+        getKernelArgInfo(Arg.getType()).getEncodedLE());
+
+  GlobalVariable *GV = createKernelInfoGlobal(
+      *F.getParent(), KernelInfoSymbol,
+      ArrayRef<uint8_t>(reinterpret_cast<uint8_t *>(EncodedKernelInfo.data()),
+                        EncodedKernelInfo.size_in_bytes()));
+  appendToCompilerUsed(*F.getParent(), {GV});
+  return true;
+}
+
+} // namespace
+
+PreservedAnalyses MaterializeKernelInfoPass::run(Module &M,
+                                                 ModuleAnalysisManager &) {
+  bool Changed = false;
+  for (Function &F : M)
+    Changed |= materializeKernelInfo(F);
+
+  return Changed ? PreservedAnalyses::none() : PreservedAnalyses::all();
+}
diff --git a/llvm/test/Transforms/Util/materialized-kernel-info.ll b/llvm/test/Transforms/Util/materialized-kernel-info.ll
new file mode 100644
index 0000000000000..3314dfeaba884
--- /dev/null
+++ b/llvm/test/Transforms/Util/materialized-kernel-info.ll
@@ -0,0 +1,40 @@
+; RUN: opt -S -passes='materialize-kernel-info' < %s | FileCheck %s
+
+; This test checks if kernel info is correctly materialized for `ptx_kernel`,
+; `amdgpu_kernel` and `spir_kernel` kernels.
+
+; CHECK-DAG: @cuda_kernel_kernel_info = constant [4 x i8] c"\00 \00\00"
+define ptx_kernel void @cuda_kernel(i32 %x) {
+  ret void
+}
+
+; CHECK-DAG: @hip_kernel_kernel_info = constant [4 x i8] c"\00@\00\00"
+define amdgpu_kernel void @hip_kernel(i64 %x) {
+  ret void
+}
+
+; CHECK-DAG: @__omp_offloading_nvptx_l42_kernel_info = constant [4 x i8] c"\03\00\00\00"
+define ptx_kernel void @__omp_offloading_nvptx_l42(ptr %dyn) "kernel" {
+  ret void
+}
+
+; CHECK-DAG: @__omp_offloading_amdgpu_l42_kernel_info = constant [4 x i8] c"\03\00\00\00"
+define amdgpu_kernel void @__omp_offloading_amdgpu_l42(ptr %dyn) "kernel" {
+  ret void
+}
+
+; CHECK-DAG: @spir_kernel_kernel_info = constant [4 x i8] c"\01\00\00\00"
+define spir_kernel void @spir_kernel(float %x) {
+  ret void
+}
+
+; CHECK-DAG: @typed_kernel_kernel_info = constant [20 x i8] c"\00 \00\00\00@\00\00\01\00\00\00\02\00\00\00\03\00\00\00"
+define amdgpu_kernel void @typed_kernel(i32 %i32, i64 %i64, float %f32,
+                                        double %f64, ptr %p) {
+  ret void
+}
+
+; CHECK-DAG: @vector_unknown_kernel_kernel_info = constant [4 x i8] c"\FF\00\00\00"
+define amdgpu_kernel void @vector_unknown_kernel(<2 x i32> %v) {
+  ret void
+}
diff --git a/llvm/utils/gn/secondary/llvm/lib/Transforms/Utils/BUILD.gn b/llvm/utils/gn/secondary/llvm/lib/Transforms/Utils/BUILD.gn
index 2a2e0f4ff8430..32951a1399925 100644
--- a/llvm/utils/gn/secondary/llvm/lib/Transforms/Utils/BUILD.gn
+++ b/llvm/utils/gn/secondary/llvm/lib/Transforms/Utils/BUILD.gn
@@ -71,6 +71,7 @@ static_library("Utils") {
     "LowerSwitch.cpp",
     "LowerVectorIntrinsics.cpp",
     "MatrixUtils.cpp",
+    "MaterializeKernelInfo.cpp",
     "Mem2Reg.cpp",
     "MemoryOpRemark.cpp",
     "MemoryTaggingSupport.cpp",

>From 1c36dbb1bc4509b6fc8114faa11b3aec8cef2c4e Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Amadeu=20Moya=20Sard=C3=A0?= <moyasarda1 at llnl.gov>
Date: Tue, 11 Aug 2026 13:05:04 -0700
Subject: [PATCH 2/3] Add MaterializeKernelInfoPass to default pipelines

---
 llvm/lib/Passes/PassBuilderPipelines.cpp             | 12 ++++++++++++
 llvm/test/CodeGen/AArch64/print-pipeline-passes.ll   |  2 +-
 llvm/test/CodeGen/Hexagon/print-pipeline-passes.ll   |  2 +-
 llvm/test/Other/new-pass-manager.ll                  |  1 +
 llvm/test/Other/new-pm-O0-defaults.ll                |  6 +++++-
 llvm/test/Other/new-pm-defaults.ll                   |  1 +
 llvm/test/Other/new-pm-lto-defaults.ll               |  1 +
 llvm/test/Other/new-pm-thinlto-postlink-defaults.ll  |  1 +
 .../Other/new-pm-thinlto-postlink-pgo-defaults.ll    |  1 +
 .../new-pm-thinlto-postlink-samplepgo-defaults.ll    |  1 +
 llvm/test/Other/new-pm-thinlto-prelink-defaults.ll   |  1 +
 .../Other/new-pm-thinlto-prelink-pgo-defaults.ll     |  1 +
 .../new-pm-thinlto-prelink-samplepgo-defaults.ll     |  1 +
 13 files changed, 28 insertions(+), 3 deletions(-)

diff --git a/llvm/lib/Passes/PassBuilderPipelines.cpp b/llvm/lib/Passes/PassBuilderPipelines.cpp
index b8c5b1eab2f97..520cc70accc39 100644
--- a/llvm/lib/Passes/PassBuilderPipelines.cpp
+++ b/llvm/lib/Passes/PassBuilderPipelines.cpp
@@ -147,6 +147,7 @@
 #include "llvm/Transforms/Utils/InjectTLIMappings.h"
 #include "llvm/Transforms/Utils/LibCallsShrinkWrap.h"
 #include "llvm/Transforms/Utils/LowerCommentStringPass.h"
+#include "llvm/Transforms/Utils/MaterializeKernelInfo.h"
 #include "llvm/Transforms/Utils/Mem2Reg.h"
 #include "llvm/Transforms/Utils/MoveAutoInit.h"
 #include "llvm/Transforms/Utils/NameAnonGlobals.h"
@@ -1195,6 +1196,8 @@ PassBuilder::buildModuleSimplificationPipeline(OptimizationLevel Level,
           PGOIndirectCallPromotion(true /* IsInLTO */, true /* SamplePGO */));
   }
 
+  MPM.addPass(MaterializeKernelInfoPass());
+
   // Try to perform OpenMP specific optimizations on the module. This is a
   // (quick!) no-op if there are no OpenMP runtime calls present in the module.
   MPM.addPass(OpenMPOptPass(Phase));
@@ -1973,6 +1976,8 @@ ModulePassManager PassBuilder::buildThinLTODefaultPipeline(
   }
 
   if (Level == OptimizationLevel::O0) {
+    MPM.addPass(MaterializeKernelInfoPass());
+
     // Run a second time to clean up any type tests left behind by WPD for use
     // in ICP.
     MPM.addPass(DropTypeTestsPass());
@@ -1990,6 +1995,7 @@ ModulePassManager PassBuilder::buildThinLTODefaultPipeline(
     return MPM;
   }
   if (!UseCtxProfile.empty()) {
+    MPM.addPass(MaterializeKernelInfoPass());
     MPM.addPass(
         buildModuleInlinerPipeline(Level, ThinOrFullLTOPhase::ThinLTOPostLink));
   } else {
@@ -2036,6 +2042,8 @@ PassBuilder::buildLTODefaultPipeline(OptimizationLevel Level,
   MPM.addPass(CrossDSOCFIPass());
 
   if (Level == OptimizationLevel::O0) {
+    MPM.addPass(MaterializeKernelInfoPass());
+
     // The WPD and LowerTypeTest passes need to run at -O0 to lower type
     // metadata and intrinsics.
     MPM.addPass(WholeProgramDevirtPass(ExportSummary, nullptr));
@@ -2068,6 +2076,8 @@ PassBuilder::buildLTODefaultPipeline(OptimizationLevel Level,
     MPM.addPass(RequireAnalysisPass<ProfileSummaryAnalysis, Module>());
   }
 
+  MPM.addPass(MaterializeKernelInfoPass());
+
   // Try to run OpenMP optimizations, quick no-op if no OpenMP metadata present.
   MPM.addPass(OpenMPOptPass(ThinOrFullLTOPhase::FullLTOPostLink));
 
@@ -2437,6 +2447,8 @@ PassBuilder::buildO0DefaultPipeline(OptimizationLevel Level,
 
   invokePipelineEarlySimplificationEPCallbacks(MPM, Level, Phase);
 
+  MPM.addPass(MaterializeKernelInfoPass());
+
   // Build a minimal pipeline based on the semantics required by LLVM,
   // which is just that always inlining occurs. Further, disable generating
   // lifetime intrinsics to avoid enabling further optimizations during
diff --git a/llvm/test/CodeGen/AArch64/print-pipeline-passes.ll b/llvm/test/CodeGen/AArch64/print-pipeline-passes.ll
index 1abc5ab09b674..6b4dae3c88792 100644
--- a/llvm/test/CodeGen/AArch64/print-pipeline-passes.ll
+++ b/llvm/test/CodeGen/AArch64/print-pipeline-passes.ll
@@ -2,7 +2,7 @@
 ; RUN: opt -mtriple=aarch64 -S -passes='default<O2>' -print-pipeline-passes < %s | FileCheck %s
 
 ; CHECK: loop-idiom-vectorize
-; O0: {{^}}function(ee-instrument<>),always-inline,coro-cond(coro-early,cgscc(coro-split),coro-cleanup,globaldce),alloc-token,lower-comment-string,function(annotation-remarks),verify,print{{$}}
+; O0: {{^}}function(ee-instrument<>),materialize-kernel-info,always-inline,coro-cond(coro-early,cgscc(coro-split),coro-cleanup,globaldce),alloc-token,lower-comment-string,function(annotation-remarks),verify,print{{$}}
 
 define void @foo() {
 entry:
diff --git a/llvm/test/CodeGen/Hexagon/print-pipeline-passes.ll b/llvm/test/CodeGen/Hexagon/print-pipeline-passes.ll
index 2ff5d83f8ed00..239f8e278ac0f 100644
--- a/llvm/test/CodeGen/Hexagon/print-pipeline-passes.ll
+++ b/llvm/test/CodeGen/Hexagon/print-pipeline-passes.ll
@@ -3,7 +3,7 @@
 
 ; CHECK: hexagon-loop-idiom
 ; CHECK: hexagon-vlcr
-; O0: {{^}}function(ee-instrument<>),always-inline,coro-cond(coro-early,cgscc(coro-split),coro-cleanup,globaldce),alloc-token,lower-comment-string,function(annotation-remarks),verify,print{{$}}
+; O0: {{^}}function(ee-instrument<>),materialize-kernel-info,always-inline,coro-cond(coro-early,cgscc(coro-split),coro-cleanup,globaldce),alloc-token,lower-comment-string,function(annotation-remarks),verify,print{{$}}
 
 define void @test_hexagon_passes() {
 entry:
diff --git a/llvm/test/Other/new-pass-manager.ll b/llvm/test/Other/new-pass-manager.ll
index f0fe708806f1b..d840f89d4e5fd 100644
--- a/llvm/test/Other/new-pass-manager.ll
+++ b/llvm/test/Other/new-pass-manager.ll
@@ -292,6 +292,7 @@
 ; RUN:     | FileCheck %s --check-prefix=CHECK-O0 --check-prefix=%llvmcheckext
 ; CHECK-O0: Running analysis: InnerAnalysisManagerProxy<{{.*}}>
 ; CHECK-O0-NEXT: Running pass: EntryExitInstrumenterPass
+; CHECK-O0-NEXT: Running pass: MaterializeKernelInfoPass
 ; CHECK-O0-NEXT: Running pass: AlwaysInlinerPass
 ; CHECK-O0-NEXT: Running analysis: ProfileSummaryAnalysis
 ; CHECK-EXT-NEXT: Running pass: {{.*}}Bye
diff --git a/llvm/test/Other/new-pm-O0-defaults.ll b/llvm/test/Other/new-pm-O0-defaults.ll
index e304525d99913..d6960babdc29e 100644
--- a/llvm/test/Other/new-pm-O0-defaults.ll
+++ b/llvm/test/Other/new-pm-O0-defaults.ll
@@ -32,10 +32,12 @@
 ; CHECK-DIS: Running analysis: InnerAnalysisManagerProxy
 ; CHECK-DIS-NEXT: Running pass: EntryExitInstrumenterPass
 ; CHECK-DIS-NEXT: Running pass: AddDiscriminatorsPass
+; CHECK-DIS-NEXT: Running pass: MaterializeKernelInfoPass
 ; CHECK-DIS-NEXT: Running pass: AlwaysInlinerPass
 ; CHECK-DIS-NEXT: Running analysis: ProfileSummaryAnalysis
 ; CHECK-DEFAULT: Running analysis: InnerAnalysisManagerProxy
 ; CHECK-DEFAULT-NEXT: Running pass: EntryExitInstrumenterPass
+; CHECK-DEFAULT-NEXT: Running pass: MaterializeKernelInfoPass
 ; CHECK-DEFAULT-NEXT: Running pass: AlwaysInlinerPass
 ; CHECK-DEFAULT-NEXT: Running analysis: ProfileSummaryAnalysis
 ; CHECK-MATRIX: Running pass: LowerMatrixIntrinsicsPass
@@ -46,13 +48,15 @@
 ; CHECK-PRE-LINK: Running pass: CanonicalizeAliasesPass
 ; CHECK-PRE-LINK-NEXT: Running pass: NameAnonGlobalPass
 ; CHECK-PRE-LINK-NEXT: Running pass: AssignGUIDPass
-; CHECK-THINLTO: Running pass: DropTypeTestsPass
+; CHECK-THINLTO: Running pass: MaterializeKernelInfoPass
+; CHECK-THINLTO-NEXT: Running pass: DropTypeTestsPass
 ; CHECK-THINLTO-NEXT: Running pass: CoroConditionalWrapper
 ; CHECK-THINLTO-NEXT: Running pass: AllocTokenPass
 ; CHECK-THINLTO-NEXT: Running analysis: InnerAnalysisManagerProxy
 ; CHECK-THINLTO-NEXT: Running pass: EliminateAvailableExternallyPass
 ; CHECK-THINLTO-NEXT: Running pass: GlobalDCEPass
 ; CHECK-LTO: Running pass: CrossDSOCFIPass on [module]
+; CHECK-LTO-NEXT: Running pass: MaterializeKernelInfoPass
 ; CHECK-LTO-NEXT: Running pass: WholeProgramDevirtPass
 ; CHECK-LTO-NEXT: Running analysis: InnerAnalysisManagerProxy
 ; CHECK-LTO-NEXT: Running pass: LowerTypeTestsPass
diff --git a/llvm/test/Other/new-pm-defaults.ll b/llvm/test/Other/new-pm-defaults.ll
index 2c1a57e00c9f1..ed1f31fb426a0 100644
--- a/llvm/test/Other/new-pm-defaults.ll
+++ b/llvm/test/Other/new-pm-defaults.ll
@@ -98,6 +98,7 @@
 ; CHECK-O-NEXT: Running pass: EarlyCSEPass
 ; CHECK-O-NEXT: Running analysis: TargetLibraryAnalysis
 ; CHECK-O3-NEXT: Running pass: CallSiteSplittingPass
+; CHECK-O-NEXT: Running pass: MaterializeKernelInfoPass
 ; CHECK-O-NEXT: Running pass: OpenMPOptPass
 ; CHECK-EP-PIPELINE-EARLY-SIMPLIFICATION-NEXT: Running pass: NoOpModulePass
 ; CHECK-O-NEXT: Running pass: IPSCCPPass
diff --git a/llvm/test/Other/new-pm-lto-defaults.ll b/llvm/test/Other/new-pm-lto-defaults.ll
index 14f189194d0e3..8615c038ca7d1 100644
--- a/llvm/test/Other/new-pm-lto-defaults.ll
+++ b/llvm/test/Other/new-pm-lto-defaults.ll
@@ -32,6 +32,7 @@
 
 ; CHECK-EP: Running pass: NoOpModulePass
 ; CHECK-O: Running pass: CrossDSOCFIPass
+; CHECK-O-NEXT: Running pass: MaterializeKernelInfoPass
 ; CHECK-O-NEXT: Running pass: OpenMPOptPass
 ; CHECK-O-NEXT: Running pass: GlobalDCEPass
 ; CHECK-O-NEXT: Running pass: InferFunctionAttrsPass
diff --git a/llvm/test/Other/new-pm-thinlto-postlink-defaults.ll b/llvm/test/Other/new-pm-thinlto-postlink-defaults.ll
index b1fde57902b05..754d6d66193f3 100644
--- a/llvm/test/Other/new-pm-thinlto-postlink-defaults.ll
+++ b/llvm/test/Other/new-pm-thinlto-postlink-defaults.ll
@@ -37,6 +37,7 @@
 ; CHECK-POSTLINK-O-NEXT: Running analysis: ProfileSummaryAnalysis
 ; CHECK-POSTLINK-O-NEXT: Running analysis: InnerAnalysisManagerProxy
 ; CHECK-POSTLINK-O-NEXT: Running analysis: OptimizationRemarkEmitterAnalysis
+; CHECK-O-NEXT: Running pass: MaterializeKernelInfoPass
 ; CHECK-O-NEXT: Running pass: OpenMPOptPass
 ; CHECK-POSTLINK-O-NEXT: Running pass: DropTypeTestsPass
 ; CHECK-O-NEXT: Running pass: IPSCCPPass
diff --git a/llvm/test/Other/new-pm-thinlto-postlink-pgo-defaults.ll b/llvm/test/Other/new-pm-thinlto-postlink-pgo-defaults.ll
index 441344250e2ff..3adda4af6f59a 100644
--- a/llvm/test/Other/new-pm-thinlto-postlink-pgo-defaults.ll
+++ b/llvm/test/Other/new-pm-thinlto-postlink-pgo-defaults.ll
@@ -22,6 +22,7 @@
 ; CHECK-O-NEXT: Running analysis: ProfileSummaryAnalysis
 ; CHECK-O-NEXT: Running analysis: InnerAnalysisManagerProxy
 ; CHECK-O-NEXT: Running analysis: OptimizationRemarkEmitterAnalysis
+; CHECK-O-NEXT: Running pass: MaterializeKernelInfoPass
 ; CHECK-O-NEXT: Running pass: OpenMPOptPass
 ; CHECK-O-NEXT: Running pass: DropTypeTestsPass
 ; CHECK-O-NEXT: Running pass: IPSCCPPass
diff --git a/llvm/test/Other/new-pm-thinlto-postlink-samplepgo-defaults.ll b/llvm/test/Other/new-pm-thinlto-postlink-samplepgo-defaults.ll
index 477e36e8d9aba..882ee8d1985e6 100644
--- a/llvm/test/Other/new-pm-thinlto-postlink-samplepgo-defaults.ll
+++ b/llvm/test/Other/new-pm-thinlto-postlink-samplepgo-defaults.ll
@@ -29,6 +29,7 @@
 ; CHECK-O-NEXT: Running pass: RequireAnalysisPass<{{.*}}ProfileSummaryAnalysis
 ; CHECK-O-NEXT: Running pass: PGOIndirectCallPromotion
 ; CHECK-O-NEXT: Running analysis: OptimizationRemarkEmitterAnalysis
+; CHECK-O-NEXT: Running pass: MaterializeKernelInfoPass
 ; CHECK-O-NEXT: Running pass: OpenMPOptPass
 ; CHECK-O-NEXT: Running pass: DropTypeTestsPass
 ; CHECK-O-NEXT: Running pass: IPSCCPPass
diff --git a/llvm/test/Other/new-pm-thinlto-prelink-defaults.ll b/llvm/test/Other/new-pm-thinlto-prelink-defaults.ll
index b07825faaa873..017fa5b5c6656 100644
--- a/llvm/test/Other/new-pm-thinlto-prelink-defaults.ll
+++ b/llvm/test/Other/new-pm-thinlto-prelink-defaults.ll
@@ -68,6 +68,7 @@
 ; CHECK-O-NEXT: Running pass: EarlyCSEPass
 ; CHECK-O-NEXT: Running analysis: TargetLibraryAnalysis
 ; CHECK-O3-NEXT: Running pass: CallSiteSplittingPass
+; CHECK-O-NEXT: Running pass: MaterializeKernelInfoPass
 ; CHECK-O-NEXT: Running pass: OpenMPOptPass
 ; CHECK-O-NEXT: Running pass: IPSCCPPass
 ; CHECK-O-NEXT: Running pass: CalledValuePropagationPass
diff --git a/llvm/test/Other/new-pm-thinlto-prelink-pgo-defaults.ll b/llvm/test/Other/new-pm-thinlto-prelink-pgo-defaults.ll
index eafd8aad98e7a..96f8b6f4c36c9 100644
--- a/llvm/test/Other/new-pm-thinlto-prelink-pgo-defaults.ll
+++ b/llvm/test/Other/new-pm-thinlto-prelink-pgo-defaults.ll
@@ -36,6 +36,7 @@
 ; CHECK-O-NEXT: Running pass: EarlyCSEPass
 ; CHECK-O-NEXT: Running analysis: TargetLibraryAnalysis
 ; CHECK-O3-NEXT: Running pass: CallSiteSplittingPass
+; CHECK-O-NEXT: Running pass: MaterializeKernelInfoPass
 ; CHECK-O-NEXT: Running pass: OpenMPOptPass
 ; CHECK-O-NEXT: Running pass: IPSCCPPass
 ; CHECK-O-NEXT: Running pass: CalledValuePropagationPass
diff --git a/llvm/test/Other/new-pm-thinlto-prelink-samplepgo-defaults.ll b/llvm/test/Other/new-pm-thinlto-prelink-samplepgo-defaults.ll
index 8d42a45475c27..048c4d62f37e8 100644
--- a/llvm/test/Other/new-pm-thinlto-prelink-samplepgo-defaults.ll
+++ b/llvm/test/Other/new-pm-thinlto-prelink-samplepgo-defaults.ll
@@ -39,6 +39,7 @@
 ; CHECK-O-NEXT: Running analysis: LazyCallGraphAnalysis
 ; CHECK-O-NEXT: Running analysis: ProfileSummaryAnalysis
 ; CHECK-O-NEXT: Running pass: RequireAnalysisPass<{{.*}}ProfileSummaryAnalysis
+; CHECK-O-NEXT: Running pass: MaterializeKernelInfoPass
 ; CHECK-O-NEXT: Running pass: OpenMPOptPass
 ; CHECK-O-NEXT: Running pass: IPSCCPPass
 ; CHECK-O-NEXT: Running pass: CalledValuePropagationPass

>From 3b6703d32fc68ef07108951ffe9af09f6d2a21fe Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Amadeu=20Moya=20Sard=C3=A0?= <moyasarda1 at llnl.gov>
Date: Wed, 12 Aug 2026 09:31:44 -0700
Subject: [PATCH 3/3] Add verbose kernel launch information printing to plugin

Kernel argument types and formatted values are printed if there is
materialized kernel information available in the kernel image. The
user has to ask for OMP_INFOTYPE_PLUGIN_KERNEL through the
LIBOMPTARGET_INFO envar (e.g. LIBOMPTARGET_INFO=16).
---
 .../common/include/PluginInterface.h          |  5 +++
 .../common/src/PluginInterface.cpp            | 34 ++++++++++++++++++-
 2 files changed, 38 insertions(+), 1 deletion(-)

diff --git a/offload/plugins-nextgen/common/include/PluginInterface.h b/offload/plugins-nextgen/common/include/PluginInterface.h
index b83d423cba54f..ac7064cdd0254 100644
--- a/offload/plugins-nextgen/common/include/PluginInterface.h
+++ b/offload/plugins-nextgen/common/include/PluginInterface.h
@@ -16,6 +16,7 @@
 #include <deque>
 #include <list>
 #include <map>
+#include <optional>
 #include <shared_mutex>
 #include <variant>
 #include <vector>
@@ -54,6 +55,7 @@
 #include "llvm/Support/MemoryBufferRef.h"
 #include "llvm/Support/raw_ostream.h"
 #include "llvm/TargetParser/Triple.h"
+#include "llvm/Transforms/Utils/KernelArgInfo.h"
 
 using namespace llvm::offload::debug;
 
@@ -626,6 +628,9 @@ struct GenericKernelTy {
   /// The kernel name.
   std::string Name;
 
+  /// The kernel argument type info.
+  std::optional<std::vector<KernelArgInfo>> ArgTypes;
+
   /// The image that contains this kernel.
   DeviceImageTy *ImagePtr = nullptr;
 
diff --git a/offload/plugins-nextgen/common/src/PluginInterface.cpp b/offload/plugins-nextgen/common/src/PluginInterface.cpp
index bb7ea2b538e85..2277892515ae2 100644
--- a/offload/plugins-nextgen/common/src/PluginInterface.cpp
+++ b/offload/plugins-nextgen/common/src/PluginInterface.cpp
@@ -75,9 +75,29 @@ Error GenericKernelTy::init(GenericDeviceTy &GenericDevice,
 
   ImagePtr = &Image;
 
+  GenericGlobalHandlerTy &GHandler = GenericDevice.Plugin.getGlobalHandler();
+
+  // Retrieve kernel information if possible.
+  const std::string KernelInfoName = Name + "_kernel_info";
+  if (GHandler.isSymbolInImage(GenericDevice, Image, KernelInfoName)) {
+    GlobalTy ImageKernelInfo(KernelInfoName);
+    if (auto Err = GHandler.getGlobalMetadataFromImage(GenericDevice, Image,
+                                                       ImageKernelInfo))
+      return Err;
+
+    assert(!ArgTypes);
+    ArgTypes.emplace();
+    const size_t NumArgs =
+        ImageKernelInfo.getSize() / sizeof(KernelArgInfo::EncodeType);
+    ArgTypes->reserve(NumArgs);
+    for (size_t i = 0; i < NumArgs; ++i)
+      ArgTypes->emplace_back(KernelArgInfo::fromEncodedLE(static_cast<void *>(
+          static_cast<KernelArgInfo::EncodeType *>(ImageKernelInfo.getPtr()) +
+          i)));
+  }
+
   // Retrieve kernel environment object for the kernel.
   std::string EnvironmentName = std::string(Name) + "_kernel_environment";
-  GenericGlobalHandlerTy &GHandler = GenericDevice.Plugin.getGlobalHandler();
   if (GHandler.isSymbolInImage(GenericDevice, Image, EnvironmentName)) {
     GlobalTy KernelEnv(EnvironmentName, sizeof(KernelEnvironment),
                        &KernelEnvironment);
@@ -185,6 +205,18 @@ Error GenericKernelTy::printLaunchInfo(GenericDeviceTy &GenericDevice,
        "%s mode\n",
        getName(), NumBlocks[0], NumBlocks[1], NumBlocks[2], NumThreads[0],
        NumThreads[1], NumThreads[2], getExecutionModeName());
+
+  assert(!ArgTypes || ArgTypes->size() == LaunchArgs.NumArgs);
+  for (uint32_t I = 0; I < LaunchArgs.NumArgs; ++I) {
+    KernelArgInfo TypeInfo = KernelArgInfo::getUnknownTy();
+    if (ArgTypes && I < ArgTypes->size())
+      TypeInfo = (*ArgTypes)[I];
+
+    INFO(OMP_INFOTYPE_PLUGIN_KERNEL, GenericDevice.getDeviceId(),
+         "  arg[%u]={ type=%s, val=%s }\n", I, TypeInfo.typeStr().data(),
+         TypeInfo.valueStr(LaunchArgs.Args[I]).data());
+  }
+
   return printLaunchInfoDetails(GenericDevice, LaunchArgs, NumThreads,
                                 NumBlocks);
 }



More information about the llvm-commits mailing list