[clang] [llvm] [HLSL] Implement explicit layout for default constant buffer ($Globals) (PR #128991)

2025-03-12 Thread Alex Sepkowski via cfe-commits


@@ -89,14 +99,57 @@ llvm::TargetExtType 
*HLSLBufferLayoutBuilder::createLayoutType(
 RecordTypes.pop_back();
 
 for (const auto *FD : RT->getDecl()->fields()) {
-  assert((!Packoffsets || Index < Packoffsets->size()) &&
- "number of elements in layout struct does not "
- "match number of packoffset annotations");
+  unsigned FieldOffset = UINT_MAX;
+  llvm::Type *FieldType = nullptr;
+
+  if (Packoffsets) {
+// have packoffset/register(c#) annotations
+assert(Index < Packoffsets->size() &&
+   "number of elements in layout struct does not match number of "
+   "packoffset annotations");
+int PO = (*Packoffsets)[Index++];
+if (PO != -1) {
+  if (!layoutField(FD, EndOffset, FieldOffset, FieldType, PO))
+return nullptr;
+} else {
+  // No packoffset/register(cX) annotation on this field;
+  // Delay the layout until after all of the other elements
+  // annotated with packoffsets/register(cX) are processed.
+  DelayLayoutFields.emplace_back(FD, LayoutElements.size());
+  // reserve space for this field in the layout vector and elements 
list
+  Layout.push_back(UINT_MAX);
+  LayoutElements.push_back(nullptr);
+  continue;
+}
+  } else {
+if (!layoutField(FD, EndOffset, FieldOffset, FieldType))
+  return nullptr;
+  }
+
+  assert(FieldOffset != UINT_MAX && FieldType != nullptr);
+  Layout.push_back((unsigned)FieldOffset);

alsepkow wrote:

Left over cast from a previous revision? Layout contains unsigned ints.

https://github.com/llvm/llvm-project/pull/128991
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [llvm] [HLSL] Implement explicit layout for default constant buffer ($Globals) (PR #128991)

2025-03-12 Thread Alex Sepkowski via cfe-commits


@@ -174,21 +176,45 @@ createBufferHandleType(const HLSLBufferDecl *BufDecl) {
   return cast(QT.getTypePtr());
 }
 
+// Iterates over all declarations in the HLSL buffer and based on the
+// packoffset or register(c#) annotations it fills outs the Layout
+// vector with the user-specified layout offsets.
+// The buffer offsets can be specified 2 ways:
+// 1. declarations in cbuffer {} block can have a packoffset annotation
+//(translates to HLSLPackOffsetAttr)
+// 2. default constant buffer declarations at global scope can have
+//register(c#) annotations (translates to HLSLResourceBindingAttr with
+//RegisterType::C)
+// It is not guaranteed that all declarations in a buffer have an annotation.
+// For those where it is not specified a -1 value is added to the Layout
+// vector. In the final layout these declarations will be placed at the end
+// of the HLSL buffer after all of the elements with specified offset.
 static void fillPackoffsetLayout(const HLSLBufferDecl *BufDecl,
- SmallVector &Layout) {
+ SmallVector &Layout) {
   assert(Layout.empty() && "expected empty vector for layout");
   assert(BufDecl->hasValidPackoffset());
 
-  for (Decl *D : BufDecl->decls()) {
+  for (Decl *D : BufDecl->buffer_decls()) {

alsepkow wrote:

nit: On formatting, it sounds like the llvm repo prefers 'auto *name' for for 
loops? 

https://github.com/llvm/llvm-project/pull/128991
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [llvm] [HLSL] Implement explicit layout for default constant buffer ($Globals) (PR #128991)

2025-03-12 Thread Alex Sepkowski via cfe-commits


@@ -174,21 +176,45 @@ createBufferHandleType(const HLSLBufferDecl *BufDecl) {
   return cast(QT.getTypePtr());
 }
 
+// Iterates over all declarations in the HLSL buffer and based on the
+// packoffset or register(c#) annotations it fills outs the Layout

alsepkow wrote:

Found it 🥳
[dx-graphics-hlsl-variable-register](https://learn.microsoft.com/en-us/windows/win32/direct3dhlsl/dx-graphics-hlsl-variable-register
 )

https://github.com/llvm/llvm-project/pull/128991
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [llvm] [HLSL] Implement explicit layout for default constant buffer ($Globals) (PR #128991)

2025-03-12 Thread Alex Sepkowski via cfe-commits


@@ -174,21 +176,45 @@ createBufferHandleType(const HLSLBufferDecl *BufDecl) {
   return cast(QT.getTypePtr());
 }
 
+// Iterates over all declarations in the HLSL buffer and based on the
+// packoffset or register(c#) annotations it fills outs the Layout
+// vector with the user-specified layout offsets.
+// The buffer offsets can be specified 2 ways:
+// 1. declarations in cbuffer {} block can have a packoffset annotation
+//(translates to HLSLPackOffsetAttr)
+// 2. default constant buffer declarations at global scope can have
+//register(c#) annotations (translates to HLSLResourceBindingAttr with
+//RegisterType::C)
+// It is not guaranteed that all declarations in a buffer have an annotation.
+// For those where it is not specified a -1 value is added to the Layout
+// vector. In the final layout these declarations will be placed at the end
+// of the HLSL buffer after all of the elements with specified offset.
 static void fillPackoffsetLayout(const HLSLBufferDecl *BufDecl,
- SmallVector &Layout) {
+ SmallVector &Layout) {
   assert(Layout.empty() && "expected empty vector for layout");
   assert(BufDecl->hasValidPackoffset());
 
-  for (Decl *D : BufDecl->decls()) {
+  for (Decl *D : BufDecl->buffer_decls()) {
 if (isa(D) || isa(D)) {
   continue;
 }
 VarDecl *VD = dyn_cast(D);
 if (!VD || VD->getType().getAddressSpace() != LangAS::hlsl_constant)
   continue;
-assert(VD->hasAttr() &&
-   "expected packoffset attribute on every declaration");
-size_t Offset = VD->getAttr()->getOffsetInBytes();
+size_t Offset = -1;

alsepkow wrote:

size_t is unsigned. You should use something like SIZE_MAX instead. Or 0?

https://github.com/llvm/llvm-project/pull/128991
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [llvm] [HLSL] Implement explicit layout for default constant buffer ($Globals) (PR #128991)

2025-03-12 Thread Alex Sepkowski via cfe-commits


@@ -89,14 +99,57 @@ llvm::TargetExtType 
*HLSLBufferLayoutBuilder::createLayoutType(
 RecordTypes.pop_back();
 
 for (const auto *FD : RT->getDecl()->fields()) {
-  assert((!Packoffsets || Index < Packoffsets->size()) &&
- "number of elements in layout struct does not "
- "match number of packoffset annotations");
+  unsigned FieldOffset = UINT_MAX;
+  llvm::Type *FieldType = nullptr;
+
+  if (Packoffsets) {
+// have packoffset/register(c#) annotations
+assert(Index < Packoffsets->size() &&
+   "number of elements in layout struct does not match number of "
+   "packoffset annotations");
+int PO = (*Packoffsets)[Index++];

alsepkow wrote:

P0 should be a const, I think? I noticed we don't really use that pattern in 
DXC but it looks like it is used here.

https://github.com/llvm/llvm-project/pull/128991
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [llvm] [HLSL] Implement explicit layout for default constant buffer ($Globals) (PR #128991)

2025-03-12 Thread Alex Sepkowski via cfe-commits


@@ -89,14 +99,57 @@ llvm::TargetExtType 
*HLSLBufferLayoutBuilder::createLayoutType(
 RecordTypes.pop_back();
 
 for (const auto *FD : RT->getDecl()->fields()) {
-  assert((!Packoffsets || Index < Packoffsets->size()) &&
- "number of elements in layout struct does not "
- "match number of packoffset annotations");
+  unsigned FieldOffset = UINT_MAX;
+  llvm::Type *FieldType = nullptr;
+
+  if (Packoffsets) {
+// have packoffset/register(c#) annotations
+assert(Index < Packoffsets->size() &&
+   "number of elements in layout struct does not match number of "
+   "packoffset annotations");
+int PO = (*Packoffsets)[Index++];
+if (PO != -1) {
+  if (!layoutField(FD, EndOffset, FieldOffset, FieldType, PO))
+return nullptr;
+} else {
+  // No packoffset/register(cX) annotation on this field;
+  // Delay the layout until after all of the other elements
+  // annotated with packoffsets/register(cX) are processed.
+  DelayLayoutFields.emplace_back(FD, LayoutElements.size());
+  // reserve space for this field in the layout vector and elements 
list
+  Layout.push_back(UINT_MAX);
+  LayoutElements.push_back(nullptr);
+  continue;
+}
+  } else {
+if (!layoutField(FD, EndOffset, FieldOffset, FieldType))
+  return nullptr;
+  }
+
+  assert(FieldOffset != UINT_MAX && FieldType != nullptr);
+  Layout.push_back((unsigned)FieldOffset);
+  LayoutElements.push_back(FieldType);
+}
+  }
 
-  if (!layoutField(FD, EndOffset, Layout, LayoutElements,
-   Packoffsets ? (*Packoffsets)[Index] : -1))
+  // process delayed layouts
+  if (!DelayLayoutFields.empty()) {
+for (auto I : DelayLayoutFields) {
+  const FieldDecl *FD = I.first;
+  unsigned IndexInLayoutElements = I.second;

alsepkow wrote:

const?

https://github.com/llvm/llvm-project/pull/128991
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [llvm] [HLSL] Implement explicit layout for default constant buffer ($Globals) (PR #128991)

2025-03-12 Thread Alex Sepkowski via cfe-commits


@@ -89,14 +99,57 @@ llvm::TargetExtType 
*HLSLBufferLayoutBuilder::createLayoutType(
 RecordTypes.pop_back();
 
 for (const auto *FD : RT->getDecl()->fields()) {
-  assert((!Packoffsets || Index < Packoffsets->size()) &&
- "number of elements in layout struct does not "
- "match number of packoffset annotations");
+  unsigned FieldOffset = UINT_MAX;
+  llvm::Type *FieldType = nullptr;
+
+  if (Packoffsets) {
+// have packoffset/register(c#) annotations
+assert(Index < Packoffsets->size() &&
+   "number of elements in layout struct does not match number of "
+   "packoffset annotations");
+int PO = (*Packoffsets)[Index++];
+if (PO != -1) {
+  if (!layoutField(FD, EndOffset, FieldOffset, FieldType, PO))
+return nullptr;
+} else {
+  // No packoffset/register(cX) annotation on this field;
+  // Delay the layout until after all of the other elements
+  // annotated with packoffsets/register(cX) are processed.
+  DelayLayoutFields.emplace_back(FD, LayoutElements.size());
+  // reserve space for this field in the layout vector and elements 
list
+  Layout.push_back(UINT_MAX);
+  LayoutElements.push_back(nullptr);
+  continue;
+}
+  } else {
+if (!layoutField(FD, EndOffset, FieldOffset, FieldType))
+  return nullptr;
+  }
+
+  assert(FieldOffset != UINT_MAX && FieldType != nullptr);
+  Layout.push_back((unsigned)FieldOffset);
+  LayoutElements.push_back(FieldType);
+}
+  }
 
-  if (!layoutField(FD, EndOffset, Layout, LayoutElements,
-   Packoffsets ? (*Packoffsets)[Index] : -1))
+  // process delayed layouts
+  if (!DelayLayoutFields.empty()) {
+for (auto I : DelayLayoutFields) {
+  const FieldDecl *FD = I.first;
+  unsigned IndexInLayoutElements = I.second;
+  // the first item in layout vector is size, so we need to offset the 
index
+  // by 1
+  unsigned IndexInLayout = IndexInLayoutElements + 1;
+  assert(Layout[IndexInLayout] == UINT_MAX &&
+ LayoutElements[IndexInLayoutElements] == nullptr);
+
+  unsigned FieldOffset = UINT_MAX;
+  llvm::Type *FieldType = nullptr;
+  if (!layoutField(FD, EndOffset, FieldOffset, FieldType))
 return nullptr;
-  Index++;
+
+  Layout[IndexInLayout] = (unsigned)FieldOffset;

alsepkow wrote:

Cast no longer needed

https://github.com/llvm/llvm-project/pull/128991
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [llvm] [HLSL] Implement explicit layout for default constant buffer ($Globals) (PR #128991)

2025-03-12 Thread Alex Sepkowski via cfe-commits


@@ -58,9 +60,15 @@ namespace CodeGen {
 // classes) and calls layoutField to converts each field to its corresponding
 // LLVM type and to calculate its HLSL constant buffer layout. Any embedded
 // structs (or arrays of structs) are converted to target layout types as well.
+//
+// When Packoffsets are specified the elements will be placed based on the
+// user-specified offsets. Not all elements must have a packoffset/register(c#)
+// annotation though. For those that don't, the Packoffsets array will constain

alsepkow wrote:

nit: typo, 'contain'

https://github.com/llvm/llvm-project/pull/128991
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [llvm] [HLSL] Implement explicit layout for default constant buffer ($Globals) (PR #128991)

2025-03-12 Thread Alex Sepkowski via cfe-commits


@@ -174,21 +176,45 @@ createBufferHandleType(const HLSLBufferDecl *BufDecl) {
   return cast(QT.getTypePtr());
 }
 
+// Iterates over all declarations in the HLSL buffer and based on the
+// packoffset or register(c#) annotations it fills outs the Layout

alsepkow wrote:

Just curious, what is 'register(c#)' annotation? I didn't get any hits trying 
to search it online or with copilot.

https://github.com/llvm/llvm-project/pull/128991
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [llvm] [HLSL] Implement explicit layout for default constant buffer ($Globals) (PR #128991)

2025-03-12 Thread Alex Sepkowski via cfe-commits


@@ -89,14 +99,57 @@ llvm::TargetExtType 
*HLSLBufferLayoutBuilder::createLayoutType(
 RecordTypes.pop_back();
 
 for (const auto *FD : RT->getDecl()->fields()) {
-  assert((!Packoffsets || Index < Packoffsets->size()) &&
- "number of elements in layout struct does not "
- "match number of packoffset annotations");
+  unsigned FieldOffset = UINT_MAX;
+  llvm::Type *FieldType = nullptr;
+
+  if (Packoffsets) {
+// have packoffset/register(c#) annotations
+assert(Index < Packoffsets->size() &&
+   "number of elements in layout struct does not match number of "
+   "packoffset annotations");
+int PO = (*Packoffsets)[Index++];
+if (PO != -1) {
+  if (!layoutField(FD, EndOffset, FieldOffset, FieldType, PO))
+return nullptr;
+} else {
+  // No packoffset/register(cX) annotation on this field;
+  // Delay the layout until after all of the other elements
+  // annotated with packoffsets/register(cX) are processed.
+  DelayLayoutFields.emplace_back(FD, LayoutElements.size());
+  // reserve space for this field in the layout vector and elements 
list
+  Layout.push_back(UINT_MAX);
+  LayoutElements.push_back(nullptr);
+  continue;
+}
+  } else {
+if (!layoutField(FD, EndOffset, FieldOffset, FieldType))
+  return nullptr;
+  }
+
+  assert(FieldOffset != UINT_MAX && FieldType != nullptr);
+  Layout.push_back((unsigned)FieldOffset);
+  LayoutElements.push_back(FieldType);
+}
+  }
 
-  if (!layoutField(FD, EndOffset, Layout, LayoutElements,
-   Packoffsets ? (*Packoffsets)[Index] : -1))
+  // process delayed layouts
+  if (!DelayLayoutFields.empty()) {
+for (auto I : DelayLayoutFields) {
+  const FieldDecl *FD = I.first;
+  unsigned IndexInLayoutElements = I.second;

alsepkow wrote:

a few other variables in this block could also be const.

https://github.com/llvm/llvm-project/pull/128991
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [HLSL][NFC] Update HLSL AST tests to be more readable (PR #130910)

2025-03-12 Thread Alex Sepkowski via cfe-commits

https://github.com/alsepkow approved this pull request.

LGTM

https://github.com/llvm/llvm-project/pull/130910
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits