Skip to content

Commit de7438e

Browse files
authored
[NVPTX] Auto-Upgrade some nvvm.annotations to attributes (#119261)
Add a new AutoUpgrade function to convert some legacy nvvm.annotations metadata to function level attributes. These attributes are quicker to look-up so improve compile time and are more idiomatic than using metadata which should not include required information that changes the meaning of the program. Currently supported annotations are: - !"kernel" -> ptx_kernel calling convention - !"align" -> alignstack parameter attributes (return not yet supported)
1 parent f0d05b0 commit de7438e

File tree

9 files changed

+122
-43
lines changed

9 files changed

+122
-43
lines changed

llvm/include/llvm/IR/AutoUpgrade.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,10 @@ namespace llvm {
6161
/// module is modified.
6262
bool UpgradeModuleFlags(Module &M);
6363

64+
/// Convert legacy nvvm.annotations metadata to appropriate function
65+
/// attributes.
66+
void UpgradeNVVMAnnotations(Module &M);
67+
6468
/// Convert calls to ARC runtime functions to intrinsic calls and upgrade the
6569
/// old retain release marker to new module flag format.
6670
void UpgradeARCRuntime(Module &M);

llvm/lib/AsmParser/LLParser.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -448,6 +448,7 @@ bool LLParser::validateEndOfModule(bool UpgradeDebugInfo) {
448448
llvm::UpgradeDebugInfo(*M);
449449

450450
UpgradeModuleFlags(*M);
451+
UpgradeNVVMAnnotations(*M);
451452
UpgradeSectionAttributes(*M);
452453

453454
if (PreserveInputDbgFormat != cl::boolOrDefault::BOU_TRUE)

llvm/lib/Bitcode/Reader/BitcodeReader.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7157,6 +7157,8 @@ Error BitcodeReader::materializeModule() {
71577157

71587158
UpgradeModuleFlags(*TheModule);
71597159

7160+
UpgradeNVVMAnnotations(*TheModule);
7161+
71607162
UpgradeARCRuntime(*TheModule);
71617163

71627164
return Error::success();

llvm/lib/IR/AutoUpgrade.cpp

Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
#include "llvm/ADT/StringSwitch.h"
1818
#include "llvm/BinaryFormat/Dwarf.h"
1919
#include "llvm/IR/AttributeMask.h"
20+
#include "llvm/IR/CallingConv.h"
2021
#include "llvm/IR/Constants.h"
2122
#include "llvm/IR/DebugInfo.h"
2223
#include "llvm/IR/DebugInfoMetadata.h"
@@ -5019,6 +5020,72 @@ bool llvm::UpgradeDebugInfo(Module &M) {
50195020
return Modified;
50205021
}
50215022

5023+
bool static upgradeSingleNVVMAnnotation(GlobalValue *GV, StringRef K,
5024+
const Metadata *V) {
5025+
if (K == "kernel") {
5026+
if (!mdconst::extract<ConstantInt>(V)->isZero())
5027+
cast<Function>(GV)->setCallingConv(CallingConv::PTX_Kernel);
5028+
return true;
5029+
}
5030+
if (K == "align") {
5031+
// V is a bitfeild specifying two 16-bit values. The alignment value is
5032+
// specfied in low 16-bits, The index is specified in the high bits. For the
5033+
// index, 0 indicates the return value while higher values correspond to
5034+
// each parameter (idx = param + 1).
5035+
const uint64_t AlignIdxValuePair =
5036+
mdconst::extract<ConstantInt>(V)->getZExtValue();
5037+
const unsigned Idx = (AlignIdxValuePair >> 16);
5038+
const Align StackAlign = Align(AlignIdxValuePair & 0xFFFF);
5039+
// TODO: Skip adding the stackalign attribute for returns, for now.
5040+
if (!Idx)
5041+
return false;
5042+
cast<Function>(GV)->addAttributeAtIndex(
5043+
Idx, Attribute::getWithStackAlignment(GV->getContext(), StackAlign));
5044+
return true;
5045+
}
5046+
5047+
return false;
5048+
}
5049+
5050+
void llvm::UpgradeNVVMAnnotations(Module &M) {
5051+
NamedMDNode *NamedMD = M.getNamedMetadata("nvvm.annotations");
5052+
if (!NamedMD)
5053+
return;
5054+
5055+
SmallVector<MDNode *, 8> NewNodes;
5056+
SmallSet<const MDNode *, 8> SeenNodes;
5057+
for (MDNode *MD : NamedMD->operands()) {
5058+
if (!SeenNodes.insert(MD).second)
5059+
continue;
5060+
5061+
auto *GV = mdconst::dyn_extract_or_null<GlobalValue>(MD->getOperand(0));
5062+
if (!GV)
5063+
continue;
5064+
5065+
assert((MD->getNumOperands() % 2) == 1 && "Invalid number of operands");
5066+
5067+
SmallVector<Metadata *, 8> NewOperands{MD->getOperand(0)};
5068+
// Each nvvm.annotations metadata entry will be of the following form:
5069+
// !{ ptr @gv, !"key1", value1, !"key2", value2, ... }
5070+
// start index = 1, to skip the global variable key
5071+
// increment = 2, to skip the value for each property-value pairs
5072+
for (unsigned j = 1, je = MD->getNumOperands(); j < je; j += 2) {
5073+
MDString *K = cast<MDString>(MD->getOperand(j));
5074+
const MDOperand &V = MD->getOperand(j + 1);
5075+
bool Upgraded = upgradeSingleNVVMAnnotation(GV, K->getString(), V);
5076+
if (!Upgraded)
5077+
NewOperands.append({K, V});
5078+
}
5079+
5080+
if (NewOperands.size() > 1)
5081+
NewNodes.push_back(MDNode::get(M.getContext(), NewOperands));
5082+
}
5083+
5084+
NamedMD->clearOperands();
5085+
for (MDNode *N : NewNodes)
5086+
NamedMD->addOperand(N);
5087+
}
5088+
50225089
/// This checks for objc retain release marker which should be upgraded. It
50235090
/// returns true if module is modified.
50245091
static bool upgradeRetainReleaseMarker(Module &M) {

llvm/lib/Linker/IRMover.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1244,6 +1244,7 @@ Error IRLinker::linkModuleFlagsMetadata() {
12441244

12451245
// Check for module flag for updates before do anything.
12461246
UpgradeModuleFlags(*SrcM);
1247+
UpgradeNVVMAnnotations(*SrcM);
12471248

12481249
// If the destination module doesn't have module flags yet, then just copy
12491250
// over the source module's flags.

llvm/lib/Target/NVPTX/NVPTXUtilities.cpp

Lines changed: 9 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -310,30 +310,21 @@ std::optional<unsigned> getMaxNReg(const Function &F) {
310310
return findOneNVVMAnnotation(&F, "maxnreg");
311311
}
312312

313-
bool isKernelFunction(const Function &F) {
314-
if (F.getCallingConv() == CallingConv::PTX_Kernel)
315-
return true;
316-
317-
if (const auto X = findOneNVVMAnnotation(&F, "kernel"))
318-
return (*X == 1);
319-
320-
return false;
321-
}
322-
323313
MaybeAlign getAlign(const Function &F, unsigned Index) {
324314
// First check the alignstack metadata
325315
if (MaybeAlign StackAlign =
326316
F.getAttributes().getAttributes(Index).getStackAlignment())
327317
return StackAlign;
328318

329-
// If that is missing, check the legacy nvvm metadata
330-
std::vector<unsigned> Vs;
331-
bool retval = findAllNVVMAnnotation(&F, "align", Vs);
332-
if (!retval)
333-
return std::nullopt;
334-
for (unsigned V : Vs)
335-
if ((V >> 16) == Index)
336-
return Align(V & 0xFFFF);
319+
// check the legacy nvvm metadata only for the return value since llvm does
320+
// not support stackalign attribute for this.
321+
if (Index == 0) {
322+
std::vector<unsigned> Vs;
323+
if (findAllNVVMAnnotation(&F, "align", Vs))
324+
for (unsigned V : Vs)
325+
if ((V >> 16) == Index)
326+
return Align(V & 0xFFFF);
327+
}
337328

338329
return std::nullopt;
339330
}

llvm/lib/Target/NVPTX/NVPTXUtilities.h

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
#include "NVPTX.h"
1717
#include "llvm/ADT/StringExtras.h"
1818
#include "llvm/CodeGen/ValueTypes.h"
19+
#include "llvm/IR/CallingConv.h"
1920
#include "llvm/IR/Function.h"
2021
#include "llvm/IR/GlobalVariable.h"
2122
#include "llvm/IR/IntrinsicInst.h"
@@ -63,7 +64,11 @@ std::optional<unsigned> getClusterDimz(const Function &);
6364
std::optional<unsigned> getMaxClusterRank(const Function &);
6465
std::optional<unsigned> getMinCTASm(const Function &);
6566
std::optional<unsigned> getMaxNReg(const Function &);
66-
bool isKernelFunction(const Function &);
67+
68+
inline bool isKernelFunction(const Function &F) {
69+
return F.getCallingConv() == CallingConv::PTX_Kernel;
70+
}
71+
6772
bool isParamGridConstant(const Value &);
6873

6974
MaybeAlign getAlign(const Function &, unsigned);

llvm/lib/Transforms/IPO/OpenMPOpt.cpp

Lines changed: 4 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -5906,39 +5906,19 @@ bool llvm::omp::isOpenMPKernel(Function &Fn) {
59065906
}
59075907

59085908
KernelSet llvm::omp::getDeviceKernels(Module &M) {
5909-
// TODO: Create a more cross-platform way of determining device kernels.
59105909
KernelSet Kernels;
59115910

5912-
DenseSet<const Function *> SeenKernels;
5913-
auto ProcessKernel = [&](Function &KF) {
5914-
if (SeenKernels.insert(&KF).second) {
5911+
for (Function &F : M)
5912+
if (F.hasKernelCallingConv()) {
59155913
// We are only interested in OpenMP target regions. Others, such as
59165914
// kernels generated by CUDA but linked together, are not interesting to
59175915
// this pass.
5918-
if (isOpenMPKernel(KF)) {
5916+
if (isOpenMPKernel(F)) {
59195917
++NumOpenMPTargetRegionKernels;
5920-
Kernels.insert(&KF);
5918+
Kernels.insert(&F);
59215919
} else
59225920
++NumNonOpenMPTargetRegionKernels;
59235921
}
5924-
};
5925-
5926-
if (NamedMDNode *MD = M.getNamedMetadata("nvvm.annotations"))
5927-
for (auto *Op : MD->operands()) {
5928-
if (Op->getNumOperands() < 2)
5929-
continue;
5930-
MDString *KindID = dyn_cast<MDString>(Op->getOperand(1));
5931-
if (!KindID || KindID->getString() != "kernel")
5932-
continue;
5933-
5934-
if (auto *KernelFn =
5935-
mdconst::dyn_extract_or_null<Function>(Op->getOperand(0)))
5936-
ProcessKernel(*KernelFn);
5937-
}
5938-
5939-
for (Function &F : M)
5940-
if (F.hasKernelCallingConv())
5941-
ProcessKernel(F);
59425922

59435923
return Kernels;
59445924
}
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --check-attributes --check-globals all --version 5
2+
; RUN: opt < %s -mtriple=nvptx64-unknown-unknown -O0 -S | FileCheck %s
3+
4+
define i32 @foo(i32 %a, i32 %b) {
5+
; CHECK-LABEL: define i32 @foo(
6+
; CHECK-SAME: i32 alignstack(8) [[A:%.*]], i32 alignstack(16) [[B:%.*]]) {
7+
; CHECK-NEXT: ret i32 0
8+
;
9+
ret i32 0
10+
}
11+
12+
define i32 @bar(i32 %a, i32 %b) {
13+
; CHECK-LABEL: define ptx_kernel i32 @bar(
14+
; CHECK-SAME: i32 [[A:%.*]], i32 [[B:%.*]]) {
15+
; CHECK-NEXT: ret i32 0
16+
;
17+
ret i32 0
18+
}
19+
20+
!nvvm.annotations = !{!0, !1, !2}
21+
22+
!0 = !{ptr @foo, !"align", i32 u0x00000008, !"align", i32 u0x00010008, !"align", i32 u0x00020010}
23+
!1 = !{null, !"align", i32 u0x00000008, !"align", i32 u0x00010008, !"align", i32 u0x00020008}
24+
!2 = !{ptr @bar, !"kernel", i32 1}
25+
26+
;.
27+
; CHECK: [[META0:![0-9]+]] = !{ptr @foo, !"align", i32 8}
28+
;.

0 commit comments

Comments
 (0)