https://github.com/bob80905 updated https://github.com/llvm/llvm-project/pull/174028
>From 44ff1d1605aefc0dbd197397db9124346dd2411b Mon Sep 17 00:00:00 2001 From: Joshua Batista <[email protected]> Date: Tue, 30 Dec 2025 13:46:14 -0800 Subject: [PATCH 1/3] first attempt --- .../clang/Basic/DiagnosticSemaKinds.td | 1 + clang/lib/Sema/SemaHLSL.cpp | 102 ++++++++++++++++++ ...esource_binding_attr_error_uint32_max.hlsl | 31 ++++++ 3 files changed, 134 insertions(+) create mode 100644 clang/test/SemaHLSL/resource_binding_attr_error_uint32_max.hlsl diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td index 6c6a26614ad0e..3807d1dab728a 100644 --- a/clang/include/clang/Basic/DiagnosticSemaKinds.td +++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td @@ -13336,6 +13336,7 @@ def warn_hlsl_register_type_c_packoffset: Warning<"binding type 'c' ignored in b def warn_hlsl_deprecated_register_type_b: Warning<"binding type 'b' only applies to constant buffers. The 'bool constant' binding type is no longer supported">, InGroup<LegacyConstantRegisterBinding>, DefaultError; def warn_hlsl_deprecated_register_type_i: Warning<"binding type 'i' ignored. The 'integer constant' binding type is no longer supported">, InGroup<LegacyConstantRegisterBinding>, DefaultError; def err_hlsl_unsupported_register_number : Error<"register number should be an integer">; +def err_hlsl_register_number_too_large : Error<"register number should not exceed UINT32_MAX, 4294967295">; def err_hlsl_expected_space : Error<"invalid space specifier '%0' used; expected 'space' followed by an integer, like space1">; def err_hlsl_space_on_global_constant : Error<"register space cannot be specified on global constants">; def warn_hlsl_implicit_binding : Warning<"resource has implicit register binding">, InGroup<HLSLImplicitBinding>, DefaultIgnore; diff --git a/clang/lib/Sema/SemaHLSL.cpp b/clang/lib/Sema/SemaHLSL.cpp index a6de1cd550212..7760b1f791374 100644 --- a/clang/lib/Sema/SemaHLSL.cpp +++ b/clang/lib/Sema/SemaHLSL.cpp @@ -2361,6 +2361,99 @@ static bool DiagnoseHLSLRegisterAttribute(Sema &S, SourceLocation &ArgLoc, return ValidateMultipleRegisterAnnotations(S, D, RegType); } +bool ExceedsUInt32Max(llvm::StringRef S) { + constexpr size_t MaxDigits = 10; // UINT32_MAX = 4294967295 + if (S.size() > MaxDigits) + return true; + + if (S.size() < MaxDigits) + return false; + + return S.compare("4294967295") > 0; +} + +// return false if the slot count exceeds the limit, true otherwise +static bool AccumulateHLSLResourceSlots(QualType Ty, llvm::APInt &SlotCount, + const llvm::APInt &Limit, + ASTContext &Ctx, + uint64_t Multiplier = 1) { + Ty = Ty.getCanonicalType(); + const Type *T = Ty.getTypePtr(); + + // Early exit if already overflowed + if (SlotCount.ugt(Limit)) + return false; + + // Case 1: array type + if (const auto *AT = dyn_cast<ArrayType>(T)) { + uint64_t Count = 1; + + if (const auto *CAT = dyn_cast<ConstantArrayType>(AT)) { + Count = CAT->getSize().getZExtValue(); + } + // TODO: how do we handle non constant resource arrays? + + QualType ElemTy = AT->getElementType(); + + return AccumulateHLSLResourceSlots(ElemTy, SlotCount, Limit, Ctx, + Multiplier * Count); + } + + // Case 2: resource leaf + if (T->isHLSLResourceRecord()) { + llvm::APInt Add(SlotCount.getBitWidth(), Multiplier); + SlotCount += Add; + return SlotCount.ule(Limit); + } + + // Case 3: struct / record + if (const auto *RT = dyn_cast<RecordType>(T)) { + const RecordDecl *RD = RT->getDecl(); + for (const FieldDecl *Field : RD->fields()) { + if (!AccumulateHLSLResourceSlots(Field->getType(), SlotCount, Limit, Ctx, + Multiplier)) + return false; + } + return true; + } + + // Case 4: everything else + return true; +} + +// return true if there is something invalid, false otherwise +bool ValidateRegisterNumber(StringRef SlotNumStr, Decl *TheDecl, + ASTContext &Ctx) { + if (ExceedsUInt32Max(SlotNumStr)) + return true; + + llvm::APInt SlotNum; + if (SlotNumStr.getAsInteger(10, SlotNum)) + return false; + SlotNum = SlotNum.zext(64); + + // uint32_max isn't 64 bits, but this int should + // have a 64 bit width in case it is compared to + // another 64 bit-width value. Assert failure otherwise. + llvm::APInt Limit(64, UINT32_MAX); + VarDecl *VD = dyn_cast<VarDecl>(TheDecl); + if (VD) { + AccumulateHLSLResourceSlots(VD->getType(), SlotNum, Limit, Ctx); + return SlotNum.ugt(Limit); + } + // handle the cbuffer case + HLSLBufferDecl *HBD = dyn_cast<HLSLBufferDecl>(TheDecl); + if (HBD) { + // resources cannot be put within a cbuffer, so no need + // to analyze the structure since the register number + // won't be pushed any higher. + return SlotNum.ugt(Limit); + } + + // we don't expect any other decl type, so fail + return true; +} + void SemaHLSL::handleResourceBindingAttr(Decl *TheDecl, const ParsedAttr &AL) { if (VarDecl *VD = dyn_cast<VarDecl>(TheDecl)) { QualType Ty = VD->getType(); @@ -2420,6 +2513,15 @@ void SemaHLSL::handleResourceBindingAttr(Decl *TheDecl, const ParsedAttr &AL) { return; } StringRef SlotNumStr = Slot.substr(1); + + // Validate register number. It should not exceed UINT32_MAX, + // including if the resource type is an array that starts + // before UINT32_MAX, but ends afterwards. + if (ValidateRegisterNumber(SlotNumStr, TheDecl, getASTContext())) { + Diag(SlotLoc, diag::err_hlsl_register_number_too_large); + return; + } + unsigned N; if (SlotNumStr.getAsInteger(10, N)) { Diag(SlotLoc, diag::err_hlsl_unsupported_register_number); diff --git a/clang/test/SemaHLSL/resource_binding_attr_error_uint32_max.hlsl b/clang/test/SemaHLSL/resource_binding_attr_error_uint32_max.hlsl new file mode 100644 index 0000000000000..81a51fb601e54 --- /dev/null +++ b/clang/test/SemaHLSL/resource_binding_attr_error_uint32_max.hlsl @@ -0,0 +1,31 @@ +// RUN: %clang_cc1 -triple dxil-pc-shadermodel6.3-library -x hlsl -o - -fsyntax-only %s -verify + +// test semantic validation for register numbers that exceed UINT32_MAX + +struct S { + RWBuffer<float> A[4]; + RWBuffer<int> B[10]; +}; + +// test that S.A carries the register number over the limit and emits the error +// expected-error@+1 {{register number should not exceed UINT32_MAX, 4294967295}} +S s : register(u4294967294); // UINT32_MAX - 1 + +// test the error is also triggered when analyzing S.B +// expected-error@+1 {{register number should not exceed UINT32_MAX, 4294967295}} +S s2 : register(u4294967289); + +// test a standard resource array +// expected-error@+1 {{register number should not exceed UINT32_MAX, 4294967295}} +RWBuffer<float> Buf[10] : register(u4294967294); + +// test directly an excessively high register number. +// expected-error@+1 {{register number should not exceed UINT32_MAX, 4294967295}} +RWBuffer<float> A : register(u9995294967294); + +// test a struct within a cbuffer +// expected-error@+1 {{register number should not exceed UINT32_MAX, 4294967295}} +cbuffer MyCB : register(b9995294967294) { + float F[4]; + int I[10]; +}; >From 6ffc9ec83357b45c59439a0eaaad5081c64f9d49 Mon Sep 17 00:00:00 2001 From: Joshua Batista <[email protected]> Date: Tue, 30 Dec 2025 13:57:39 -0800 Subject: [PATCH 2/3] add some more tests --- ...resource_binding_attr_error_uint32_max.hlsl | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/clang/test/SemaHLSL/resource_binding_attr_error_uint32_max.hlsl b/clang/test/SemaHLSL/resource_binding_attr_error_uint32_max.hlsl index 81a51fb601e54..70a226337ef6a 100644 --- a/clang/test/SemaHLSL/resource_binding_attr_error_uint32_max.hlsl +++ b/clang/test/SemaHLSL/resource_binding_attr_error_uint32_max.hlsl @@ -7,6 +7,11 @@ struct S { RWBuffer<int> B[10]; }; +// do some more nesting +struct S2 { + S a[3]; +}; + // test that S.A carries the register number over the limit and emits the error // expected-error@+1 {{register number should not exceed UINT32_MAX, 4294967295}} S s : register(u4294967294); // UINT32_MAX - 1 @@ -15,9 +20,17 @@ S s : register(u4294967294); // UINT32_MAX - 1 // expected-error@+1 {{register number should not exceed UINT32_MAX, 4294967295}} S s2 : register(u4294967289); + +// test the error is also triggered when analyzing S2.a[1].B +// expected-error@+1 {{register number should not exceed UINT32_MAX, 4294967295}} +S2 s3 : register(u4294967275); + +// expected-error@+1 {{register number should not exceed UINT32_MAX, 4294967295}} +RWBuffer<float> Buf[10][10] : register(u4294967234); + // test a standard resource array // expected-error@+1 {{register number should not exceed UINT32_MAX, 4294967295}} -RWBuffer<float> Buf[10] : register(u4294967294); +RWBuffer<float> Buf2[10] : register(u4294967294); // test directly an excessively high register number. // expected-error@+1 {{register number should not exceed UINT32_MAX, 4294967295}} @@ -29,3 +42,6 @@ cbuffer MyCB : register(b9995294967294) { float F[4]; int I[10]; }; + +// no errors expected, all 100 register numbers are occupied here +RWBuffer<float> Buf3[10][10] : register(u4294967194); >From 8d838fcfcf86ce2a78ab795e0f9518eeb2b12e5e Mon Sep 17 00:00:00 2001 From: Joshua Batista <[email protected]> Date: Tue, 30 Dec 2025 14:07:09 -0800 Subject: [PATCH 3/3] adjust comment --- clang/test/SemaHLSL/resource_binding_attr_error_uint32_max.hlsl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/clang/test/SemaHLSL/resource_binding_attr_error_uint32_max.hlsl b/clang/test/SemaHLSL/resource_binding_attr_error_uint32_max.hlsl index 70a226337ef6a..d2e089391143c 100644 --- a/clang/test/SemaHLSL/resource_binding_attr_error_uint32_max.hlsl +++ b/clang/test/SemaHLSL/resource_binding_attr_error_uint32_max.hlsl @@ -36,7 +36,7 @@ RWBuffer<float> Buf2[10] : register(u4294967294); // expected-error@+1 {{register number should not exceed UINT32_MAX, 4294967295}} RWBuffer<float> A : register(u9995294967294); -// test a struct within a cbuffer +// test a cbuffer directly with an excessively high register number. // expected-error@+1 {{register number should not exceed UINT32_MAX, 4294967295}} cbuffer MyCB : register(b9995294967294) { float F[4]; _______________________________________________ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
