Skip to content

Commit 6c2e170

Browse files
authored
[NVPTX] Convert vector function nvvm.annotations to attributes (#127736)
Replace some more nvvm.annotations with function attributes, auto-upgrading the annotations as needed. These new attributes will be more idiomatic and compile-time efficient than the annotations. - !"maxntid[xyz]" -> "nvvm.maxntid" - !"reqntid[xyz]" -> "nvvm.reqntid" - !"cluster_dim_[xyz]" -> "nvvm.cluster_dim"
1 parent 14da7d5 commit 6c2e170

23 files changed

+306
-317
lines changed

clang/lib/CodeGen/Targets/NVPTX.cpp

+2-6
Original file line numberDiff line numberDiff line change
@@ -357,17 +357,13 @@ void CodeGenModule::handleCUDALaunchBoundsAttr(llvm::Function *F,
357357
int32_t *MaxThreadsVal,
358358
int32_t *MinBlocksVal,
359359
int32_t *MaxClusterRankVal) {
360-
// Create !{<func-ref>, metadata !"maxntidx", i32 <val>} node
361360
llvm::APSInt MaxThreads(32);
362361
MaxThreads = Attr->getMaxThreads()->EvaluateKnownConstInt(getContext());
363362
if (MaxThreads > 0) {
364363
if (MaxThreadsVal)
365364
*MaxThreadsVal = MaxThreads.getExtValue();
366-
if (F) {
367-
// Create !{<func-ref>, metadata !"maxntidx", i32 <val>} node
368-
NVPTXTargetCodeGenInfo::addNVVMMetadata(F, "maxntidx",
369-
MaxThreads.getExtValue());
370-
}
365+
if (F)
366+
F->addFnAttr("nvvm.maxntid", llvm::utostr(MaxThreads.getExtValue()));
371367
}
372368

373369
// min and max blocks is an optional argument for CUDALaunchBoundsAttr. If it

clang/test/CodeGenCUDA/launch-bounds.cu

+23-36
Original file line numberDiff line numberDiff line change
@@ -10,23 +10,30 @@
1010
#endif
1111

1212
// CHECK: @Kernel1() #[[ATTR0:[0-9]+]]
13+
// CHECK: @Kernel2() #[[ATTR1:[0-9]+]]
14+
// CHECK: @{{.*}}Kernel3{{.*}}() #[[ATTR1]]
1315
// CHECK: @{{.*}}Kernel4{{.*}}() #[[ATTR0]]
14-
// CHECK: @{{.*}}Kernel5{{.*}}() #[[ATTR1:[0-9]+]]
15-
// CHECK: @{{.*}}Kernel6{{.*}}() #[[ATTR0]]
16-
// CHECK: @{{.*}}Kernel8{{.*}}() #[[ATTR3:[0-9]+]]
17-
18-
// CHECK: attributes #[[ATTR0]] = {{{.*}} "nvvm.minctasm"="2" {{.*}}}
19-
// CHECK: attributes #[[ATTR1]] = {{{.*}} "nvvm.minctasm"="258" {{.*}}}
20-
// CHECK: attributes #[[ATTR3]] = {{{.*}} "nvvm.minctasm"="12" {{.*}}}
21-
22-
// CHECK_MAX_BLOCKS: @Kernel1_sm_90() #[[ATTR4:[0-9]+]]
23-
// CHECK_MAX_BLOCKS: @{{.*}}Kernel4_sm_90{{.*}} #[[ATTR4]]
24-
// CHECK_MAX_BLOCKS: @{{.*}}Kernel5_sm_90{{.*}} #[[ATTR5:[0-9]+]]
25-
// CHECK_MAX_BLOCKS: @{{.*}}Kernel8_sm_90{{.*}} #[[ATTR6:[0-9]+]]
26-
27-
// CHECK_MAX_BLOCKS: attributes #[[ATTR4]] = {{{.*}} "nvvm.maxclusterrank"="4" "nvvm.minctasm"="2" {{.*}}}
28-
// CHECK_MAX_BLOCKS: attributes #[[ATTR5]] = {{{.*}} "nvvm.maxclusterrank"="260" "nvvm.minctasm"="258" {{.*}}}
29-
// CHECK_MAX_BLOCKS: attributes #[[ATTR6]] = {{{.*}} "nvvm.maxclusterrank"="14" "nvvm.minctasm"="12" {{.*}}}
16+
// CHECK: @{{.*}}Kernel5{{.*}}() #[[ATTR2:[0-9]+]]
17+
// CHECK: @{{.*}}Kernel6{{.*}}() #[[ATTR3:[0-9]+]]
18+
// CHECK: @{{.*}}Kernel7{{.*}}() #[[ATTR1]]
19+
// CHECK: @{{.*}}Kernel8{{.*}}() #[[ATTR4:[0-9]+]]
20+
21+
// CHECK-DAG: attributes #[[ATTR0]] = {{{.*}} "nvvm.maxntid"="256" "nvvm.minctasm"="2" {{.*}}}
22+
// CHECK-DAG: attributes #[[ATTR1]] = {{{.*}} "nvvm.maxntid"="256" {{.*}}}
23+
// CHECK-DAG: attributes #[[ATTR2]] = {{{.*}} "nvvm.maxntid"="356" "nvvm.minctasm"="258" {{.*}}}
24+
// CHECK-DAG: attributes #[[ATTR3]] = {{{.*}} "nvvm.minctasm"="2" {{.*}}}
25+
// CHECK-DAG: attributes #[[ATTR4]] = {{{.*}} "nvvm.maxntid"="100" "nvvm.minctasm"="12" {{.*}}}
26+
27+
// CHECK_MAX_BLOCKS: @Kernel1_sm_90() #[[ATTR0:[0-9]+]]
28+
// CHECK_MAX_BLOCKS: @{{.*}}Kernel4_sm_90{{.*}} #[[ATTR0]]
29+
// CHECK_MAX_BLOCKS: @{{.*}}Kernel5_sm_90{{.*}} #[[ATTR1:[0-9]+]]
30+
// CHECK_MAX_BLOCKS: @{{.*}}Kernel7_sm_90{{.*}} #[[ATTR2:[0-9]+]]
31+
// CHECK_MAX_BLOCKS: @{{.*}}Kernel8_sm_90{{.*}} #[[ATTR3:[0-9]+]]
32+
33+
// CHECK_MAX_BLOCKS-DAG: attributes #[[ATTR0]] = {{{.*}} "nvvm.maxclusterrank"="4" "nvvm.maxntid"="256" "nvvm.minctasm"="2" {{.*}}}
34+
// CHECK_MAX_BLOCKS-DAG: attributes #[[ATTR1]] = {{{.*}} "nvvm.maxclusterrank"="260" "nvvm.maxntid"="356" "nvvm.minctasm"="258" {{.*}}}
35+
// CHECK_MAX_BLOCKS-DAG: attributes #[[ATTR2]] = {{{.*}} "nvvm.maxntid"="256" {{.*}}}
36+
// CHECK_MAX_BLOCKS-DAG: attributes #[[ATTR3]] = {{{.*}} "nvvm.maxclusterrank"="14" "nvvm.maxntid"="100" "nvvm.minctasm"="12" {{.*}}}
3037

3138
// Test both max threads per block and Min cta per sm.
3239
extern "C" {
@@ -37,8 +44,6 @@ Kernel1()
3744
}
3845
}
3946

40-
// CHECK: !{{[0-9]+}} = !{ptr @Kernel1, !"maxntidx", i32 256}
41-
4247
#ifdef USE_MAX_BLOCKS
4348
// Test max threads per block and min/max cta per sm.
4449
extern "C" {
@@ -48,8 +53,6 @@ Kernel1_sm_90()
4853
{
4954
}
5055
}
51-
52-
// CHECK_MAX_BLOCKS: !{{[0-9]+}} = !{ptr @Kernel1_sm_90, !"maxntidx", i32 256}
5356
#endif // USE_MAX_BLOCKS
5457

5558
// Test only max threads per block. Min cta per sm defaults to 0, and
@@ -62,8 +65,6 @@ Kernel2()
6265
}
6366
}
6467

