[clang] [llvm] [NVPTX] Add NVVMUpgradeAnnotations pass to cleanup legacy annotations (PR #119261)

Alex MacLean via llvm-commits llvm-commits at lists.llvm.org
Mon Dec 9 15:46:08 PST 2024


https://github.com/AlexMaclean updated https://github.com/llvm/llvm-project/pull/119261

>From f9f30a77f5e7232f968a3063c34338c9dfc7bac5 Mon Sep 17 00:00:00 2001
From: Alex Maclean <amaclean at nvidia.com>
Date: Fri, 8 Nov 2024 22:39:34 +0000
Subject: [PATCH 1/3] [NVPTX] Add NVVMUpgradeAnnotations pass to cleanup legacy
 annotations

---
 llvm/lib/Target/NVPTX/CMakeLists.txt          |   1 +
 llvm/lib/Target/NVPTX/NVPTX.h                 |   5 +
 llvm/lib/Target/NVPTX/NVPTXTargetMachine.cpp  |   4 +
 llvm/lib/Target/NVPTX/NVPTXUtilities.cpp      |   9 +-
 .../Target/NVPTX/NVVMUpgradeAnnotations.cpp   | 130 ++++++++++++++++++
 .../CodeGen/NVPTX/upgrade-nvvm-annotations.ll |  30 ++++
 6 files changed, 177 insertions(+), 2 deletions(-)
 create mode 100644 llvm/lib/Target/NVPTX/NVVMUpgradeAnnotations.cpp
 create mode 100644 llvm/test/CodeGen/NVPTX/upgrade-nvvm-annotations.ll

diff --git a/llvm/lib/Target/NVPTX/CMakeLists.txt b/llvm/lib/Target/NVPTX/CMakeLists.txt
index 693365161330f5..bb2e4ad48b51d8 100644
--- a/llvm/lib/Target/NVPTX/CMakeLists.txt
+++ b/llvm/lib/Target/NVPTX/CMakeLists.txt
@@ -39,6 +39,7 @@ set(NVPTXCodeGen_sources
   NVVMReflect.cpp
   NVPTXProxyRegErasure.cpp
   NVPTXCtorDtorLowering.cpp
+  NVVMUpgradeAnnotations.cpp
   )
 
 add_llvm_target(NVPTXCodeGen
diff --git a/llvm/lib/Target/NVPTX/NVPTX.h b/llvm/lib/Target/NVPTX/NVPTX.h
index ca915cd3f3732f..53418148be3615 100644
--- a/llvm/lib/Target/NVPTX/NVPTX.h
+++ b/llvm/lib/Target/NVPTX/NVPTX.h
@@ -52,6 +52,7 @@ FunctionPass *createNVPTXLowerUnreachablePass(bool TrapUnreachable,
                                               bool NoTrapAfterNoreturn);
 MachineFunctionPass *createNVPTXPeephole();
 MachineFunctionPass *createNVPTXProxyRegErasurePass();
+ModulePass *createNVVMUpgradeAnnotationsPass();
 
 struct NVVMIntrRangePass : PassInfoMixin<NVVMIntrRangePass> {
   PreservedAnalyses run(Function &F, FunctionAnalysisManager &AM);
@@ -74,6 +75,10 @@ struct NVPTXCopyByValArgsPass : PassInfoMixin<NVPTXCopyByValArgsPass> {
   PreservedAnalyses run(Function &F, FunctionAnalysisManager &AM);
 };
 
+struct NVVMUpgradeAnnotationsPass : PassInfoMixin<NVVMUpgradeAnnotationsPass> {
+  PreservedAnalyses run(Module &M, ModuleAnalysisManager &AM);
+};
+
 namespace NVPTX {
 enum DrvInterface {
   NVCL,
diff --git a/llvm/lib/Target/NVPTX/NVPTXTargetMachine.cpp b/llvm/lib/Target/NVPTX/NVPTXTargetMachine.cpp
index a5c5e9420ee737..b4fd36625adc9c 100644
--- a/llvm/lib/Target/NVPTX/NVPTXTargetMachine.cpp
+++ b/llvm/lib/Target/NVPTX/NVPTXTargetMachine.cpp
@@ -254,6 +254,8 @@ void NVPTXTargetMachine::registerPassBuilderCallbacks(PassBuilder &PB) {
 
   PB.registerPipelineStartEPCallback(
       [this](ModulePassManager &PM, OptimizationLevel Level) {
+        PM.addPass(NVVMUpgradeAnnotationsPass());
+
         FunctionPassManager FPM;
         FPM.addPass(NVVMReflectPass(Subtarget.getSmVersion()));
         // Note: NVVMIntrRangePass was causing numerical discrepancies at one
@@ -349,6 +351,8 @@ void NVPTXPassConfig::addIRPasses() {
       AAR.addAAResult(WrapperPass->getResult());
   }));
 
+  addPass(createNVVMUpgradeAnnotationsPass());
+
   // NVVMReflectPass is added in addEarlyAsPossiblePasses, so hopefully running
   // it here does nothing.  But since we need it for correctness when lowering
   // to NVPTX, run it here too, in case whoever built our pass pipeline didn't
diff --git a/llvm/lib/Target/NVPTX/NVPTXUtilities.cpp b/llvm/lib/Target/NVPTX/NVPTXUtilities.cpp
index 98bffd92a087b6..04e83576cbf958 100644
--- a/llvm/lib/Target/NVPTX/NVPTXUtilities.cpp
+++ b/llvm/lib/Target/NVPTX/NVPTXUtilities.cpp
@@ -311,11 +311,16 @@ std::optional<unsigned> getMaxNReg(const Function &F) {
 }
 
 bool isKernelFunction(const Function &F) {
+  if (F.getCallingConv() == CallingConv::PTX_Kernel)
+    return true;
+
+  if (F.hasFnAttribute("nvvm.kernel"))
+    return true;
+
   if (const auto X = findOneNVVMAnnotation(&F, "kernel"))
     return (*X == 1);
 
-  // There is no NVVM metadata, check the calling convention
-  return F.getCallingConv() == CallingConv::PTX_Kernel;
+  return false;
 }
 
 MaybeAlign getAlign(const Function &F, unsigned Index) {
diff --git a/llvm/lib/Target/NVPTX/NVVMUpgradeAnnotations.cpp b/llvm/lib/Target/NVPTX/NVVMUpgradeAnnotations.cpp
new file mode 100644
index 00000000000000..ca550434835a2c
--- /dev/null
+++ b/llvm/lib/Target/NVPTX/NVVMUpgradeAnnotations.cpp
@@ -0,0 +1,130 @@
+//===- NVVMUpgradeAnnotations.cpp - Upgrade NVVM Annotations --------------===//
+//
+// 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 replaces deprecated metadata in nvvm.annotation with a more modern
+// IR representation.
+//
+//===----------------------------------------------------------------------===//
+
+#include "NVPTX.h"
+#include "llvm/ADT/SmallSet.h"
+#include "llvm/ADT/SmallVector.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/CodeGen/Passes.h"
+#include "llvm/IR/Attributes.h"
+#include "llvm/IR/Constants.h"
+#include "llvm/IR/Function.h"
+#include "llvm/IR/Metadata.h"
+#include "llvm/IR/Module.h"
+#include "llvm/IR/PassManager.h"
+#include "llvm/Pass.h"
+#include <cstdint>
+
+#define DEBUG_TYPE "nvvm-upgrade-annotations"
+
+using namespace llvm;
+
+namespace llvm {
+void initializeNVVMUpgradeAnnotationsLegacyPassPass(PassRegistry &);
+} // namespace llvm
+
+namespace {
+
+class NVVMUpgradeAnnotationsLegacyPass : public ModulePass {
+public:
+  static char ID;
+  NVVMUpgradeAnnotationsLegacyPass() : ModulePass(ID) {
+    initializeNVVMUpgradeAnnotationsLegacyPassPass(
+        *PassRegistry::getPassRegistry());
+  }
+  bool runOnModule(Module &M) override;
+};
+} // namespace
+
+char NVVMUpgradeAnnotationsLegacyPass::ID = 0;
+
+bool static autoUpgradeAnnotation(Function *F, StringRef K, const Metadata *V) {
+  if (K == "kernel") {
+    assert(mdconst::extract<ConstantInt>(V)->getZExtValue() == 1);
+    F->addFnAttr("nvvm.kernel");
+    return true;
+  }
+  if (K == "align") {
+    const uint64_t AlignBits = mdconst::extract<ConstantInt>(V)->getZExtValue();
+    const unsigned Idx = (AlignBits >> 16);
+    const Align StackAlign = Align(AlignBits & 0xFFFF);
+    // TODO: Skip adding the stackalign attribute for returns, for now.
+    if (!Idx)
+      return false;
+    F->addAttributeAtIndex(
+        Idx, Attribute::getWithStackAlignment(F->getContext(), StackAlign));
+    return true;
+  }
+
+  return false;
+}
+
+// Iterate over nvvm.annotations rewriting them as appropiate.
+void static upgradeNVAnnotations(Module &M) {
+  NamedMDNode *NamedMD = M.getNamedMetadata("nvvm.annotations");
+  if (!NamedMD)
+    return;
+
+  SmallVector<MDNode *, 8> NewNodes;
+  SmallSet<const MDNode *, 8> SeenNodes;
+  for (MDNode *MD : NamedMD->operands()) {
+    if (SeenNodes.contains(MD))
+      continue;
+    SeenNodes.insert(MD);
+
+    Function *F = mdconst::dyn_extract_or_null<Function>(MD->getOperand(0));
+    if (!F)
+      continue;
+
+    assert(MD && "Invalid MDNode for annotation");
+    assert((MD->getNumOperands() % 2) == 1 && "Invalid number of operands");
+
+    SmallVector<Metadata *, 8> NewOperands;
+    // start index = 1, to skip the global variable key
+    // increment = 2, to skip the value for each property-value pairs
+    for (unsigned j = 1, je = MD->getNumOperands(); j < je; j += 2) {
+      MDString *K = cast<MDString>(MD->getOperand(j));
+      const MDOperand &V = MD->getOperand(j + 1);
+      bool Upgraded = autoUpgradeAnnotation(F, K->getString(), V);
+      if (!Upgraded)
+        NewOperands.append({K, V});
+    }
+
+    if (!NewOperands.empty()) {
+      NewOperands.insert(NewOperands.begin(), MD->getOperand(0));
+      NewNodes.push_back(MDNode::get(M.getContext(), NewOperands));
+    }
+  }
+
+  NamedMD->clearOperands();
+  for (MDNode *N : NewNodes)
+    NamedMD->addOperand(N);
+}
+
+PreservedAnalyses NVVMUpgradeAnnotationsPass::run(Module &M,
+                                                  ModuleAnalysisManager &AM) {
+  upgradeNVAnnotations(M);
+  return PreservedAnalyses::all();
+}
+
+bool NVVMUpgradeAnnotationsLegacyPass::runOnModule(Module &M) {
+  upgradeNVAnnotations(M);
+  return false;
+}
+
+INITIALIZE_PASS(NVVMUpgradeAnnotationsLegacyPass, DEBUG_TYPE,
+                "NVVMUpgradeAnnotations", false, false)
+
+ModulePass *llvm::createNVVMUpgradeAnnotationsPass() {
+  return new NVVMUpgradeAnnotationsLegacyPass();
+}
diff --git a/llvm/test/CodeGen/NVPTX/upgrade-nvvm-annotations.ll b/llvm/test/CodeGen/NVPTX/upgrade-nvvm-annotations.ll
new file mode 100644
index 00000000000000..68dc2353858cb3
--- /dev/null
+++ b/llvm/test/CodeGen/NVPTX/upgrade-nvvm-annotations.ll
@@ -0,0 +1,30 @@
+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --check-attributes --check-globals all --version 5
+; RUN: opt < %s -mtriple=nvptx64-unknown-unknown -O0 -S | FileCheck %s
+
+define i32 @foo(i32 %a, i32 %b) {
+; CHECK-LABEL: define i32 @foo(
+; CHECK-SAME: i32 alignstack(8) [[A:%.*]], i32 alignstack(16) [[B:%.*]]) {
+; CHECK-NEXT:    ret i32 0
+;
+  ret i32 0
+}
+
+define i32 @bar(i32 %a, i32 %b) {
+; CHECK-LABEL: define i32 @bar(
+; CHECK-SAME: i32 [[A:%.*]], i32 [[B:%.*]]) #[[ATTR0:[0-9]+]] {
+; CHECK-NEXT:    ret i32 0
+;
+  ret i32 0
+}
+
+!nvvm.annotations = !{!0, !1, !2}
+
+!0 = !{ptr @foo, !"align", i32 u0x00000008, !"align", i32 u0x00010008, !"align", i32 u0x00020010}
+!1 = !{null, !"align", i32 u0x00000008, !"align", i32 u0x00010008, !"align", i32 u0x00020008}
+!2 = !{ptr @bar, !"kernel", i32 1}
+
+;.
+; CHECK: attributes #[[ATTR0]] = { "nvvm.kernel" }
+;.
+; CHECK: [[META0:![0-9]+]] = !{ptr @foo, !"align", i32 8}
+;.

>From b65b1d8f30b0aadb1152d07eedf39545e1c8fd65 Mon Sep 17 00:00:00 2001
From: Alex Maclean <amaclean at nvidia.com>
Date: Mon, 9 Dec 2024 22:43:39 +0000
Subject: [PATCH 2/3] fixups

---
 clang/lib/CodeGen/Targets/NVPTX.cpp           | 36 ++++++++++++-------
 clang/test/CodeGen/nvptx_attributes.c         |  8 ++++-
 clang/test/CodeGenCUDA/grid-constant.cu       | 21 ++++++++---
 clang/test/CodeGenCUDA/ptx-kernels.cu         |  7 ++--
 clang/test/CodeGenCUDA/usual-deallocators.cu  |  4 +--
 clang/test/CodeGenOpenCL/ptx-calls.cl         |  4 +--
 clang/test/CodeGenOpenCL/ptx-kernels.cl       |  4 +--
 clang/test/CodeGenOpenCL/reflect.cl           |  8 ++++-
 .../Target/NVPTX/NVVMUpgradeAnnotations.cpp   | 12 ++++---
 9 files changed, 70 insertions(+), 34 deletions(-)

diff --git a/clang/lib/CodeGen/Targets/NVPTX.cpp b/clang/lib/CodeGen/Targets/NVPTX.cpp
index 0431d2cc4ddc39..2fddaf8efad10d 100644
--- a/clang/lib/CodeGen/Targets/NVPTX.cpp
+++ b/clang/lib/CodeGen/Targets/NVPTX.cpp
@@ -78,14 +78,12 @@ class NVPTXTargetCodeGenInfo : public TargetCodeGenInfo {
 
   // Adds a NamedMDNode with GV, Name, and Operand as operands, and adds the
   // resulting MDNode to the nvvm.annotations MDNode.
-  static void addNVVMMetadata(llvm::GlobalValue *GV, StringRef Name,
-                              int Operand,
+  static void
+  addNVVMGridConstantMetadata(llvm::GlobalValue *GV,
                               const SmallVectorImpl<int> &GridConstantArgs);
 
   static void addNVVMMetadata(llvm::GlobalValue *GV, StringRef Name,
-                              int Operand) {
-    addNVVMMetadata(GV, Name, Operand, SmallVector<int, 1>(0));
-  }
+                              int Operand);
 
 private:
   static void emitBuiltinSurfTexDeviceCopy(CodeGenFunction &CGF, LValue Dst,
@@ -259,7 +257,7 @@ void NVPTXTargetCodeGenInfo::setTargetAttributes(
     if (FD->hasAttr<OpenCLKernelAttr>()) {
       // OpenCL __kernel functions get kernel metadata
       // Create !{<func-ref>, metadata !"kernel", i32 1} node
-      addNVVMMetadata(F, "kernel", 1);
+      F->addFnAttr("nvvm.kernel");
       // And kernel functions are not subject to inlining
       F->addFnAttr(llvm::Attribute::NoInline);
     }
@@ -277,21 +275,20 @@ void NVPTXTargetCodeGenInfo::setTargetAttributes(
           // For some reason arg indices are 1-based in NVVM
           GCI.push_back(IV.index() + 1);
       // Create !{<func-ref>, metadata !"kernel", i32 1} node
-      addNVVMMetadata(F, "kernel", 1, GCI);
+      addNVVMGridConstantMetadata(F, GCI);
+      F->addFnAttr("nvvm.kernel");
     }
     if (CUDALaunchBoundsAttr *Attr = FD->getAttr<CUDALaunchBoundsAttr>())
       M.handleCUDALaunchBoundsAttr(F, Attr);
   }
 
   // Attach kernel metadata directly if compiling for NVPTX.
-  if (FD->hasAttr<NVPTXKernelAttr>()) {
-    addNVVMMetadata(F, "kernel", 1);
-  }
+  if (FD->hasAttr<NVPTXKernelAttr>())
+    F->addFnAttr("nvvm.kernel");
 }
 
-void NVPTXTargetCodeGenInfo::addNVVMMetadata(
-    llvm::GlobalValue *GV, StringRef Name, int Operand,
-    const SmallVectorImpl<int> &GridConstantArgs) {
+void NVPTXTargetCodeGenInfo::addNVVMMetadata(llvm::GlobalValue *GV,
+                                             StringRef Name, int Operand) {
   llvm::Module *M = GV->getParent();
   llvm::LLVMContext &Ctx = M->getContext();
 
@@ -302,6 +299,19 @@ void NVPTXTargetCodeGenInfo::addNVVMMetadata(
       llvm::ConstantAsMetadata::get(GV), llvm::MDString::get(Ctx, Name),
       llvm::ConstantAsMetadata::get(
           llvm::ConstantInt::get(llvm::Type::getInt32Ty(Ctx), Operand))};
+  // Append metadata to nvvm.annotations
+  MD->addOperand(llvm::MDNode::get(Ctx, MDVals));
+}
+
+void NVPTXTargetCodeGenInfo::addNVVMGridConstantMetadata(
+    llvm::GlobalValue *GV, const SmallVectorImpl<int> &GridConstantArgs) {
+  llvm::Module *M = GV->getParent();
+  llvm::LLVMContext &Ctx = M->getContext();
+
+  // Get "nvvm.annotations" metadata node
+  llvm::NamedMDNode *MD = M->getOrInsertNamedMetadata("nvvm.annotations");
+
+  SmallVector<llvm::Metadata *, 5> MDVals = {llvm::ConstantAsMetadata::get(GV)};
   if (!GridConstantArgs.empty()) {
     SmallVector<llvm::Metadata *, 10> GCM;
     for (int I : GridConstantArgs)
diff --git a/clang/test/CodeGen/nvptx_attributes.c b/clang/test/CodeGen/nvptx_attributes.c
index 7dbd9f1321e280..2edca9cd28c815 100644
--- a/clang/test/CodeGen/nvptx_attributes.c
+++ b/clang/test/CodeGen/nvptx_attributes.c
@@ -10,8 +10,14 @@
 // CHECK-NEXT:    [[TMP0:%.*]] = load ptr, ptr [[RET_ADDR]], align 8
 // CHECK-NEXT:    store i32 1, ptr [[TMP0]], align 4
 // CHECK-NEXT:    ret void
+//
 __attribute__((nvptx_kernel)) void foo(int *ret) {
   *ret = 1;
 }
 
-// CHECK: !0 = !{ptr @foo, !"kernel", i32 1}
+//.
+// CHECK: attributes #[[ATTR0]] = { convergent noinline nounwind optnone "no-trapping-math"="true" "nvvm.kernel" "stack-protector-buffer-size"="8" "target-cpu"="sm_61" "target-features"="+ptx32,+sm_61" }
+//.
+// CHECK: [[META0:![0-9]+]] = !{i32 1, !"wchar_size", i32 4}
+// CHECK: [[META1:![0-9]+]] = !{!"{{.*}}clang version {{.*}}"}
+//.
diff --git a/clang/test/CodeGenCUDA/grid-constant.cu b/clang/test/CodeGenCUDA/grid-constant.cu
index 8d4be9c9dc7e1e..34c94009dc4d75 100644
--- a/clang/test/CodeGenCUDA/grid-constant.cu
+++ b/clang/test/CodeGenCUDA/grid-constant.cu
@@ -5,6 +5,15 @@
 
 struct S {};
 
+// CHECK-LABEL: define dso_local void @_Z6kernel1Sii(
+// CHECK-SAME: ptr noundef byval([[STRUCT_S:%.*]]) align 1 [[GC_ARG1:%.*]], i32 noundef [[ARG2:%.*]], i32 noundef [[GC_ARG3:%.*]]) #[[ATTR0:[0-9]+]] {
+// CHECK-NEXT:  [[ENTRY:.*:]]
+// CHECK-NEXT:    [[ARG2_ADDR:%.*]] = alloca i32, align 4
+// CHECK-NEXT:    [[GC_ARG3_ADDR:%.*]] = alloca i32, align 4
+// CHECK-NEXT:    store i32 [[ARG2]], ptr [[ARG2_ADDR]], align 4
+// CHECK-NEXT:    store i32 [[GC_ARG3]], ptr [[GC_ARG3_ADDR]], align 4
+// CHECK-NEXT:    ret void
+//
 __global__ void kernel(__grid_constant__ const S gc_arg1, int arg2, __grid_constant__ const int gc_arg3) {}
 
 // dependent arguments get diagnosed after instantiation.
@@ -20,12 +29,16 @@ void foo() {
   tkernel<const S><<<1,1>>>(1, {});
 }
 //.
+// CHECK: attributes #[[ATTR0]] = { convergent mustprogress noinline norecurse nounwind optnone "no-trapping-math"="true" "nvvm.kernel" "stack-protector-buffer-size"="8" "target-features"="+ptx32" "uniform-work-group-size"="true" }
 //.
-// CHECK: [[META0:![0-9]+]] = !{ptr @_Z6kernel1Sii, !"kernel", i32 1, !"grid_constant", [[META1:![0-9]+]]}
+// CHECK: [[META0:![0-9]+]] = !{ptr @_Z6kernel1Sii, !"grid_constant", [[META1:![0-9]+]]}
 // CHECK: [[META1]] = !{i32 1, i32 3}
-// CHECK: [[META2:![0-9]+]] = !{ptr @_Z13tkernel_constIK1SEvT_, !"kernel", i32 1, !"grid_constant", [[META3:![0-9]+]]}
+// CHECK: [[META2:![0-9]+]] = !{ptr @_Z13tkernel_constIK1SEvT_, !"grid_constant", [[META3:![0-9]+]]}
 // CHECK: [[META3]] = !{i32 1}
-// CHECK: [[META4:![0-9]+]] = !{ptr @_Z13tkernel_constI1SEvT_, !"kernel", i32 1, !"grid_constant", [[META3]]}
-// CHECK: [[META5:![0-9]+]] = !{ptr @_Z7tkernelIK1SEviT_, !"kernel", i32 1, !"grid_constant", [[META6:![0-9]+]]}
+// CHECK: [[META4:![0-9]+]] = !{ptr @_Z13tkernel_constI1SEvT_, !"grid_constant", [[META3]]}
+// CHECK: [[META5:![0-9]+]] = !{ptr @_Z7tkernelIK1SEviT_, !"grid_constant", [[META6:![0-9]+]]}
 // CHECK: [[META6]] = !{i32 2}
+// CHECK: [[META7:![0-9]+]] = !{i32 1, !"wchar_size", i32 4}
+// CHECK: [[META8:![0-9]+]] = !{i32 4, !"nvvm-reflect-ftz", i32 0}
+// CHECK: [[META9:![0-9]+]] = !{!"{{.*}}clang version {{.*}}"}
 //.
diff --git a/clang/test/CodeGenCUDA/ptx-kernels.cu b/clang/test/CodeGenCUDA/ptx-kernels.cu
index b7172b77369296..dd64bd822c01e0 100644
--- a/clang/test/CodeGenCUDA/ptx-kernels.cu
+++ b/clang/test/CodeGenCUDA/ptx-kernels.cu
@@ -10,7 +10,7 @@
 extern "C"
 __device__ void device_function() {}
 
-// CHECK-LABEL: define{{.*}} void @global_function
+// CHECK-LABEL: define{{.*}} void @global_function{{.*}} #[[ATTR0:[0-9]+]]
 extern "C"
 __global__ void global_function() {
   // CHECK: call void @device_function
@@ -23,7 +23,7 @@ template <typename T> __global__ void templated_kernel(T param) {}
 
 namespace {
 __global__ void anonymous_ns_kernel() {}
-// CHECK-DAG: define{{.*}} void @_ZN12_GLOBAL__N_119anonymous_ns_kernelEv(
+// CHECK-DAG: define{{.*}} void @_ZN12_GLOBAL__N_119anonymous_ns_kernelEv({{.*}} #[[ATTR0]]
 }
 
 void host_function() {
@@ -31,5 +31,4 @@ void host_function() {
   anonymous_ns_kernel<<<0,0>>>();
 }
 
-// CHECK: !{{[0-9]+}} = !{ptr @global_function, !"kernel", i32 1}
-// CHECK: !{{[0-9]+}} = !{ptr @_Z16templated_kernelIiEvT_, !"kernel", i32 1}
+// CHECK: attributes #[[ATTR0]] = {{{.*}} "nvvm.kernel" {{.*}}}
diff --git a/clang/test/CodeGenCUDA/usual-deallocators.cu b/clang/test/CodeGenCUDA/usual-deallocators.cu
index b85a706813fc2b..21616b19ae135a 100644
--- a/clang/test/CodeGenCUDA/usual-deallocators.cu
+++ b/clang/test/CodeGenCUDA/usual-deallocators.cu
@@ -109,7 +109,7 @@ __host__ __device__ void tests_hd(void *t) {
 }
 
 // Make sure that we've generated the kernel used by A::~A.
-// DEVICE-LABEL: define void @_Z1fIiEvT_
+// DEVICE: define void @_Z1fIiEvT_{{.*}} #[[ATTR0:[0-9]+]]
 
 // Make sure we've picked deallocator for the correct side of compilation.
 
@@ -148,4 +148,4 @@ __host__ __device__ void tests_hd(void *t) {
 // DEVICE: call void @dev_fn()
 // HOST: call void @host_fn()
 
-// DEVICE: !0 = !{ptr @_Z1fIiEvT_, !"kernel", i32 1}
+// DEVICE: attributes #[[ATTR0]] = {{{.*}} "nvvm.kernel" {{.*}}}
diff --git a/clang/test/CodeGenOpenCL/ptx-calls.cl b/clang/test/CodeGenOpenCL/ptx-calls.cl
index 0081152ae40e01..c914db87572cee 100644
--- a/clang/test/CodeGenOpenCL/ptx-calls.cl
+++ b/clang/test/CodeGenOpenCL/ptx-calls.cl
@@ -7,7 +7,7 @@ void device_function() {
 __kernel void kernel_function() {
   device_function();
 }
-// CHECK-LABEL: define{{.*}} spir_kernel void @kernel_function()
+// CHECK: define{{.*}} spir_kernel void @kernel_function() #[[ATTR0:[0-9]+]]
 // CHECK: call void @device_function()
-// CHECK: !{{[0-9]+}} = !{ptr @kernel_function, !"kernel", i32 1}
+// CHECK: attributes #[[ATTR0]] = {{{.*}} "nvvm.kernel" {{.*}}}
 
diff --git a/clang/test/CodeGenOpenCL/ptx-kernels.cl b/clang/test/CodeGenOpenCL/ptx-kernels.cl
index 210e5682ac721c..93f2df6c49e82a 100644
--- a/clang/test/CodeGenOpenCL/ptx-kernels.cl
+++ b/clang/test/CodeGenOpenCL/ptx-kernels.cl
@@ -6,6 +6,6 @@ void device_function() {
 
 __kernel void kernel_function() {
 }
-// CHECK-LABEL: define{{.*}} spir_kernel void @kernel_function()
+// CHECK: define{{.*}} spir_kernel void @kernel_function() #[[ATTR0:[0-9]+]]
 
-// CHECK: !{{[0-9]+}} = !{ptr @kernel_function, !"kernel", i32 1}
+// CHECK: attributes #[[ATTR0]] = {{{.*}} "nvvm.kernel" {{.*}}}
diff --git a/clang/test/CodeGenOpenCL/reflect.cl b/clang/test/CodeGenOpenCL/reflect.cl
index 9ae4a5f027d358..88ff74022e6c5f 100644
--- a/clang/test/CodeGenOpenCL/reflect.cl
+++ b/clang/test/CodeGenOpenCL/reflect.cl
@@ -13,7 +13,7 @@ bool device_function() {
 }
 
 // CHECK-LABEL: define dso_local spir_kernel void @kernel_function(
-// CHECK-SAME: ptr addrspace(1) noundef align 4 [[I:%.*]]) #[[ATTR2:[0-9]+]] !kernel_arg_addr_space !4 !kernel_arg_access_qual !5 !kernel_arg_type !6 !kernel_arg_base_type !6 !kernel_arg_type_qual !7 {
+// CHECK-SAME: ptr addrspace(1) noundef align 4 [[I:%.*]]) #[[ATTR2:[0-9]+]] !kernel_arg_addr_space [[META3:![0-9]+]] !kernel_arg_access_qual [[META4:![0-9]+]] !kernel_arg_type [[META5:![0-9]+]] !kernel_arg_base_type [[META5]] !kernel_arg_type_qual [[META6:![0-9]+]] {
 // CHECK-NEXT:  entry:
 // CHECK-NEXT:    [[I_ADDR:%.*]] = alloca ptr addrspace(1), align 4
 // CHECK-NEXT:    store ptr addrspace(1) [[I]], ptr [[I_ADDR]], align 4
@@ -26,3 +26,9 @@ bool device_function() {
 __kernel void kernel_function(__global int *i) {
   *i = device_function();
 }
+//.
+// CHECK: [[META3]] = !{i32 1}
+// CHECK: [[META4]] = !{!"none"}
+// CHECK: [[META5]] = !{!"int*"}
+// CHECK: [[META6]] = !{!""}
+//.
diff --git a/llvm/lib/Target/NVPTX/NVVMUpgradeAnnotations.cpp b/llvm/lib/Target/NVPTX/NVVMUpgradeAnnotations.cpp
index ca550434835a2c..27415be5034f96 100644
--- a/llvm/lib/Target/NVPTX/NVVMUpgradeAnnotations.cpp
+++ b/llvm/lib/Target/NVPTX/NVVMUpgradeAnnotations.cpp
@@ -19,6 +19,7 @@
 #include "llvm/IR/Attributes.h"
 #include "llvm/IR/Constants.h"
 #include "llvm/IR/Function.h"
+#include "llvm/IR/GlobalValue.h"
 #include "llvm/IR/Metadata.h"
 #include "llvm/IR/Module.h"
 #include "llvm/IR/PassManager.h"
@@ -48,10 +49,11 @@ class NVVMUpgradeAnnotationsLegacyPass : public ModulePass {
 
 char NVVMUpgradeAnnotationsLegacyPass::ID = 0;
 
-bool static autoUpgradeAnnotation(Function *F, StringRef K, const Metadata *V) {
+bool static autoUpgradeAnnotation(GlobalValue *GV, StringRef K,
+                                  const Metadata *V) {
   if (K == "kernel") {
     assert(mdconst::extract<ConstantInt>(V)->getZExtValue() == 1);
-    F->addFnAttr("nvvm.kernel");
+    cast<Function>(GV)->addFnAttr("nvvm.kernel");
     return true;
   }
   if (K == "align") {
@@ -61,8 +63,8 @@ bool static autoUpgradeAnnotation(Function *F, StringRef K, const Metadata *V) {
     // TODO: Skip adding the stackalign attribute for returns, for now.
     if (!Idx)
       return false;
-    F->addAttributeAtIndex(
-        Idx, Attribute::getWithStackAlignment(F->getContext(), StackAlign));
+    cast<Function>(GV)->addAttributeAtIndex(
+        Idx, Attribute::getWithStackAlignment(GV->getContext(), StackAlign));
     return true;
   }
 
@@ -82,7 +84,7 @@ void static upgradeNVAnnotations(Module &M) {
       continue;
     SeenNodes.insert(MD);
 
-    Function *F = mdconst::dyn_extract_or_null<Function>(MD->getOperand(0));
+    auto *F = mdconst::dyn_extract_or_null<GlobalValue>(MD->getOperand(0));
     if (!F)
       continue;
 

>From eb96b4dcee7db603e43707a00a188937171e955b Mon Sep 17 00:00:00 2001
From: Alex Maclean <amaclean at nvidia.com>
Date: Mon, 9 Dec 2024 23:45:54 +0000
Subject: [PATCH 3/3] move to auto-upgrade

---
 llvm/include/llvm/IR/AutoUpgrade.h            |   4 +
 llvm/lib/AsmParser/LLParser.cpp               |   1 +
 llvm/lib/Bitcode/Reader/BitcodeReader.cpp     |   2 +
 llvm/lib/IR/AutoUpgrade.cpp                   |  63 +++++++++
 llvm/lib/Linker/IRMover.cpp                   |   1 +
 llvm/lib/Target/NVPTX/CMakeLists.txt          |   1 -
 llvm/lib/Target/NVPTX/NVPTX.h                 |   5 -
 llvm/lib/Target/NVPTX/NVPTXTargetMachine.cpp  |   4 -
 .../Target/NVPTX/NVVMUpgradeAnnotations.cpp   | 132 ------------------
 9 files changed, 71 insertions(+), 142 deletions(-)
 delete mode 100644 llvm/lib/Target/NVPTX/NVVMUpgradeAnnotations.cpp

diff --git a/llvm/include/llvm/IR/AutoUpgrade.h b/llvm/include/llvm/IR/AutoUpgrade.h
index 97c3e4d7589d7b..8c093568a1e031 100644
--- a/llvm/include/llvm/IR/AutoUpgrade.h
+++ b/llvm/include/llvm/IR/AutoUpgrade.h
@@ -61,6 +61,10 @@ namespace llvm {
   /// module is modified.
   bool UpgradeModuleFlags(Module &M);
 
+  /// Convert legacy nvvm.annotations metadata to appropriate function
+  /// attributes.
+  void UpgradeNVVMAnnotations(Module &M);
+
   /// Convert calls to ARC runtime functions to intrinsic calls and upgrade the
   /// old retain release marker to new module flag format.
   void UpgradeARCRuntime(Module &M);
diff --git a/llvm/lib/AsmParser/LLParser.cpp b/llvm/lib/AsmParser/LLParser.cpp
index 34311499367b41..4e869cfe312e47 100644
--- a/llvm/lib/AsmParser/LLParser.cpp
+++ b/llvm/lib/AsmParser/LLParser.cpp
@@ -448,6 +448,7 @@ bool LLParser::validateEndOfModule(bool UpgradeDebugInfo) {
     llvm::UpgradeDebugInfo(*M);
 
   UpgradeModuleFlags(*M);
+  UpgradeNVVMAnnotations(*M);
   UpgradeSectionAttributes(*M);
 
   if (PreserveInputDbgFormat != cl::boolOrDefault::BOU_TRUE)
diff --git a/llvm/lib/Bitcode/Reader/BitcodeReader.cpp b/llvm/lib/Bitcode/Reader/BitcodeReader.cpp
index 85c6fadeda6cc3..fff196aca9ffc6 100644
--- a/llvm/lib/Bitcode/Reader/BitcodeReader.cpp
+++ b/llvm/lib/Bitcode/Reader/BitcodeReader.cpp
@@ -7142,6 +7142,8 @@ Error BitcodeReader::materializeModule() {
 
   UpgradeModuleFlags(*TheModule);
 
+  UpgradeNVVMAnnotations(*TheModule);
+
   UpgradeARCRuntime(*TheModule);
 
   return Error::success();
diff --git a/llvm/lib/IR/AutoUpgrade.cpp b/llvm/lib/IR/AutoUpgrade.cpp
index e73538da282e99..d774606bac9448 100644
--- a/llvm/lib/IR/AutoUpgrade.cpp
+++ b/llvm/lib/IR/AutoUpgrade.cpp
@@ -5022,6 +5022,69 @@ bool llvm::UpgradeDebugInfo(Module &M) {
   return Modified;
 }
 
+bool static upgradeSingleNVVMAnnotation(GlobalValue *GV, StringRef K,
+                                        const Metadata *V) {
+  if (K == "kernel") {
+    assert(mdconst::extract<ConstantInt>(V)->getZExtValue() == 1);
+    cast<Function>(GV)->addFnAttr("nvvm.kernel");
+    return true;
+  }
+  if (K == "align") {
+    const uint64_t AlignBits = mdconst::extract<ConstantInt>(V)->getZExtValue();
+    const unsigned Idx = (AlignBits >> 16);
+    const Align StackAlign = Align(AlignBits & 0xFFFF);
+    // TODO: Skip adding the stackalign attribute for returns, for now.
+    if (!Idx)
+      return false;
+    cast<Function>(GV)->addAttributeAtIndex(
+        Idx, Attribute::getWithStackAlignment(GV->getContext(), StackAlign));
+    return true;
+  }
+
+  return false;
+}
+
+void llvm::UpgradeNVVMAnnotations(Module &M) {
+  NamedMDNode *NamedMD = M.getNamedMetadata("nvvm.annotations");
+  if (!NamedMD)
+    return;
+
+  SmallVector<MDNode *, 8> NewNodes;
+  SmallSet<const MDNode *, 8> SeenNodes;
+  for (MDNode *MD : NamedMD->operands()) {
+    if (SeenNodes.contains(MD))
+      continue;
+    SeenNodes.insert(MD);
+
+    auto *F = mdconst::dyn_extract_or_null<GlobalValue>(MD->getOperand(0));
+    if (!F)
+      continue;
+
+    assert(MD && "Invalid MDNode for annotation");
+    assert((MD->getNumOperands() % 2) == 1 && "Invalid number of operands");
+
+    SmallVector<Metadata *, 8> NewOperands;
+    // start index = 1, to skip the global variable key
+    // increment = 2, to skip the value for each property-value pairs
+    for (unsigned j = 1, je = MD->getNumOperands(); j < je; j += 2) {
+      MDString *K = cast<MDString>(MD->getOperand(j));
+      const MDOperand &V = MD->getOperand(j + 1);
+      bool Upgraded = upgradeSingleNVVMAnnotation(F, K->getString(), V);
+      if (!Upgraded)
+        NewOperands.append({K, V});
+    }
+
+    if (!NewOperands.empty()) {
+      NewOperands.insert(NewOperands.begin(), MD->getOperand(0));
+      NewNodes.push_back(MDNode::get(M.getContext(), NewOperands));
+    }
+  }
+
+  NamedMD->clearOperands();
+  for (MDNode *N : NewNodes)
+    NamedMD->addOperand(N);
+}
+
 /// This checks for objc retain release marker which should be upgraded. It
 /// returns true if module is modified.
 static bool upgradeRetainReleaseMarker(Module &M) {
diff --git a/llvm/lib/Linker/IRMover.cpp b/llvm/lib/Linker/IRMover.cpp
index a0c3f2c5b0baf6..5681c4257a90ad 100644
--- a/llvm/lib/Linker/IRMover.cpp
+++ b/llvm/lib/Linker/IRMover.cpp
@@ -1247,6 +1247,7 @@ Error IRLinker::linkModuleFlagsMetadata() {
 
   // Check for module flag for updates before do anything.
   UpgradeModuleFlags(*SrcM);
+  UpgradeNVVMAnnotations(*SrcM);
 
   // If the destination module doesn't have module flags yet, then just copy
   // over the source module's flags.
diff --git a/llvm/lib/Target/NVPTX/CMakeLists.txt b/llvm/lib/Target/NVPTX/CMakeLists.txt
index bb2e4ad48b51d8..693365161330f5 100644
--- a/llvm/lib/Target/NVPTX/CMakeLists.txt
+++ b/llvm/lib/Target/NVPTX/CMakeLists.txt
@@ -39,7 +39,6 @@ set(NVPTXCodeGen_sources
   NVVMReflect.cpp
   NVPTXProxyRegErasure.cpp
   NVPTXCtorDtorLowering.cpp
-  NVVMUpgradeAnnotations.cpp
   )
 
 add_llvm_target(NVPTXCodeGen
diff --git a/llvm/lib/Target/NVPTX/NVPTX.h b/llvm/lib/Target/NVPTX/NVPTX.h
index 53418148be3615..ca915cd3f3732f 100644
--- a/llvm/lib/Target/NVPTX/NVPTX.h
+++ b/llvm/lib/Target/NVPTX/NVPTX.h
@@ -52,7 +52,6 @@ FunctionPass *createNVPTXLowerUnreachablePass(bool TrapUnreachable,
                                               bool NoTrapAfterNoreturn);
 MachineFunctionPass *createNVPTXPeephole();
 MachineFunctionPass *createNVPTXProxyRegErasurePass();
-ModulePass *createNVVMUpgradeAnnotationsPass();
 
 struct NVVMIntrRangePass : PassInfoMixin<NVVMIntrRangePass> {
   PreservedAnalyses run(Function &F, FunctionAnalysisManager &AM);
@@ -75,10 +74,6 @@ struct NVPTXCopyByValArgsPass : PassInfoMixin<NVPTXCopyByValArgsPass> {
   PreservedAnalyses run(Function &F, FunctionAnalysisManager &AM);
 };
 
-struct NVVMUpgradeAnnotationsPass : PassInfoMixin<NVVMUpgradeAnnotationsPass> {
-  PreservedAnalyses run(Module &M, ModuleAnalysisManager &AM);
-};
-
 namespace NVPTX {
 enum DrvInterface {
   NVCL,
diff --git a/llvm/lib/Target/NVPTX/NVPTXTargetMachine.cpp b/llvm/lib/Target/NVPTX/NVPTXTargetMachine.cpp
index b4fd36625adc9c..a5c5e9420ee737 100644
--- a/llvm/lib/Target/NVPTX/NVPTXTargetMachine.cpp
+++ b/llvm/lib/Target/NVPTX/NVPTXTargetMachine.cpp
@@ -254,8 +254,6 @@ void NVPTXTargetMachine::registerPassBuilderCallbacks(PassBuilder &PB) {
 
   PB.registerPipelineStartEPCallback(
       [this](ModulePassManager &PM, OptimizationLevel Level) {
-        PM.addPass(NVVMUpgradeAnnotationsPass());
-
         FunctionPassManager FPM;
         FPM.addPass(NVVMReflectPass(Subtarget.getSmVersion()));
         // Note: NVVMIntrRangePass was causing numerical discrepancies at one
@@ -351,8 +349,6 @@ void NVPTXPassConfig::addIRPasses() {
       AAR.addAAResult(WrapperPass->getResult());
   }));
 
-  addPass(createNVVMUpgradeAnnotationsPass());
-
   // NVVMReflectPass is added in addEarlyAsPossiblePasses, so hopefully running
   // it here does nothing.  But since we need it for correctness when lowering
   // to NVPTX, run it here too, in case whoever built our pass pipeline didn't
diff --git a/llvm/lib/Target/NVPTX/NVVMUpgradeAnnotations.cpp b/llvm/lib/Target/NVPTX/NVVMUpgradeAnnotations.cpp
deleted file mode 100644
index 27415be5034f96..00000000000000
--- a/llvm/lib/Target/NVPTX/NVVMUpgradeAnnotations.cpp
+++ /dev/null
@@ -1,132 +0,0 @@
-//===- NVVMUpgradeAnnotations.cpp - Upgrade NVVM Annotations --------------===//
-//
-// 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 replaces deprecated metadata in nvvm.annotation with a more modern
-// IR representation.
-//
-//===----------------------------------------------------------------------===//
-
-#include "NVPTX.h"
-#include "llvm/ADT/SmallSet.h"
-#include "llvm/ADT/SmallVector.h"
-#include "llvm/ADT/StringRef.h"
-#include "llvm/CodeGen/Passes.h"
-#include "llvm/IR/Attributes.h"
-#include "llvm/IR/Constants.h"
-#include "llvm/IR/Function.h"
-#include "llvm/IR/GlobalValue.h"
-#include "llvm/IR/Metadata.h"
-#include "llvm/IR/Module.h"
-#include "llvm/IR/PassManager.h"
-#include "llvm/Pass.h"
-#include <cstdint>
-
-#define DEBUG_TYPE "nvvm-upgrade-annotations"
-
-using namespace llvm;
-
-namespace llvm {
-void initializeNVVMUpgradeAnnotationsLegacyPassPass(PassRegistry &);
-} // namespace llvm
-
-namespace {
-
-class NVVMUpgradeAnnotationsLegacyPass : public ModulePass {
-public:
-  static char ID;
-  NVVMUpgradeAnnotationsLegacyPass() : ModulePass(ID) {
-    initializeNVVMUpgradeAnnotationsLegacyPassPass(
-        *PassRegistry::getPassRegistry());
-  }
-  bool runOnModule(Module &M) override;
-};
-} // namespace
-
-char NVVMUpgradeAnnotationsLegacyPass::ID = 0;
-
-bool static autoUpgradeAnnotation(GlobalValue *GV, StringRef K,
-                                  const Metadata *V) {
-  if (K == "kernel") {
-    assert(mdconst::extract<ConstantInt>(V)->getZExtValue() == 1);
-    cast<Function>(GV)->addFnAttr("nvvm.kernel");
-    return true;
-  }
-  if (K == "align") {
-    const uint64_t AlignBits = mdconst::extract<ConstantInt>(V)->getZExtValue();
-    const unsigned Idx = (AlignBits >> 16);
-    const Align StackAlign = Align(AlignBits & 0xFFFF);
-    // TODO: Skip adding the stackalign attribute for returns, for now.
-    if (!Idx)
-      return false;
-    cast<Function>(GV)->addAttributeAtIndex(
-        Idx, Attribute::getWithStackAlignment(GV->getContext(), StackAlign));
-    return true;
-  }
-
-  return false;
-}
-
-// Iterate over nvvm.annotations rewriting them as appropiate.
-void static upgradeNVAnnotations(Module &M) {
-  NamedMDNode *NamedMD = M.getNamedMetadata("nvvm.annotations");
-  if (!NamedMD)
-    return;
-
-  SmallVector<MDNode *, 8> NewNodes;
-  SmallSet<const MDNode *, 8> SeenNodes;
-  for (MDNode *MD : NamedMD->operands()) {
-    if (SeenNodes.contains(MD))
-      continue;
-    SeenNodes.insert(MD);
-
-    auto *F = mdconst::dyn_extract_or_null<GlobalValue>(MD->getOperand(0));
-    if (!F)
-      continue;
-
-    assert(MD && "Invalid MDNode for annotation");
-    assert((MD->getNumOperands() % 2) == 1 && "Invalid number of operands");
-
-    SmallVector<Metadata *, 8> NewOperands;
-    // start index = 1, to skip the global variable key
-    // increment = 2, to skip the value for each property-value pairs
-    for (unsigned j = 1, je = MD->getNumOperands(); j < je; j += 2) {
-      MDString *K = cast<MDString>(MD->getOperand(j));
-      const MDOperand &V = MD->getOperand(j + 1);
-      bool Upgraded = autoUpgradeAnnotation(F, K->getString(), V);
-      if (!Upgraded)
-        NewOperands.append({K, V});
-    }
-
-    if (!NewOperands.empty()) {
-      NewOperands.insert(NewOperands.begin(), MD->getOperand(0));
-      NewNodes.push_back(MDNode::get(M.getContext(), NewOperands));
-    }
-  }
-
-  NamedMD->clearOperands();
-  for (MDNode *N : NewNodes)
-    NamedMD->addOperand(N);
-}
-
-PreservedAnalyses NVVMUpgradeAnnotationsPass::run(Module &M,
-                                                  ModuleAnalysisManager &AM) {
-  upgradeNVAnnotations(M);
-  return PreservedAnalyses::all();
-}
-
-bool NVVMUpgradeAnnotationsLegacyPass::runOnModule(Module &M) {
-  upgradeNVAnnotations(M);
-  return false;
-}
-
-INITIALIZE_PASS(NVVMUpgradeAnnotationsLegacyPass, DEBUG_TYPE,
-                "NVVMUpgradeAnnotations", false, false)
-
-ModulePass *llvm::createNVVMUpgradeAnnotationsPass() {
-  return new NVVMUpgradeAnnotationsLegacyPass();
-}



More information about the llvm-commits mailing list