-
Notifications
You must be signed in to change notification settings - Fork 14.3k
[NVPTX] Add support for maxclusterrank in launch_bounds #66496
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[NVPTX] Add support for maxclusterrank in launch_bounds #66496
Conversation
@llvm/pr-subscribers-clang-codegen @llvm/pr-subscribers-clang ChangesSince SM_90 CUDA supports specifying additional argument to the launch_bounds attribute: maxBlocksPerCluster, to express the maximum number of CTAs that can be part of the cluster. See: https://docs.nvidia.com/cuda/parallel-thread-execution/index.html#cluster-dimension-directives-maxclusterrank and https://docs.nvidia.com/cuda/cuda-c-programming-guide/index.html#launch-bounds for details. --Patch is 24.44 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/66496.diff 13 Files Affected:
diff --git a/clang/include/clang/Basic/Attr.td b/clang/include/clang/Basic/Attr.td index c95db7e8049d47a..3c51261bd3eb081 100644 --- a/clang/include/clang/Basic/Attr.td +++ b/clang/include/clang/Basic/Attr.td @@ -1267,7 +1267,8 @@ def CUDAInvalidTarget : InheritableAttr { def CUDALaunchBounds : InheritableAttr { let Spellings = [GNU<"launch_bounds">, Declspec<"__launch_bounds__">]; - let Args = [ExprArgument<"MaxThreads">, ExprArgument<"MinBlocks", 1>]; + let Args = [ExprArgument<"MaxThreads">, ExprArgument<"MinBlocks", 1>, + ExprArgument<"MaxBlocks", 1>]; let LangOpts = [CUDA]; let Subjects = SubjectList<[ObjCMethod, FunctionLike]>; // An AST node is created for this attribute, but is not used by other parts diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td index 0ac4df8edb242f6..088e3a45c7babba 100644 --- a/clang/include/clang/Basic/DiagnosticSemaKinds.td +++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td @@ -11836,6 +11836,10 @@ def err_sycl_special_type_num_init_method : Error< "types with 'sycl_special_class' attribute must have one and only one '__init' " "method defined">; +def warn_cuda_maxclusterrank_sm_90 : Warning< + "maxclusterrank requires sm_90 or higher, CUDA arch provided: %0, ignoring " + "%1 attribute">, InGroup<IgnoredAttributes>; + def err_bit_int_bad_size : Error<"%select{signed|unsigned}0 _BitInt must " "have a bit size of at least %select{2|1}0">; def err_bit_int_max_size : Error<"%select{signed|unsigned}0 _BitInt of bit " diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h index 47379e00a7445e3..dca7b66da3796d9 100644 --- a/clang/include/clang/Sema/Sema.h +++ b/clang/include/clang/Sema/Sema.h @@ -11051,12 +11051,13 @@ class Sema final { /// Create an CUDALaunchBoundsAttr attribute. CUDALaunchBoundsAttr *CreateLaunchBoundsAttr(const AttributeCommonInfo &CI, Expr *MaxThreads, - Expr *MinBlocks); + Expr *MinBlocks, + Expr *MaxBlocks); /// AddLaunchBoundsAttr - Adds a launch_bounds attribute to a particular /// declaration. void AddLaunchBoundsAttr(Decl *D, const AttributeCommonInfo &CI, - Expr *MaxThreads, Expr *MinBlocks); + Expr *MaxThreads, Expr *MinBlocks, Expr *MaxBlocks); /// AddModeAttr - Adds a mode attribute to a particular declaration. void AddModeAttr(Decl *D, const AttributeCommonInfo &CI, IdentifierInfo *Name, diff --git a/clang/lib/CodeGen/Targets/NVPTX.cpp b/clang/lib/CodeGen/Targets/NVPTX.cpp index 0d4bbd795648008..64d019a10514d60 100644 --- a/clang/lib/CodeGen/Targets/NVPTX.cpp +++ b/clang/lib/CodeGen/Targets/NVPTX.cpp @@ -296,8 +296,8 @@ void CodeGenModule::handleCUDALaunchBoundsAttr( NVPTXTargetCodeGenInfo::addNVVMMetadata(F, "maxntidx", MaxThreads.getExtValue()); - // min blocks is an optional argument for CUDALaunchBoundsAttr. If it was - // not specified in __launch_bounds__ or if the user specified a 0 value, + // min and max blocks is an optional argument for CUDALaunchBoundsAttr. If it + // was not specified in __launch_bounds__ or if the user specified a 0 value, // we don't have to add a PTX directive. if (Attr->getMinBlocks()) { llvm::APSInt MinBlocks(32); @@ -307,6 +307,14 @@ void CodeGenModule::handleCUDALaunchBoundsAttr( NVPTXTargetCodeGenInfo::addNVVMMetadata(F, "minctasm", MinBlocks.getExtValue()); } + if (Attr->getMaxBlocks()) { + llvm::APSInt MaxBlocks(32); + MaxBlocks = Attr->getMaxBlocks()->EvaluateKnownConstInt(getContext()); + if (MaxBlocks > 0) + // Create !{<func-ref>, metadata !"maxclusterrank", i32 <val>} node + NVPTXTargetCodeGenInfo::addNVVMMetadata(F, "maxclusterrank", + MaxBlocks.getExtValue()); + } } std::unique_ptr<TargetCodeGenInfo> diff --git a/clang/lib/Parse/ParseOpenMP.cpp b/clang/lib/Parse/ParseOpenMP.cpp index 605b97617432ed3..8a8a126bf7244d4 100644 --- a/clang/lib/Parse/ParseOpenMP.cpp +++ b/clang/lib/Parse/ParseOpenMP.cpp @@ -3739,7 +3739,8 @@ OMPClause *Parser::ParseOpenMPOMPXAttributesClause(bool ParseOnly) { continue; if (auto *A = Actions.CreateLaunchBoundsAttr( PA, PA.getArgAsExpr(0), - PA.getNumArgs() > 1 ? PA.getArgAsExpr(1) : nullptr)) + PA.getNumArgs() > 1 ? PA.getArgAsExpr(1) : nullptr, + PA.getNumArgs() > 2 ? PA.getArgAsExpr(2) : nullptr)) Attrs.push_back(A); continue; default: diff --git a/clang/lib/Sema/SemaDeclAttr.cpp b/clang/lib/Sema/SemaDeclAttr.cpp index cc98713241395ec..e62a0d4fc29f9cd 100644 --- a/clang/lib/Sema/SemaDeclAttr.cpp +++ b/clang/lib/Sema/SemaDeclAttr.cpp @@ -5607,6 +5607,21 @@ bool Sema::CheckRegparmAttr(const ParsedAttr &AL, unsigned &numParams) { return false; } +// Helper to get CudaArch. +static CudaArch getCudaArch(const TargetInfo &TI) { + if (!TI.hasFeature("ptx")) { + return CudaArch::UNKNOWN; + } + for (const auto &Feature : TI.getTargetOpts().FeatureMap) { + if (Feature.getValue()) { + CudaArch Arch = StringToCudaArch(Feature.getKey()); + if (Arch != CudaArch::UNKNOWN) + return Arch; + } + } + return CudaArch::UNKNOWN; +} + // Checks whether an argument of launch_bounds attribute is // acceptable, performs implicit conversion to Rvalue, and returns // non-nullptr Expr result on success. Otherwise, it returns nullptr @@ -5650,8 +5665,8 @@ static Expr *makeLaunchBoundsArgExpr(Sema &S, Expr *E, CUDALaunchBoundsAttr * Sema::CreateLaunchBoundsAttr(const AttributeCommonInfo &CI, Expr *MaxThreads, - Expr *MinBlocks) { - CUDALaunchBoundsAttr TmpAttr(Context, CI, MaxThreads, MinBlocks); + Expr *MinBlocks, Expr *MaxBlocks) { + CUDALaunchBoundsAttr TmpAttr(Context, CI, MaxThreads, MinBlocks, MaxBlocks); MaxThreads = makeLaunchBoundsArgExpr(*this, MaxThreads, TmpAttr, 0); if (MaxThreads == nullptr) return nullptr; @@ -5662,22 +5677,39 @@ Sema::CreateLaunchBoundsAttr(const AttributeCommonInfo &CI, Expr *MaxThreads, return nullptr; } + if (MaxBlocks) { + // Feature '.maxclusterrank' requires .target sm_90 or higher. + auto SM = getCudaArch(Context.getTargetInfo()); + if (SM == CudaArch::UNKNOWN || SM < CudaArch::SM_90) { + Diag(MaxBlocks->getBeginLoc(), diag::warn_cuda_maxclusterrank_sm_90) + << CudaArchToString(SM) << CI << MaxBlocks->getSourceRange(); + // Ignore it by setting MaxBlocks to null; + MaxBlocks = nullptr; + } else { + MaxBlocks = makeLaunchBoundsArgExpr(*this, MaxBlocks, TmpAttr, 2); + if (MaxBlocks == nullptr) + return nullptr; + } + } + return ::new (Context) - CUDALaunchBoundsAttr(Context, CI, MaxThreads, MinBlocks); + CUDALaunchBoundsAttr(Context, CI, MaxThreads, MinBlocks, MaxBlocks); } void Sema::AddLaunchBoundsAttr(Decl *D, const AttributeCommonInfo &CI, - Expr *MaxThreads, Expr *MinBlocks) { - if (auto *Attr = CreateLaunchBoundsAttr(CI, MaxThreads, MinBlocks)) + Expr *MaxThreads, Expr *MinBlocks, + Expr *MaxBlocks) { + if (auto *Attr = CreateLaunchBoundsAttr(CI, MaxThreads, MinBlocks, MaxBlocks)) D->addAttr(Attr); } static void handleLaunchBoundsAttr(Sema &S, Decl *D, const ParsedAttr &AL) { - if (!AL.checkAtLeastNumArgs(S, 1) || !AL.checkAtMostNumArgs(S, 2)) + if (!AL.checkAtLeastNumArgs(S, 1) || !AL.checkAtMostNumArgs(S, 3)) return; S.AddLaunchBoundsAttr(D, AL, AL.getArgAsExpr(0), - AL.getNumArgs() > 1 ? AL.getArgAsExpr(1) : nullptr); + AL.getNumArgs() > 1 ? AL.getArgAsExpr(1) : nullptr, + AL.getNumArgs() > 2 ? AL.getArgAsExpr(2) : nullptr); } static void handleArgumentWithTypeTagAttr(Sema &S, Decl *D, diff --git a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp index 37a7d6204413a38..3f7268f5450a6fa 100644 --- a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp +++ b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp @@ -302,7 +302,15 @@ static void instantiateDependentCUDALaunchBoundsAttr( MinBlocks = Result.getAs<Expr>(); } - S.AddLaunchBoundsAttr(New, Attr, MaxThreads, MinBlocks); + Expr *MaxBlocks = nullptr; + if (Attr.getMaxBlocks()) { + Result = S.SubstExpr(Attr.getMaxBlocks(), TemplateArgs); + if (Result.isInvalid()) + return; + MaxBlocks = Result.getAs<Expr>(); + } + + S.AddLaunchBoundsAttr(New, Attr, MaxThreads, MinBlocks, MaxBlocks); } static void diff --git a/clang/test/CodeGenCUDA/launch-bounds.cu b/clang/test/CodeGenCUDA/launch-bounds.cu index 58bcc410201f35f..31ca9216b413e92 100644 --- a/clang/test/CodeGenCUDA/launch-bounds.cu +++ b/clang/test/CodeGenCUDA/launch-bounds.cu @@ -1,9 +1,13 @@ // RUN: %clang_cc1 %s -triple nvptx-unknown-unknown -fcuda-is-device -emit-llvm -o - | FileCheck %s +// RUN: %clang_cc1 %s -triple nvptx-unknown-unknown -target-cpu sm_90 -DUSE_MAX_BLOCKS -fcuda-is-device -emit-llvm -o - | FileCheck -check-prefix=CHECK_MAX_BLOCKS %s #include "Inputs/cuda.h" #define MAX_THREADS_PER_BLOCK 256 #define MIN_BLOCKS_PER_MP 2 +#ifdef USE_MAX_BLOCKS +#define MAX_BLOCKS_PER_MP 4 +#endif // Test both max threads per block and Min cta per sm. extern "C" { @@ -17,6 +21,21 @@ Kernel1() // CHECK: !{{[0-9]+}} = !{ptr @Kernel1, !"maxntidx", i32 256} // CHECK: !{{[0-9]+}} = !{ptr @Kernel1, !"minctasm", i32 2} +#ifdef USE_MAX_BLOCKS +// Test max threads per block and min/max cta per sm. +extern "C" { +__global__ void +__launch_bounds__( MAX_THREADS_PER_BLOCK, MIN_BLOCKS_PER_MP, MAX_BLOCKS_PER_MP ) +Kernel1_sm_90() +{ +} +} + +// CHECK_MAX_BLOCKS: !{{[0-9]+}} = !{ptr @Kernel1_sm_90, !"maxntidx", i32 256} +// CHECK_MAX_BLOCKS: !{{[0-9]+}} = !{ptr @Kernel1_sm_90, !"minctasm", i32 2} +// CHECK_MAX_BLOCKS: !{{[0-9]+}} = !{ptr @Kernel1_sm_90, !"maxclusterrank", i32 4} +#endif // USE_MAX_BLOCKS + // Test only max threads per block. Min cta per sm defaults to 0, and // CodeGen doesn't output a zero value for minctasm. extern "C" { @@ -50,6 +69,20 @@ template __global__ void Kernel4<MAX_THREADS_PER_BLOCK, MIN_BLOCKS_PER_MP>(); // CHECK: !{{[0-9]+}} = !{ptr @{{.*}}Kernel4{{.*}}, !"maxntidx", i32 256} // CHECK: !{{[0-9]+}} = !{ptr @{{.*}}Kernel4{{.*}}, !"minctasm", i32 2} +#ifdef USE_MAX_BLOCKS +template <int max_threads_per_block, int min_blocks_per_mp, int max_blocks_per_mp> +__global__ void +__launch_bounds__(max_threads_per_block, min_blocks_per_mp, max_blocks_per_mp) +Kernel4_sm_90() +{ +} +template __global__ void Kernel4_sm_90<MAX_THREADS_PER_BLOCK, MIN_BLOCKS_PER_MP, MAX_BLOCKS_PER_MP>(); + +// CHECK_MAX_BLOCKS: !{{[0-9]+}} = !{ptr @{{.*}}Kernel4_sm_90{{.*}}, !"maxntidx", i32 256} +// CHECK_MAX_BLOCKS: !{{[0-9]+}} = !{ptr @{{.*}}Kernel4_sm_90{{.*}}, !"minctasm", i32 2} +// CHECK_MAX_BLOCKS: !{{[0-9]+}} = !{ptr @{{.*}}Kernel4_sm_90{{.*}}, !"maxclusterrank", i32 4} +#endif //USE_MAX_BLOCKS + const int constint = 100; template <int max_threads_per_block, int min_blocks_per_mp> __global__ void @@ -63,6 +96,23 @@ template __global__ void Kernel5<MAX_THREADS_PER_BLOCK, MIN_BLOCKS_PER_MP>(); // CHECK: !{{[0-9]+}} = !{ptr @{{.*}}Kernel5{{.*}}, !"maxntidx", i32 356} // CHECK: !{{[0-9]+}} = !{ptr @{{.*}}Kernel5{{.*}}, !"minctasm", i32 258} +#ifdef USE_MAX_BLOCKS + +template <int max_threads_per_block, int min_blocks_per_mp, int max_blocks_per_mp> +__global__ void +__launch_bounds__(max_threads_per_block + constint, + min_blocks_per_mp + max_threads_per_block, + max_blocks_per_mp + max_threads_per_block) +Kernel5_sm_90() +{ +} +template __global__ void Kernel5_sm_90<MAX_THREADS_PER_BLOCK, MIN_BLOCKS_PER_MP, MAX_BLOCKS_PER_MP>(); + +// CHECK_MAX_BLOCKS: !{{[0-9]+}} = !{ptr @{{.*}}Kernel5_sm_90{{.*}}, !"maxntidx", i32 356} +// CHECK_MAX_BLOCKS: !{{[0-9]+}} = !{ptr @{{.*}}Kernel5_sm_90{{.*}}, !"minctasm", i32 258} +// CHECK_MAX_BLOCKS: !{{[0-9]+}} = !{ptr @{{.*}}Kernel5_sm_90{{.*}}, !"maxclusterrank", i32 260} +#endif //USE_MAX_BLOCKS + // Make sure we don't emit negative launch bounds values. __global__ void __launch_bounds__( -MAX_THREADS_PER_BLOCK, MIN_BLOCKS_PER_MP ) @@ -80,7 +130,26 @@ Kernel7() // CHECK: !{{[0-9]+}} = !{ptr @{{.*}}Kernel7{{.*}}, !"maxntidx", // CHECK-NOT: !{{[0-9]+}} = !{ptr @{{.*}}Kernel7{{.*}}, !"minctasm", +#ifdef USE_MAX_BLOCKS +__global__ void +__launch_bounds__( MAX_THREADS_PER_BLOCK, -MIN_BLOCKS_PER_MP, -MAX_BLOCKS_PER_MP ) +Kernel7_sm_90() +{ +} +// CHECK_MAX_BLOCKS: !{{[0-9]+}} = !{ptr @{{.*}}Kernel7_sm_90{{.*}}, !"maxntidx", +// CHECK_MAX_BLOCKS-NOT: !{{[0-9]+}} = !{ptr @{{.*}}Kernel7_sm_90{{.*}}, !"minctasm", +// CHECK_MAX_BLOCKS-NOT: !{{[0-9]+}} = !{ptr @{{.*}}Kernel7_sm_90{{.*}}, !"maxclusterrank", +#endif // USE_MAX_BLOCKS + const char constchar = 12; __global__ void __launch_bounds__(constint, constchar) Kernel8() {} // CHECK: !{{[0-9]+}} = !{ptr @{{.*}}Kernel8{{.*}}, !"maxntidx", i32 100 // CHECK: !{{[0-9]+}} = !{ptr @{{.*}}Kernel8{{.*}}, !"minctasm", i32 12 + +#ifdef USE_MAX_BLOCKS +const char constchar_2 = 14; +__global__ void __launch_bounds__(constint, constchar, constchar_2) Kernel8_sm_90() {} +// CHECK_MAX_BLOCKS: !{{[0-9]+}} = !{ptr @{{.*}}Kernel8_sm_90{{.*}}, !"maxntidx", i32 100 +// CHECK_MAX_BLOCKS: !{{[0-9]+}} = !{ptr @{{.*}}Kernel8_sm_90{{.*}}, !"minctasm", i32 12 +// CHECK_MAX_BLOCKS: !{{[0-9]+}} = !{ptr @{{.*}}Kernel8_sm_90{{.*}}, !"maxclusterrank", i32 14 +#endif // USE_MAX_BLOCKS diff --git a/clang/test/SemaCUDA/launch_bounds.cu b/clang/test/SemaCUDA/launch_bounds.cu index 0ca0c0145d8bbb6..b1f29480da30c65 100644 --- a/clang/test/SemaCUDA/launch_bounds.cu +++ b/clang/test/SemaCUDA/launch_bounds.cu @@ -12,7 +12,7 @@ __launch_bounds__(0x10000000000000000) void TestWayTooBigArg(void); // expected- __launch_bounds__(-128, 7) void TestNegArg1(void); // expected-warning {{'launch_bounds' attribute parameter 0 is negative and will be ignored}} __launch_bounds__(128, -7) void TestNegArg2(void); // expected-warning {{'launch_bounds' attribute parameter 1 is negative and will be ignored}} -__launch_bounds__(1, 2, 3) void Test3Args(void); // expected-error {{'launch_bounds' attribute takes no more than 2 arguments}} +__launch_bounds__(1, 2, 3, 4) void Test4Args(void); // expected-error {{'launch_bounds' attribute takes no more than 3 arguments}} __launch_bounds__() void TestNoArgs(void); // expected-error {{'launch_bounds' attribute takes at least 1 argument}} int TestNoFunction __launch_bounds__(128, 7); // expected-warning {{'launch_bounds' attribute only applies to Objective-C methods, functions, and function pointers}} @@ -47,3 +47,5 @@ __launch_bounds__(Args) void TestTemplateVariadicArgs(void) {} // expected-error template <int... Args> __launch_bounds__(1, Args) void TestTemplateVariadicArgs2(void) {} // expected-error {{expression contains unexpanded parameter pack 'Args'}} + +__launch_bounds__(1, 2, 3) void Test3Args(void); // expected-warning {{maxclusterrank requires sm_90 or higher, CUDA arch provided: unknown, ignoring 'launch_bounds' attribute}} diff --git a/clang/test/SemaCUDA/launch_bounds_sm_90.cu b/clang/test/SemaCUDA/launch_bounds_sm_90.cu new file mode 100644 index 000000000000000..6b2369983b74fbb --- /dev/null +++ b/clang/test/SemaCUDA/launch_bounds_sm_90.cu @@ -0,0 +1,45 @@ +// RUN: %clang_cc1 -std=c++11 -fsyntax-only -triple nvptx-unknown-unknown -target-cpu sm_90 -verify %s + +#include "Inputs/cuda.h" + +__launch_bounds__(128, 7) void Test2Args(void); +__launch_bounds__(128) void Test1Arg(void); + +__launch_bounds__(0xffffffff) void TestMaxArg(void); +__launch_bounds__(0x100000000) void TestTooBigArg(void); // expected-error {{integer constant expression evaluates to value 4294967296 that cannot be represented in a 32-bit unsigned integer type}} +__launch_bounds__(0x10000000000000000) void TestWayTooBigArg(void); // expected-error {{integer literal is too large to be represented in any integer type}} +__launch_bounds__(1, 1, 0x10000000000000000) void TestWayTooBigArg(void); // expected-error {{integer literal is too large to be represented in any integer type}} + +__launch_bounds__(-128, 7) void TestNegArg1(void); // expected-warning {{'launch_bounds' attribute parameter 0 is negative and will be ignored}} +__launch_bounds__(128, -7) void TestNegArg2(void); // expected-warning {{'launch_bounds' attribute parameter 1 is negative and will be ignored}} +__launch_bounds__(128, 1, -7) void TestNegArg2(void); // expected-warning {{'launch_bounds' attribute parameter 2 is negative and will be ignored}} + + +__launch_bounds__(1, 2, 3, 4) void Test4Args(void); // expected-error {{'launch_bounds' attribute takes no more than 3 arguments}} +__launch_bounds__() void TestNoArgs(void); // expected-error {{'launch_bounds' attribute takes at least 1 argument}} + +int TestNoFunction __launch_bounds__(128, 7, 13); // expected-warning {{'launch_bounds' attribute only applies to Objective-C methods, functions, and function pointers}} + +__launch_bounds__(true) void TestBool(void); +__launch_bounds__(128, 1, 128.0) void TestFP(void); // expected-error {{'launch_bounds' attribute requires parameter 2 to be an integer constant}} +__launch_bounds__(128, 1, (void*)0) void TestNullptr(void); // expected-error {{'launch_bounds' ... |
A friendly ping. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
lovely tests. Looks good modulo nits
MaxBlocks = Attr->getMaxBlocks()->EvaluateKnownConstInt(getContext()); | ||
if (MaxBlocks > 0) | ||
// Create !{<func-ref>, metadata !"maxclusterrank", i32 <val>} node | ||
NVPTXTargetCodeGenInfo::addNVVMMetadata(F, "maxclusterrank", |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do we have enough information to assert this is non-negative?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That's a good question, so makeLaunchBoundsArgEspr
does perform a check for negative values, but lets the value pass (unlike for the case of values > 32 bits, when it returns nullptr
), I didn't want to change it, so catch the negative case here.
including Artem as NVPTX is involved |
@@ -11836,6 +11836,10 @@ def err_sycl_special_type_num_init_method : Error< | |||
"types with 'sycl_special_class' attribute must have one and only one '__init' " | |||
"method defined">; | |||
|
|||
def warn_cuda_maxclusterrank_sm_90 : Warning< | |||
"maxclusterrank requires sm_90 or higher, CUDA arch provided: %0, ignoring " | |||
"%1 attribute">, InGroup<IgnoredAttributes>; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Are we ignoring the whole launch_bounds attribute, or only the MaxBlocks parameter?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The whole thing, this is analogous to how we currently handle:
__launch_bounds__(128, -2)
we issue a warning:
/home/dev/llvm/clang/test/SemaCUDA/launch_bounds_running_test.cu:5:24: warning: 'launch_bounds' attribute parameter 1 is negative and will be ignored [-Wcuda-compat]
5 | __launch_bounds__(128, -2) void Test2Args(void);
| ^~
/home/dev/llvm/clang/test/SemaCUDA/Inputs/cuda.h:14:61: note: expanded from macro '__launch_bounds__'
14 | #define __launch_bounds__(...) __attribute__((launch_bounds(__VA_ARGS__)))
| ^~~~~~~~~~~
1 warning generated when compiling for host.
vs max cluster rank:
/home/dev/llvm/clang/test/SemaCUDA/launch_bounds_running_test.cu:5:27: warning: 'launch_bounds' attribute parameter 2 is negative and will be ignored [-Wcuda-compat]
5 | __launch_bounds__(128, 2, -8) void Test2Args(void);
| ^~
/home/dev/llvm/clang/test/SemaCUDA/Inputs/cuda.h:14:61: note: expanded from macro '__launch_bounds__'
14 | #define __launch_bounds__(...) __attribute__((launch_bounds(__VA_ARGS__)))
| ^~~~~~~~~~~
1 warning generated when compiling for host.
and the resulting asm contains neither of the directives.
@@ -5607,6 +5607,21 @@ bool Sema::CheckRegparmAttr(const ParsedAttr &AL, unsigned &numParams) { | |||
return false; | |||
} | |||
|
|||
// Helper to get CudaArch. | |||
static CudaArch getCudaArch(const TargetInfo &TI) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Considering that we do have TargetInfo pointer here, instead of trying to figure out the target GPU via features, can we just extract CudaArch directly from NVPTXTargetInfo::GPU ?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is that the kind of thing you had in mind:
diff --git a/clang/lib/Basic/Targets/NVPTX.h b/clang/lib/Basic/Targets/NVPTX.h
index 6fa0b8df97d7..20d76b702a94 100644
--- a/clang/lib/Basic/Targets/NVPTX.h
+++ b/clang/lib/Basic/Targets/NVPTX.h
@@ -181,6 +181,8 @@ public:
bool hasBitIntType() const override { return true; }
bool hasBFloat16Type() const override { return true; }
+
+ CudaArch getGPU() const { return GPU; }
};
} // namespace targets
} // namespace clang
diff --git a/clang/lib/Sema/SemaDeclAttr.cpp b/clang/lib/Sema/SemaDeclAttr.cpp
index c4ecaec7728b..636bb0694d36 100644
--- a/clang/lib/Sema/SemaDeclAttr.cpp
+++ b/clang/lib/Sema/SemaDeclAttr.cpp
@@ -10,6 +10,7 @@
//
//===----------------------------------------------------------------------===//
+#include "../Basic/Targets/NVPTX.h"
#include "clang/AST/ASTConsumer.h"
#include "clang/AST/ASTContext.h"
#include "clang/AST/ASTMutationListener.h"
@@ -5609,17 +5610,7 @@ bool Sema::CheckRegparmAttr(const ParsedAttr &AL, unsigned &numParams) {
// Helper to get CudaArch.
static CudaArch getCudaArch(const TargetInfo &TI) {
- if (!TI.hasFeature("ptx")) {
- return CudaArch::UNKNOWN;
- }
- for (const auto &Feature : TI.getTargetOpts().FeatureMap) {
- if (Feature.getValue()) {
- CudaArch Arch = StringToCudaArch(Feature.getKey());
- if (Arch != CudaArch::UNKNOWN)
- return Arch;
- }
- }
- return CudaArch::UNKNOWN;
+ return static_cast<const targets::NVPTXTargetInfo *>(&TI)->getGPU();
}
// Checks whether an argument of launch_bounds attribute is
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You may need to verify that TI->getTriple()->isNVPTX()
before casting, but other than that, LGTM.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done in: 3c17966
if (getMaxNReg(F, Maxnreg)) | ||
O << ".maxnreg " << Maxnreg << "\n"; | ||
|
||
unsigned Maxclusterrank = 0; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do we want to ignore this directive if the metadata exists, but we're targeting a pre-sm_90 GPU?
It may be useful for non-clang LLVM users (e.g XLA) to be able to always specify launch bounds metadata, and let LLVM decide on what it can do with it. Generating the directive for older GPUs would result in ptxas error, while ignoring it would still allow the kernels to compile and work, the same as would be the case if the metadata was correctly absent. I don't think there's not much point to require users to jump through more hoops just to achieve exactly the same result.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You are right, ptxas
reacts to a sample with .maxclusterrank
with pre SM_90 with a hard error:
ptxas --gpu-name sm_75 --output-file cluster_rank.o cluster_rank.s
ptxas cluster_rank.s, line 18; error : Feature '.maxclusterrank' requires .target sm_90 or higher
ptxas fatal : Ptx assembly aborted due to errors
Do I understand you right, that you'd like to see a check similar to what we do in SemaDeclAttr and filter out the directive on targets < SM_90?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We do not have a good way to issue any diagnostics from LLVM, so the choice would be to either reject the IR as invalid, or make an effort to compile to valid PTX. Right now we're neither here nor there.
I'd be fine with either of the options above. That said, ignoring metadata which we can't apply seems OK to me.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I've talked to @alinas who has more experience dealing with IR and she also thinks that ignoring maxclusterrank
metadata on older GPUs is the right choice here.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sure, done in: 261840a
Since SM_90 CUDA supports specifying additional argument to the launch_bounds attribute: maxBlocksPerCluster, to express the maximum number of CTAs that can be part of the cluster. See: https://docs.nvidia.com/cuda/parallel-thread-execution/index.html#cluster-dimension-directives-maxclusterrank and https://docs.nvidia.com/cuda/cuda-c-programming-guide/index.html#launch-bounds for details.
261840a
to
437c41f
Compare
…)" This reverts commit dfab31b. SemaDeclAttr.cpp cannot depend on Basic's private headers (lib/Basic/Targets/NVPTX.h)
@@ -10,6 +10,7 @@ | |||
// | |||
//===----------------------------------------------------------------------===// | |||
|
|||
#include "../Basic/Targets/NVPTX.h" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This header is not part of clangBasic
's interface, but rather its implementation (lib/Basic
rather than include/clang/Basic
).
Sema can't depend on it - if you need to use its APIs from outside clangBasic they should be moved to a public header.
The bazel build shows the problem: https://buildkite.com/llvm-project/upstream-bazel/builds/75928#018ad568-2f7c-4dda-ae90-3b4d787caad7. Breaking bazel is not itself reason to revert, but here it's flagging a real problem that CMake doesn't catch.
I've reverted as 0afbcb2 - sorry to do this so abruptly, but I can't fix this myself & such problems block downstream use of LLVM.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@sam-mccall, apologies for introducing the bug and thank you for drawing my attention to it.
I've got the fix for the problem:
diff --git a/clang/lib/Sema/SemaDeclAttr.cpp b/clang/lib/Sema/SemaDeclAttr.cpp
index 10d1c910d9cd..3b87300e24bc 100644
--- a/clang/lib/Sema/SemaDeclAttr.cpp
+++ b/clang/lib/Sema/SemaDeclAttr.cpp
@@ -10,7 +10,6 @@
//
//===----------------------------------------------------------------------===//
-#include "../Basic/Targets/NVPTX.h"
#include "clang/AST/ASTConsumer.h"
#include "clang/AST/ASTContext.h"
#include "clang/AST/ASTMutationListener.h"
@@ -5612,7 +5611,8 @@ bool Sema::CheckRegparmAttr(const ParsedAttr &AL, unsigned &numParams) {
static CudaArch getCudaArch(const TargetInfo &TI) {
if (!TI.getTriple().isNVPTX())
llvm_unreachable("getCudaArch is only valid for NVPTX triple");
- return static_cast<const targets::NVPTXTargetInfo *>(&TI)->getGPU();
+ auto &TO = TI.getTargetOpts();
+ return StringToCudaArch(TO.CPU);
}
// Checks whether an argument of launch_bounds attribute is
Would you be so king and point me to the process for "reverting the revert" and folding the fix into the original patch?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@jchlanda ah, that's simpler than I expected! Wish I'd found that before reverting...
That looks good to me, I think rather than a new review you can just git revert 0afbcb2
, make the changes you described above, git amend -a
and change the description to "Reland [NVPTX] ...", run the tests and push.
Or if you prefer, send it as a new PR, happy to approve it.
Since SM_90 CUDA supports specifying additional argument to the launch_bounds attribute: maxBlocksPerCluster, to express the maximum number of CTAs that can be part of the cluster. See: https://docs.nvidia.com/cuda/parallel-thread-execution/index.html#cluster-dimension-directives-maxclusterrank and https://docs.nvidia.com/cuda/cuda-c-programming-guide/index.html#launch-bounds for details.
…66496) (llvm#67667) This reverts commit 0afbcb2.
Since SM_90 CUDA supports specifying additional argument to the launch_bounds attribute: maxBlocksPerCluster, to express the maximum number of CTAs that can be part of the cluster. See: https://docs.nvidia.com/cuda/parallel-thread-execution/index.html#cluster-dimension-directives-maxclusterrank and
https://docs.nvidia.com/cuda/cuda-c-programming-guide/index.html#launch-bounds for details.