65-
// CHECK: !{{[0-9]+}} = !{ptr @Kernel2, !"maxntidx", i32 256}
66-
6768
template <int max_threads_per_block>
6869
__global__ void
6970
__launch_bounds__(max_threads_per_block)
@@ -72,7 +73,6 @@ Kernel3()
7273
}
7374

7475
template __global__ void Kernel3<MAX_THREADS_PER_BLOCK>();
75-
// CHECK: !{{[0-9]+}} = !{ptr @{{.*}}Kernel3{{.*}}, !"maxntidx", i32 256}
7676

7777
template <int max_threads_per_block, int min_blocks_per_mp>
7878
__global__ void
@@ -82,7 +82,6 @@ Kernel4()
8282
}
8383
template __global__ void Kernel4<MAX_THREADS_PER_BLOCK, MIN_BLOCKS_PER_MP>();
8484

85-
// CHECK: !{{[0-9]+}} = !{ptr @{{.*}}Kernel4{{.*}}, !"maxntidx", i32 256}
8685

8786
#ifdef USE_MAX_BLOCKS
8887
template <int max_threads_per_block, int min_blocks_per_mp, int max_blocks_per_mp>
@@ -93,7 +92,6 @@ Kernel4_sm_90()
9392
}
9493
template __global__ void Kernel4_sm_90<MAX_THREADS_PER_BLOCK, MIN_BLOCKS_PER_MP, MAX_BLOCKS_PER_MP>();
9594

96-
// CHECK_MAX_BLOCKS: !{{[0-9]+}} = !{ptr @{{.*}}Kernel4_sm_90{{.*}}, !"maxntidx", i32 256}
9795
#endif //USE_MAX_BLOCKS
9896

9997
const int constint = 100;
@@ -106,8 +104,6 @@ Kernel5()
106104
}
107105
template __global__ void Kernel5<MAX_THREADS_PER_BLOCK, MIN_BLOCKS_PER_MP>();
108106

109-
// CHECK: !{{[0-9]+}} = !{ptr @{{.*}}Kernel5{{.*}}, !"maxntidx", i32 356}
110-
111107
#ifdef USE_MAX_BLOCKS
112108

113109
template <int max_threads_per_block, int min_blocks_per_mp, int max_blocks_per_mp>
@@ -120,7 +116,6 @@ Kernel5_sm_90()
120116
}
121117
template __global__ void Kernel5_sm_90<MAX_THREADS_PER_BLOCK, MIN_BLOCKS_PER_MP, MAX_BLOCKS_PER_MP>();
122118

123-
// CHECK_MAX_BLOCKS: !{{[0-9]+}} = !{ptr @{{.*}}Kernel5_sm_90{{.*}}, !"maxntidx", i32 356}
124119
#endif //USE_MAX_BLOCKS
125120

126121
// Make sure we don't emit negative launch bounds values.
@@ -129,33 +124,25 @@ __launch_bounds__( -MAX_THREADS_PER_BLOCK, MIN_BLOCKS_PER_MP )
129124
Kernel6()
130125
{
131126
}
132-
// CHECK-NOT: !{{[0-9]+}} = !{ptr @{{.*}}Kernel6{{.*}}, !"maxntidx",
133127

134128
__global__ void
135129
__launch_bounds__( MAX_THREADS_PER_BLOCK, -MIN_BLOCKS_PER_MP )
136130
Kernel7()
137131
{
138132
}
139-
// CHECK: !{{[0-9]+}} = !{ptr @{{.*}}Kernel7{{.*}}, !"maxntidx",
140-
// CHECK-NOT: !{{[0-9]+}} = !{ptr @{{.*}}Kernel7{{.*}}, !"minctasm",
141133

142134
#ifdef USE_MAX_BLOCKS
143135
__global__ void
144136
__launch_bounds__( MAX_THREADS_PER_BLOCK, -MIN_BLOCKS_PER_MP, -MAX_BLOCKS_PER_MP )
145137
Kernel7_sm_90()
146138
{
147139
}
148-
// CHECK_MAX_BLOCKS: !{{[0-9]+}} = !{ptr @{{.*}}Kernel7_sm_90{{.*}}, !"maxntidx",
149-
// CHECK_MAX_BLOCKS-NOT: !{{[0-9]+}} = !{ptr @{{.*}}Kernel7_sm_90{{.*}}, !"minctasm",
150-
// CHECK_MAX_BLOCKS-NOT: !{{[0-9]+}} = !{ptr @{{.*}}Kernel7_sm_90{{.*}}, !"maxclusterrank",
151140
#endif // USE_MAX_BLOCKS
152141

153142
const char constchar = 12;
154143
__global__ void __launch_bounds__(constint, constchar) Kernel8() {}
155-
// CHECK: !{{[0-9]+}} = !{ptr @{{.*}}Kernel8{{.*}}, !"maxntidx", i32 100
156144

157145
#ifdef USE_MAX_BLOCKS
158146
const char constchar_2 = 14;
159147
__global__ void __launch_bounds__(constint, constchar, constchar_2) Kernel8_sm_90() {}
160-
// CHECK_MAX_BLOCKS: !{{[0-9]+}} = !{ptr @{{.*}}Kernel8_sm_90{{.*}}, !"maxntidx", i32 100
161148
#endif // USE_MAX_BLOCKS

clang/test/OpenMP/ompx_attributes_codegen.cpp

+16-9
Original file line numberDiff line numberDiff line change
@@ -11,9 +11,13 @@
1111

1212
// Check that the target attributes are set on the generated kernel
1313
void func() {
14-
// AMD: amdgpu_kernel void @__omp_offloading[[HASH:.*]]_l18(ptr {{[^,]+}}) #0
15-
// AMD: amdgpu_kernel void @__omp_offloading[[HASH:.*]]_l20(ptr {{[^,]+}})
16-
// AMD: amdgpu_kernel void @__omp_offloading[[HASH:.*]]_l22(ptr {{[^,]+}}) #4
14+
// AMD: amdgpu_kernel void @__omp_offloading[[HASH:.*]]_l22(ptr {{[^,]+}}) #0
15+
// AMD: amdgpu_kernel void @__omp_offloading[[HASH:.*]]_l24(ptr {{[^,]+}})
16+
// AMD: amdgpu_kernel void @__omp_offloading[[HASH:.*]]_l26(ptr {{[^,]+}}) #4
17+
18+
// NVIDIA: ptx_kernel void @__omp_offloading[[HASH:.*]]_l22(ptr {{[^,]+}}) #[[ATTR0:[0-9]+]]
19+
// NVIDIA: ptx_kernel void @__omp_offloading[[HASH:.*]]_l24(ptr {{[^,]+}}) #[[ATTR1:[0-9]+]]
20+
// NVIDIA: ptx_kernel void @__omp_offloading[[HASH:.*]]_l26(ptr {{[^,]+}}) #[[ATTR2:[0-9]+]]
1721

1822
#pragma omp target ompx_attribute([[clang::amdgpu_flat_work_group_size(10, 20)]])
1923
{}
@@ -34,9 +38,12 @@ void func() {
3438
// AMD-SAME: "omp_target_thread_limit"="17"
3539

3640
// It is unclear if we should use the AMD annotations for other targets, we do for now.
37-
// NVIDIA: "omp_target_thread_limit"="20"
38-
// NVIDIA: "omp_target_thread_limit"="45"
39-
// NVIDIA: "omp_target_thread_limit"="17"
40-
// NVIDIA: !{ptr @__omp_offloading[[HASH1:.*]]_l18, !"maxntidx", i32 20}
41-
// NVIDIA: !{ptr @__omp_offloading[[HASH2:.*]]_l20, !"maxntidx", i32 45}
42-
// NVIDIA: !{ptr @__omp_offloading[[HASH3:.*]]_l22, !"maxntidx", i32 17}
41+
// NVIDIA: attributes #[[ATTR0]]
42+
// NVIDIA-SAME: "nvvm.maxntid"="20"
43+
// NVIDIA-SAME: "omp_target_thread_limit"="20"
44+
// NVIDIA: attributes #[[ATTR1]]
45+
// NVIDIA-SAME: "nvvm.maxntid"="45"
46+
// NVIDIA-SAME: "omp_target_thread_limit"="45"
47+
// NVIDIA: attributes #[[ATTR2]]
48+
// NVIDIA-SAME: "nvvm.maxntid"="17"
49+
// NVIDIA-SAME: "omp_target_thread_limit"="17"

clang/test/OpenMP/thread_limit_nvptx.c

+10-8
Original file line numberDiff line numberDiff line change
@@ -7,27 +7,29 @@
77
#define HEADER
88

99
void foo(int N) {
10-
// CHECK: l11, !"maxntidx", i32 128}
10+
// CHECK: define {{.*}}l11{{.*}} #[[ATTR0:[0-9]+]]
1111
#pragma omp target teams distribute parallel for simd
1212
for (int i = 0; i < N; ++i)
1313
;
14-
// CHECK: l15, !"maxntidx", i32 4}
14+
// CHECK: define {{.*}}l15{{.*}} #[[ATTR1:[0-9]+]]
1515
#pragma omp target teams distribute parallel for simd thread_limit(4)
1616
for (int i = 0; i < N; ++i)
1717
;
18-
// CHECK-NOT: l21, !"maxntidx", i32 128}
19-
// CHECK: l21, !"maxntidx", i32 42}
20-
// CHECK-NOT: l21, !"maxntidx", i32 128}
18+
19+
// CHECK: define {{.*}}l20{{.*}} #[[ATTR2:[0-9]+]]
2120
#pragma omp target teams distribute parallel for simd ompx_attribute(__attribute__((launch_bounds(42, 42))))
2221
for (int i = 0; i < N; ++i)
2322
;
24-
// CHECK-NOT: l27, !"maxntidx", i32 42}
25-
// CHECK: l27, !"maxntidx", i32 22}
26-
// CHECK-NOT: l27, !"maxntidx", i32 42}
23+
24+
// CHECK: define {{.*}}l25{{.*}} #[[ATTR3:[0-9]+]]
2725
#pragma omp target teams distribute parallel for simd ompx_attribute(__attribute__((launch_bounds(42, 42)))) num_threads(22)
2826
for (int i = 0; i < N; ++i)
2927
;
3028
}
3129

3230
#endif
3331

32+
// CHECK: attributes #[[ATTR0]] = {{{.*}} "nvvm.maxntid"="128" {{.*}}}
33+
// CHECK: attributes #[[ATTR1]] = {{{.*}} "nvvm.maxntid"="4" {{.*}}}
34+
// CHECK: attributes #[[ATTR2]] = {{{.*}} "nvvm.maxntid"="42" {{.*}}}
35+
// CHECK: attributes #[[ATTR3]] = {{{.*}} "nvvm.maxntid"="22" {{.*}}}

llvm/docs/NVPTXUsage.rst

+17
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,23 @@ Function Attributes
7474
This attribute indicates the maximum number of registers to be used for the
7575
kernel function.
7676

77+
``"nvvm.maxntid"="<x>[,<y>[,<z>]]"``
78+
This attribute declares the maximum number of threads in the thread block
79+
(CTA). The maximum number of threads is the product of the maximum extent in
80+
each dimension. Exceeding the maximum number of threads results in a runtime
81+
error or kernel launch failure.
82+
83+
``"nvvm.reqntid"="<x>[,<y>[,<z>]]"``
84+
This attribute declares the exact number of threads in the thread block
85+
(CTA). The number of threads is the product of the value in each dimension.
86+
Specifying a different CTA dimension at launch will result in a runtime
87+
error or kernel launch failure.
88+
89+
``"nvvm.cluster_dim"="<x>[,<y>[,<z>]]"``
90+
This attribute declares the number of thread blocks (CTAs) in the cluster.
91+
The total number of CTAs is the product of the number of CTAs in each
92+
dimension. Specifying a different cluster dimension at launch will result in
93+
a runtime error or kernel launch failure. Only supported for Hopper+.
7794

7895
.. _address_spaces:
7996

llvm/lib/Frontend/OpenMP/OMPIRBuilder.cpp

+9-42
Original file line numberDiff line numberDiff line change
@@ -6406,45 +6406,13 @@ void OpenMPIRBuilder::createTargetDeinit(const LocationDescription &Loc,
64066406
KernelEnvironmentGV->setInitializer(NewInitializer);
64076407
}
64086408

6409-
static MDNode *getNVPTXMDNode(Function &Kernel, StringRef Name) {
6410-
Module &M = *Kernel.getParent();
6411-
NamedMDNode *MD = M.getOrInsertNamedMetadata("nvvm.annotations");
6412-
for (auto *Op : MD->operands()) {
6413-
if (Op->getNumOperands() != 3)
6414-
continue;
6415-
auto *KernelOp = dyn_cast<ConstantAsMetadata>(Op->getOperand(0));
6416-
if (!KernelOp || KernelOp->getValue() != &Kernel)
6417-
continue;
6418-
auto *Prop = dyn_cast<MDString>(Op->getOperand(1));
6419-
if (!Prop || Prop->getString() != Name)
6420-
continue;
6421-
return Op;
6422-
}
6423-
return nullptr;
6424-
}
6425-
6426-
static void updateNVPTXMetadata(Function &Kernel, StringRef Name, int32_t Value,
6427-
bool Min) {
6428-
// Update the "maxntidx" metadata for NVIDIA, or add it.
6429-
MDNode *ExistingOp = getNVPTXMDNode(Kernel, Name);
6430-
if (ExistingOp) {
6431-
auto *OldVal = cast<ConstantAsMetadata>(ExistingOp->getOperand(2));
6432-
int32_t OldLimit = cast<ConstantInt>(OldVal->getValue())->getZExtValue();
6433-
ExistingOp->replaceOperandWith(
6434-
2, ConstantAsMetadata::get(ConstantInt::get(
6435-
OldVal->getValue()->getType(),
6436-
Min ? std::min(OldLimit, Value) : std::max(OldLimit, Value))));
6437-
} else {
6438-
LLVMContext &Ctx = Kernel.getContext();
6439-
Metadata *MDVals[] = {ConstantAsMetadata::get(&Kernel),
6440-
MDString::get(Ctx, Name),
6441-
ConstantAsMetadata::get(
6442-
ConstantInt::get(Type::getInt32Ty(Ctx), Value))};
6443-
// Append metadata to nvvm.annotations
6444-
Module &M = *Kernel.getParent();
6445-
NamedMDNode *MD = M.getOrInsertNamedMetadata("nvvm.annotations");
6446-
MD->addOperand(MDNode::get(Ctx, MDVals));
6409+
static void updateNVPTXAttr(Function &Kernel, StringRef Name, int32_t Value,
6410+
bool Min) {
6411+
if (Kernel.hasFnAttribute(Name)) {
6412+
int32_t OldLimit = Kernel.getFnAttributeAsParsedInteger(Name);
6413+
Value = Min ? std::min(OldLimit, Value) : std::max(OldLimit, Value);
64476414
}
6415+
Kernel.addFnAttr(Name, llvm::utostr(Value));
64486416
}
64496417

64506418
std::pair<int32_t, int32_t>
@@ -6466,9 +6434,8 @@ OpenMPIRBuilder::readThreadBoundsForKernel(const Triple &T, Function &Kernel) {
64666434
return {LB, UB};
64676435
}
64686436

6469-
if (MDNode *ExistingOp = getNVPTXMDNode(Kernel, "maxntidx")) {
6470-
auto *OldVal = cast<ConstantAsMetadata>(ExistingOp->getOperand(2));
6471-
int32_t UB = cast<ConstantInt>(OldVal->getValue())->getZExtValue();
6437+
if (Kernel.hasFnAttribute("nvvm.maxntid")) {
6438+
int32_t UB = Kernel.getFnAttributeAsParsedInteger("nvvm.maxntid");
64726439
return {0, ThreadLimit ? std::min(ThreadLimit, UB) : UB};
64736440
}
64746441
return {0, ThreadLimit};
@@ -6485,7 +6452,7 @@ void OpenMPIRBuilder::writeThreadBoundsForKernel(const Triple &T,
64856452
return;
64866453
}
64876454

6488-
updateNVPTXMetadata(Kernel, "maxntidx", UB, true);
6455+
updateNVPTXAttr(Kernel, "nvvm.maxntid", UB, true);
64896456
}
64906457

64916458
std::pair<int32_t, int32_t>

0 commit comments

Comments
 (0)