[clang] [HLSL] Codegen for `cbuffer` declarations without embedded arrays or structs (PR #119755)
Helena Kotas via cfe-commits
cfe-commits at lists.llvm.org
Thu Dec 19 16:56:30 PST 2024
https://github.com/hekota updated https://github.com/llvm/llvm-project/pull/119755
>From 8cebb59304a1f893d94f2a758bc47a62f27c1b8b Mon Sep 17 00:00:00 2001
From: Helena Kotas <hekotas at microsoft.com>
Date: Thu, 12 Dec 2024 11:37:46 -0800
Subject: [PATCH 1/4] [HLSL] Codegen for simple `cbuffer` blocks without
embedded arrays or structs
---
clang/include/clang/Basic/Attr.td | 6 +-
clang/lib/CodeGen/CGDeclCXX.cpp | 12 +-
clang/lib/CodeGen/CGHLSLRuntime.cpp | 249 +++++++++++-------
clang/lib/CodeGen/CGHLSLRuntime.h | 45 +++-
clang/lib/Sema/SemaHLSL.cpp | 15 +-
.../ByteAddressBuffers-constructors.hlsl | 8 +-
.../builtins/RWBuffer-constructor.hlsl | 10 +-
.../StructuredBuffers-constructors.hlsl | 8 +-
clang/test/CodeGenHLSL/cbuf.hlsl | 26 --
clang/test/CodeGenHLSL/cbuf_in_namespace.hlsl | 23 --
clang/test/CodeGenHLSL/cbuffer.hlsl | 67 +++++
.../CodeGenHLSL/cbuffer_and_namespaces.hlsl | 47 ++++
.../CodeGenHLSL/cbuffer_with_packoffset.hlsl | 33 +++
...uffer_with_static_global_and_function.hlsl | 28 ++
.../static_global_and_function_in_cb.hlsl | 17 --
15 files changed, 392 insertions(+), 202 deletions(-)
delete mode 100644 clang/test/CodeGenHLSL/cbuf.hlsl
delete mode 100644 clang/test/CodeGenHLSL/cbuf_in_namespace.hlsl
create mode 100644 clang/test/CodeGenHLSL/cbuffer.hlsl
create mode 100644 clang/test/CodeGenHLSL/cbuffer_and_namespaces.hlsl
create mode 100644 clang/test/CodeGenHLSL/cbuffer_with_packoffset.hlsl
create mode 100644 clang/test/CodeGenHLSL/cbuffer_with_static_global_and_function.hlsl
delete mode 100644 clang/test/CodeGenHLSL/static_global_and_function_in_cb.hlsl
diff --git a/clang/include/clang/Basic/Attr.td b/clang/include/clang/Basic/Attr.td
index 90d2a2056fe1ba..f615f45a9524d8 100644
--- a/clang/include/clang/Basic/Attr.td
+++ b/clang/include/clang/Basic/Attr.td
@@ -4711,9 +4711,9 @@ def HLSLPackOffset: HLSLAnnotationAttr {
let Args = [IntArgument<"Subcomponent">, IntArgument<"Component">];
let Documentation = [HLSLPackOffsetDocs];
let AdditionalMembers = [{
- unsigned getOffset() {
- return subcomponent * 4 + component;
- }
+ unsigned getOffsetInBytes() {
+ return subcomponent * 16 + component * 4;
+ }
}];
}
diff --git a/clang/lib/CodeGen/CGDeclCXX.cpp b/clang/lib/CodeGen/CGDeclCXX.cpp
index 2c3054605ee754..2869150a5e6648 100644
--- a/clang/lib/CodeGen/CGDeclCXX.cpp
+++ b/clang/lib/CodeGen/CGDeclCXX.cpp
@@ -886,6 +886,10 @@ CodeGenModule::EmitCXXGlobalInitFunc() {
ModuleInits.push_back(Fn);
}
+ if (getLangOpts().HLSL && getHLSLRuntime().needsResourceBindingInitFn()) {
+ CXXGlobalInits.push_back(getHLSLRuntime().createResourceBindingInitFn());
+ }
+
if (ModuleInits.empty() && CXXGlobalInits.empty() &&
PrioritizedCXXGlobalInits.empty())
return;
@@ -1127,14 +1131,6 @@ CodeGenFunction::GenerateCXXGlobalInitFunc(llvm::Function *Fn,
if (Decls[i])
EmitRuntimeCall(Decls[i]);
- if (getLangOpts().HLSL) {
- CGHLSLRuntime &CGHLSL = CGM.getHLSLRuntime();
- if (CGHLSL.needsResourceBindingInitFn()) {
- llvm::Function *ResInitFn = CGHLSL.createResourceBindingInitFn();
- Builder.CreateCall(llvm::FunctionCallee(ResInitFn), {});
- }
- }
-
Scope.ForceCleanup();
if (ExitBlock) {
diff --git a/clang/lib/CodeGen/CGHLSLRuntime.cpp b/clang/lib/CodeGen/CGHLSLRuntime.cpp
index fb15b1993e74ad..82fae11bc7bc37 100644
--- a/clang/lib/CodeGen/CGHLSLRuntime.cpp
+++ b/clang/lib/CodeGen/CGHLSLRuntime.cpp
@@ -54,69 +54,110 @@ void addDxilValVersion(StringRef ValVersionStr, llvm::Module &M) {
auto *DXILValMD = M.getOrInsertNamedMetadata(DXILValKey);
DXILValMD->addOperand(Val);
}
+
void addDisableOptimizations(llvm::Module &M) {
StringRef Key = "dx.disable_optimizations";
M.addModuleFlag(llvm::Module::ModFlagBehavior::Override, Key, 1);
}
-// cbuffer will be translated into global variable in special address space.
-// If translate into C,
-// cbuffer A {
-// float a;
-// float b;
-// }
-// float foo() { return a + b; }
-//
-// will be translated into
-//
-// struct A {
-// float a;
-// float b;
-// } cbuffer_A __attribute__((address_space(4)));
-// float foo() { return cbuffer_A.a + cbuffer_A.b; }
-//
-// layoutBuffer will create the struct A type.
-// replaceBuffer will replace use of global variable a and b with cbuffer_A.a
-// and cbuffer_A.b.
-//
-void layoutBuffer(CGHLSLRuntime::Buffer &Buf, const DataLayout &DL) {
- if (Buf.Constants.empty())
- return;
+
+// Creates the LLVM struct type representing the shape of the constant buffer
+// which will be included in the LLVM target type and calculates the memory
+// layout and constant buffer layout offsets of each constant.
+static void layoutBuffer(CGHLSLRuntime::Buffer &Buf, const DataLayout &DL) {
+ assert(!Buf.Constants.empty() &&
+ "empty constant buffer should not be created");
std::vector<llvm::Type *> EltTys;
- for (auto &Const : Buf.Constants) {
- GlobalVariable *GV = Const.first;
- Const.second = EltTys.size();
+ unsigned MemOffset = 0, CBufOffset = 0, Size = 0;
+
+ for (auto &C : Buf.Constants) {
+ GlobalVariable *GV = C.GlobalVar;
llvm::Type *Ty = GV->getValueType();
+
+ assert(!Ty->isArrayTy() && !Ty->isStructTy() &&
+ "arrays and structs in cbuffer are not yet implemened");
+
+ // scalar type, vector or matrix
EltTys.emplace_back(Ty);
+ unsigned FieldSize = Ty->getScalarSizeInBits() / 8;
+ if (Ty->isVectorTy())
+ FieldSize *= cast<FixedVectorType>(Ty)->getNumElements();
+ assert(FieldSize <= 16 && "field side larger than constant buffer row");
+
+ // set memory layout offset (no padding)
+ C.MemOffset = MemOffset;
+ MemOffset += FieldSize;
+
+ // calculate cbuffer layout offset or update total cbuffer size from
+ // packoffset annotations
+ if (Buf.HasPackoffset) {
+ assert(C.CBufferOffset != UINT_MAX &&
+ "cbuffer offset should have been set from packoffset attribute");
+ unsigned OffsetAfterField = C.CBufferOffset + FieldSize;
+ if (Size < OffsetAfterField)
+ Size = OffsetAfterField;
+ } else {
+ // allign to the size of the field
+ CBufOffset = llvm::alignTo(CBufOffset, FieldSize);
+ C.CBufferOffset = CBufOffset;
+ CBufOffset += FieldSize;
+ Size = CBufOffset;
+ }
}
Buf.LayoutStruct = llvm::StructType::get(EltTys[0]->getContext(), EltTys);
+ Buf.Size = Size;
}
-GlobalVariable *replaceBuffer(CGHLSLRuntime::Buffer &Buf) {
- // Create global variable for CB.
- GlobalVariable *CBGV = new GlobalVariable(
- Buf.LayoutStruct, /*isConstant*/ true,
- GlobalValue::LinkageTypes::ExternalLinkage, nullptr,
- llvm::formatv("{0}{1}", Buf.Name, Buf.IsCBuffer ? ".cb." : ".tb."),
- GlobalValue::NotThreadLocal);
+// Creates LLVM target type target("dx.CBuffer",..) for the constant buffer.
+// The target type includes the LLVM struct type representing the shape
+// of the constant buffer, size, and a list of offsets for each fields
+// in cbuffer layout.
+static llvm::Type *getBufferTargetType(LLVMContext &Ctx,
+ CGHLSLRuntime::Buffer &Buf) {
+ assert(Buf.LayoutStruct != nullptr && Buf.Size != UINT_MAX &&
+ "the buffer layout has not been calculated yet");
+ llvm::SmallVector<unsigned> SizeAndOffsets;
+ SizeAndOffsets.reserve(Buf.Constants.size() + 1);
+ SizeAndOffsets.push_back(Buf.Size);
+ for (CGHLSLRuntime::BufferConstant &C : Buf.Constants) {
+ SizeAndOffsets.push_back(C.CBufferOffset);
+ }
+ return llvm::TargetExtType::get(Ctx, "dx.CBuffer", {Buf.LayoutStruct},
+ SizeAndOffsets);
+}
- IRBuilder<> B(CBGV->getContext());
- Value *ZeroIdx = B.getInt32(0);
- // Replace Const use with CB use.
- for (auto &[GV, Offset] : Buf.Constants) {
- Value *GEP =
- B.CreateGEP(Buf.LayoutStruct, CBGV, {ZeroIdx, B.getInt32(Offset)});
-
- assert(Buf.LayoutStruct->getElementType(Offset) == GV->getValueType() &&
- "constant type mismatch");
-
- // Replace.
- GV->replaceAllUsesWith(GEP);
- // Erase GV.
- GV->removeDeadConstantUsers();
- GV->eraseFromParent();
+// Replaces all uses of the temporary constant buffer global variables with
+// buffer access intrinsic resource.getpointer.
+static void replaceBufferGlobals(CodeGenModule &CGM,
+ CGHLSLRuntime::Buffer &Buf) {
+ assert(Buf.IsCBuffer && "tbuffer codegen is not yet supported");
+
+ GlobalVariable *BufGV = Buf.GlobalVar;
+ for (auto &Constant : Buf.Constants) {
+ GlobalVariable *ConstGV = Constant.GlobalVar;
+
+ // TODO: Map to an hlsl_device address space.
+ llvm::Type *RetTy = ConstGV->getType();
+ llvm::Type *TargetTy = BufGV->getValueType();
+
+ // Replace all uses of GV with CBuffer access
+ while (ConstGV->use_begin() != ConstGV->use_end()) {
+ Use &U = *ConstGV->use_begin();
+ if (Instruction *UserInstr = dyn_cast<Instruction>(U.getUser())) {
+ IRBuilder<> Builder(UserInstr);
+ Value *Handle = Builder.CreateLoad(TargetTy, BufGV);
+ Value *ResGetPointer = Builder.CreateIntrinsic(
+ RetTy, Intrinsic::dx_resource_getpointer,
+ ArrayRef<llvm::Value *>{Handle,
+ Builder.getInt32(Constant.MemOffset)});
+ U.set(ResGetPointer);
+ } else {
+ llvm_unreachable("unexpected use of constant value");
+ }
+ }
+ ConstGV->removeDeadConstantUsers();
+ ConstGV->eraseFromParent();
}
- return CBGV;
}
} // namespace
@@ -143,6 +184,9 @@ void CGHLSLRuntime::addConstant(VarDecl *D, Buffer &CB) {
return;
}
+ assert(!D->getType()->isArrayType() && !D->getType()->isStructureType() &&
+ "codegen for arrays and structs in cbuffer is not yet supported");
+
auto *GV = cast<GlobalVariable>(CGM.GetAddrOfGlobalVar(D));
// Add debug info for constVal.
if (CGDebugInfo *DI = CGM.getModuleDebugInfo())
@@ -150,13 +194,12 @@ void CGHLSLRuntime::addConstant(VarDecl *D, Buffer &CB) {
codegenoptions::DebugInfoKind::LimitedDebugInfo)
DI->EmitGlobalVariable(cast<GlobalVariable>(GV), D);
- // FIXME: support packoffset.
- // See https://github.com/llvm/llvm-project/issues/57914.
- uint32_t Offset = 0;
- bool HasUserOffset = false;
+ CB.Constants.emplace_back(GV);
- unsigned LowerBound = HasUserOffset ? Offset : UINT_MAX;
- CB.Constants.emplace_back(std::make_pair(GV, LowerBound));
+ if (HLSLPackOffsetAttr *PO = D->getAttr<HLSLPackOffsetAttr>()) {
+ CB.HasPackoffset = true;
+ CB.Constants.back().CBufferOffset = PO->getOffsetInBytes();
+ }
}
void CGHLSLRuntime::addBufferDecls(const DeclContext *DC, Buffer &CB) {
@@ -173,9 +216,37 @@ void CGHLSLRuntime::addBufferDecls(const DeclContext *DC, Buffer &CB) {
}
}
+// Creates temporary global variables for all declarations within the constant
+// buffer context, calculates the buffer layouts, and then creates a global
+// variable for the constant buffer and adds it to the module.
+// All uses of the temporary constant globals will be replaced with buffer
+// access intrinsic resource.getpointer in CGHLSLRuntime::finishCodeGen.
+// Later on in DXILResourceAccess pass these will be transtaled
+// to dx.op.cbufferLoadLegacy instructions.
void CGHLSLRuntime::addBuffer(const HLSLBufferDecl *D) {
- Buffers.emplace_back(Buffer(D));
- addBufferDecls(D, Buffers.back());
+ llvm::Module &M = CGM.getModule();
+ const DataLayout &DL = M.getDataLayout();
+
+ assert(D->isCBuffer() && "tbuffer codegen is not supported yet");
+
+ Buffer &Buf = Buffers.emplace_back(D);
+ addBufferDecls(D, Buf);
+ if (Buf.Constants.empty()) {
+ // empty constant buffer - do not add to globals
+ Buffers.pop_back();
+ return;
+ }
+ layoutBuffer(Buf, DL);
+
+ // Create global variable for CB.
+ llvm::Type *TargetTy = getBufferTargetType(CGM.getLLVMContext(), Buf);
+ Buf.GlobalVar = new GlobalVariable(
+ TargetTy, /*isConstant*/ true, GlobalValue::LinkageTypes::ExternalLinkage,
+ nullptr, llvm::formatv("{0}{1}", Buf.Name, Buf.IsCBuffer ? ".cb" : ".tb"),
+ GlobalValue::NotThreadLocal);
+
+ M.insertGlobalVariable(Buf.GlobalVar);
+ ResourcesToBind.emplace_back(Buf.Decl, Buf.GlobalVar);
}
void CGHLSLRuntime::finishCodeGen() {
@@ -189,26 +260,14 @@ void CGHLSLRuntime::finishCodeGen() {
if (CGM.getCodeGenOpts().OptimizationLevel == 0)
addDisableOptimizations(M);
- const DataLayout &DL = M.getDataLayout();
-
for (auto &Buf : Buffers) {
- layoutBuffer(Buf, DL);
- GlobalVariable *GV = replaceBuffer(Buf);
- M.insertGlobalVariable(GV);
- llvm::hlsl::ResourceClass RC = Buf.IsCBuffer
- ? llvm::hlsl::ResourceClass::CBuffer
- : llvm::hlsl::ResourceClass::SRV;
- llvm::hlsl::ResourceKind RK = Buf.IsCBuffer
- ? llvm::hlsl::ResourceKind::CBuffer
- : llvm::hlsl::ResourceKind::TBuffer;
- addBufferResourceAnnotation(GV, RC, RK, /*IsROV=*/false,
- llvm::hlsl::ElementType::Invalid, Buf.Binding);
+ replaceBufferGlobals(CGM, Buf);
}
}
CGHLSLRuntime::Buffer::Buffer(const HLSLBufferDecl *D)
- : Name(D->getName()), IsCBuffer(D->isCBuffer()),
- Binding(D->getAttr<HLSLResourceBindingAttr>()) {}
+ : Name(D->getName()), IsCBuffer(D->isCBuffer()), HasPackoffset(false),
+ LayoutStruct(nullptr), Decl(D), GlobalVar(nullptr) {}
void CGHLSLRuntime::addBufferResourceAnnotation(llvm::GlobalVariable *GV,
llvm::hlsl::ResourceClass RC,
@@ -237,7 +296,7 @@ void CGHLSLRuntime::addBufferResourceAnnotation(llvm::GlobalVariable *GV,
"ResourceMD must have been set by the switch above.");
llvm::hlsl::FrontendResource Res(
- GV, RK, ET, IsROV, Binding.Reg.value_or(UINT_MAX), Binding.Space);
+ GV, RK, ET, IsROV, Binding.Slot.value_or(UINT_MAX), Binding.Space);
ResourceMD->addOperand(Res.getMetadata());
}
@@ -328,12 +387,8 @@ void CGHLSLRuntime::annotateHLSLResource(const VarDecl *D, GlobalVariable *GV) {
CGHLSLRuntime::BufferResBinding::BufferResBinding(
HLSLResourceBindingAttr *Binding) {
if (Binding) {
- llvm::APInt RegInt(64, 0);
- Binding->getSlot().substr(1).getAsInteger(10, RegInt);
- Reg = RegInt.getLimitedValue();
- llvm::APInt SpaceInt(64, 0);
- Binding->getSpace().substr(5).getAsInteger(10, SpaceInt);
- Space = SpaceInt.getLimitedValue();
+ Slot = Binding->getSlotNumber();
+ Space = Binding->getSpaceNumber();
} else {
Space = 0;
}
@@ -572,24 +627,30 @@ llvm::Function *CGHLSLRuntime::createResourceBindingInitFn() {
const DataLayout &DL = CGM.getModule().getDataLayout();
Builder.SetInsertPoint(EntryBB);
- for (const auto &[VD, GV] : ResourcesToBind) {
- for (Attr *A : VD->getAttrs()) {
+ for (const auto &[Decl, GV] : ResourcesToBind) {
+ for (Attr *A : Decl->getAttrs()) {
HLSLResourceBindingAttr *RBA = dyn_cast<HLSLResourceBindingAttr>(A);
if (!RBA)
continue;
- const HLSLAttributedResourceType *AttrResType =
- HLSLAttributedResourceType::findHandleTypeOnResource(
- VD->getType().getTypePtr());
-
- // FIXME: Only simple declarations of resources are supported for now.
- // Arrays of resources or resources in user defined classes are
- // not implemented yet.
- assert(AttrResType != nullptr &&
- "Resource class must have a handle of HLSLAttributedResourceType");
-
- llvm::Type *TargetTy =
- CGM.getTargetCodeGenInfo().getHLSLType(CGM, AttrResType);
+ llvm::Type *TargetTy = nullptr;
+ if (const VarDecl *VD = dyn_cast<VarDecl>(Decl)) {
+ const HLSLAttributedResourceType *AttrResType =
+ HLSLAttributedResourceType::findHandleTypeOnResource(
+ VD->getType().getTypePtr());
+
+ // FIXME: Only simple declarations of resources are supported for now.
+ // Arrays of resources or resources in user defined classes are
+ // not implemented yet.
+ assert(
+ AttrResType != nullptr &&
+ "Resource class must have a handle of HLSLAttributedResourceType");
+
+ TargetTy = CGM.getTargetCodeGenInfo().getHLSLType(CGM, AttrResType);
+ } else {
+ assert(isa<HLSLBufferDecl>(Decl));
+ TargetTy = GV->getValueType();
+ }
assert(TargetTy != nullptr &&
"Failed to convert resource handle to target type");
@@ -604,7 +665,7 @@ llvm::Function *CGHLSLRuntime::createResourceBindingInitFn() {
llvm::Value *CreateHandle = Builder.CreateIntrinsic(
/*ReturnType=*/TargetTy, getCreateHandleFromBindingIntrinsic(), Args,
- nullptr, Twine(VD->getName()).concat("_h"));
+ nullptr, Twine(Decl->getName()).concat("_h"));
llvm::Value *HandleRef =
Builder.CreateStructGEP(GV->getValueType(), GV, 0);
diff --git a/clang/lib/CodeGen/CGHLSLRuntime.h b/clang/lib/CodeGen/CGHLSLRuntime.h
index f9efb1bc996412..9c3bbf5bbfe190 100644
--- a/clang/lib/CodeGen/CGHLSLRuntime.h
+++ b/clang/lib/CodeGen/CGHLSLRuntime.h
@@ -15,6 +15,7 @@
#ifndef LLVM_CLANG_LIB_CODEGEN_CGHLSLRUNTIME_H
#define LLVM_CLANG_LIB_CODEGEN_CGHLSLRUNTIME_H
+#include "llvm/IR/GlobalVariable.h"
#include "llvm/IR/IRBuilder.h"
#include "llvm/IR/Intrinsics.h"
#include "llvm/IR/IntrinsicsDirectX.h"
@@ -53,6 +54,7 @@ class StructType;
} // namespace llvm
namespace clang {
+class NamedDecl;
class VarDecl;
class ParmVarDecl;
class HLSLBufferDecl;
@@ -112,22 +114,43 @@ class CGHLSLRuntime {
//===----------------------------------------------------------------------===//
struct BufferResBinding {
- // The ID like 2 in register(b2, space1).
- std::optional<unsigned> Reg;
- // The Space like 1 is register(b2, space1).
- // Default value is 0.
+ // Register slot
+ std::optional<unsigned> Slot;
+ // Register space; default value is 0.
unsigned Space;
+
BufferResBinding(HLSLResourceBindingAttr *Attr);
};
+
+ struct BufferConstant {
+ llvm::GlobalVariable *GlobalVar;
+ // offset in memory layout (in bytes)
+ unsigned MemOffset;
+ // offset in cbuffer layout (in bytes)
+ unsigned CBufferOffset;
+
+ BufferConstant(llvm::GlobalVariable *GV)
+ : GlobalVar(GV), MemOffset(UINT_MAX), CBufferOffset(UINT_MAX) {}
+ };
+
struct Buffer {
- Buffer(const HLSLBufferDecl *D);
llvm::StringRef Name;
- // IsCBuffer - Whether the buffer is a cbuffer (and not a tbuffer).
+ // Whether the buffer is a cbuffer (and not a tbuffer).
bool IsCBuffer;
- BufferResBinding Binding;
- // Global variable and offset for each constant.
- std::vector<std::pair<llvm::GlobalVariable *, unsigned>> Constants;
- llvm::StructType *LayoutStruct = nullptr;
+ // Whether the buffer has packoffset annotations
+ bool HasPackoffset;
+ // List of global constants with memory and cbuffer layout ofsets
+ std::vector<BufferConstant> Constants;
+ // LLVM layout type
+ llvm::StructType *LayoutStruct;
+ // size of the buffer in cbuffer layout
+ unsigned Size;
+ // reference to the AST Decl node with resource binding attribute
+ const HLSLBufferDecl *Decl;
+ // global variable for the constant buffer
+ llvm::GlobalVariable *GlobalVar;
+
+ Buffer(const HLSLBufferDecl *D);
};
protected:
@@ -169,7 +192,7 @@ class CGHLSLRuntime {
llvm::Triple::ArchType getArch();
llvm::SmallVector<Buffer> Buffers;
- llvm::SmallVector<std::pair<const VarDecl *, llvm::GlobalVariable *>>
+ llvm::SmallVector<std::pair<const NamedDecl *, llvm::GlobalVariable *>>
ResourcesToBind;
};
diff --git a/clang/lib/Sema/SemaHLSL.cpp b/clang/lib/Sema/SemaHLSL.cpp
index 600c800029fd05..9b96806c35f3da 100644
--- a/clang/lib/Sema/SemaHLSL.cpp
+++ b/clang/lib/Sema/SemaHLSL.cpp
@@ -164,18 +164,18 @@ Decl *SemaHLSL::ActOnStartBuffer(Scope *BufferScope, bool CBuffer,
return Result;
}
-// Calculate the size of a legacy cbuffer type based on
+// Calculate the size of a legacy cbuffer type in bytes based on
// https://learn.microsoft.com/en-us/windows/win32/direct3dhlsl/dx-graphics-hlsl-packing-rules
static unsigned calculateLegacyCbufferSize(const ASTContext &Context,
QualType T) {
unsigned Size = 0;
- constexpr unsigned CBufferAlign = 128;
+ constexpr unsigned CBufferAlign = 16;
if (const RecordType *RT = T->getAs<RecordType>()) {
const RecordDecl *RD = RT->getDecl();
for (const FieldDecl *Field : RD->fields()) {
QualType Ty = Field->getType();
unsigned FieldSize = calculateLegacyCbufferSize(Context, Ty);
- unsigned FieldAlign = 32;
+ unsigned FieldAlign = 4;
if (Ty->isAggregateType())
FieldAlign = CBufferAlign;
Size = llvm::alignTo(Size, FieldAlign);
@@ -194,7 +194,7 @@ static unsigned calculateLegacyCbufferSize(const ASTContext &Context,
calculateLegacyCbufferSize(Context, VT->getElementType());
Size = ElementSize * ElementCount;
} else {
- Size = Context.getTypeSize(T);
+ Size = Context.getTypeSize(T) / 8;
}
return Size;
}
@@ -229,16 +229,17 @@ void SemaHLSL::ActOnFinishBuffer(Decl *Dcl, SourceLocation RBrace) {
std::sort(PackOffsetVec.begin(), PackOffsetVec.end(),
[](const std::pair<VarDecl *, HLSLPackOffsetAttr *> &LHS,
const std::pair<VarDecl *, HLSLPackOffsetAttr *> &RHS) {
- return LHS.second->getOffset() < RHS.second->getOffset();
+ return LHS.second->getOffsetInBytes() <
+ RHS.second->getOffsetInBytes();
});
for (unsigned i = 0; i < PackOffsetVec.size() - 1; i++) {
VarDecl *Var = PackOffsetVec[i].first;
HLSLPackOffsetAttr *Attr = PackOffsetVec[i].second;
unsigned Size = calculateLegacyCbufferSize(Context, Var->getType());
- unsigned Begin = Attr->getOffset() * 32;
+ unsigned Begin = Attr->getOffsetInBytes();
unsigned End = Begin + Size;
- unsigned NextBegin = PackOffsetVec[i + 1].second->getOffset() * 32;
+ unsigned NextBegin = PackOffsetVec[i + 1].second->getOffsetInBytes();
if (End > NextBegin) {
VarDecl *NextVar = PackOffsetVec[i + 1].first;
Diag(NextVar->getLocation(), diag::err_hlsl_packoffset_overlap)
diff --git a/clang/test/CodeGenHLSL/builtins/ByteAddressBuffers-constructors.hlsl b/clang/test/CodeGenHLSL/builtins/ByteAddressBuffers-constructors.hlsl
index 45e135427ba9c3..f1e949ab652cce 100644
--- a/clang/test/CodeGenHLSL/builtins/ByteAddressBuffers-constructors.hlsl
+++ b/clang/test/CodeGenHLSL/builtins/ByteAddressBuffers-constructors.hlsl
@@ -15,10 +15,6 @@ RasterizerOrderedByteAddressBuffer Buffer2: register(u3, space4);
// CHECK: @Buffer1 = global %"class.hlsl::RWByteAddressBuffer" zeroinitializer, align 4
// CHECK: @Buffer2 = global %"class.hlsl::RasterizerOrderedByteAddressBuffer" zeroinitializer, align 4
-// CHECK: define internal void @_GLOBAL__sub_I_ByteAddressBuffers_constructors.hlsl()
-// CHECK: entry:
-// CHECK: call void @_init_resource_bindings()
-
// CHECK: define internal void @_init_resource_bindings() {
// CHECK-NEXT: entry:
// CHECK-DXIL-NEXT: %Buffer0_h = call target("dx.RawBuffer", i8, 0, 0) @llvm.dx.handle.fromBinding.tdx.RawBuffer_i8_0_0t(i32 0, i32 0, i32 1, i32 0, i1 false)
@@ -27,3 +23,7 @@ RasterizerOrderedByteAddressBuffer Buffer2: register(u3, space4);
// CHECK-DXIL-NEXT: store target("dx.RawBuffer", i8, 1, 0) %Buffer1_h, ptr @Buffer1, align 4
// CHECK-DXIL-NEXT: %Buffer2_h = call target("dx.RawBuffer", i8, 1, 1) @llvm.dx.handle.fromBinding.tdx.RawBuffer_i8_1_1t(i32 4, i32 3, i32 1, i32 0, i1 false)
// CHECK-DXIL-NEXT: store target("dx.RawBuffer", i8, 1, 1) %Buffer2_h, ptr @Buffer2, align 4
+
+// CHECK: define internal void @_GLOBAL__sub_I_ByteAddressBuffers_constructors.hlsl()
+// CHECK: entry:
+// CHECK: call void @_init_resource_bindings()
diff --git a/clang/test/CodeGenHLSL/builtins/RWBuffer-constructor.hlsl b/clang/test/CodeGenHLSL/builtins/RWBuffer-constructor.hlsl
index c2db56e2b2bddf..8f252ea357459a 100644
--- a/clang/test/CodeGenHLSL/builtins/RWBuffer-constructor.hlsl
+++ b/clang/test/CodeGenHLSL/builtins/RWBuffer-constructor.hlsl
@@ -12,14 +12,14 @@ RWBuffer<float> Buf : register(u5, space3);
// CHECK: define linkonce_odr void @_ZN4hlsl8RWBufferIfEC2Ev(ptr noundef nonnull align 4 dereferenceable(4) %this)
// CHECK-NEXT: entry:
-// CHECK: define internal void @_GLOBAL__sub_I_RWBuffer_constructor.hlsl()
-// CHECK-NEXT: entry:
-// CHECK-NEXT: call void @__cxx_global_var_init()
-// CHECK-NEXT: call void @_init_resource_bindings()
-
// CHECK: define internal void @_init_resource_bindings() {
// CHECK-NEXT: entry:
// CHECK-DXIL-NEXT: %Buf_h = call target("dx.TypedBuffer", float, 1, 0, 0) @llvm.dx.handle.fromBinding.tdx.TypedBuffer_f32_1_0_0t(i32 3, i32 5, i32 1, i32 0, i1 false)
// CHECK-DXIL-NEXT: store target("dx.TypedBuffer", float, 1, 0, 0) %Buf_h, ptr @Buf, align 4
// CHECK-SPIRV-NEXT: %Buf_h = call target("dx.TypedBuffer", float, 1, 0, 0) @llvm.spv.handle.fromBinding.tdx.TypedBuffer_f32_1_0_0t(i32 3, i32 5, i32 1, i32 0, i1 false)
// CHECK-SPIRV-NEXT: store target("dx.TypedBuffer", float, 1, 0, 0) %Buf_h, ptr @Buf, align 4
+
+// CHECK: define internal void @_GLOBAL__sub_I_RWBuffer_constructor.hlsl()
+// CHECK-NEXT: entry:
+// CHECK-NEXT: call void @__cxx_global_var_init()
+// CHECK-NEXT: call void @_init_resource_bindings()
diff --git a/clang/test/CodeGenHLSL/builtins/StructuredBuffers-constructors.hlsl b/clang/test/CodeGenHLSL/builtins/StructuredBuffers-constructors.hlsl
index d84e92242ffb4d..17cba38cc8283f 100644
--- a/clang/test/CodeGenHLSL/builtins/StructuredBuffers-constructors.hlsl
+++ b/clang/test/CodeGenHLSL/builtins/StructuredBuffers-constructors.hlsl
@@ -31,10 +31,6 @@ RasterizerOrderedStructuredBuffer<float> Buf5 : register(u1, space2);
// CHECK: define linkonce_odr void @_ZN4hlsl33RasterizerOrderedStructuredBufferIfEC2Ev(ptr noundef nonnull align 4 dereferenceable(4) %this)
// CHECK-NEXT: entry:
-// CHECK: define internal void @_GLOBAL__sub_I_StructuredBuffers_constructors.hlsl()
-// CHECK: entry:
-// CHECK: call void @_init_resource_bindings()
-
// CHECK: define internal void @_init_resource_bindings() {
// CHECK-NEXT: entry:
// CHECK-DXIL-NEXT: %Buf_h = call target("dx.RawBuffer", float, 0, 0) @llvm.dx.handle.fromBinding.tdx.RawBuffer_f32_0_0t(i32 0, i32 10, i32 1, i32 0, i1 false)
@@ -58,3 +54,7 @@ RasterizerOrderedStructuredBuffer<float> Buf5 : register(u1, space2);
// CHECK-SPIRV-NEXT: store target("dx.RawBuffer", float, 1, 0) %Buf4_h, ptr @Buf4, align 4
// CHECK-SPIRV-NEXT: %Buf5_h = call target("dx.RawBuffer", float, 1, 1) @llvm.spv.handle.fromBinding.tdx.RawBuffer_f32_1_1t(i32 2, i32 1, i32 1, i32 0, i1 false)
// CHECK-SPIRV-NEXT: store target("dx.RawBuffer", float, 1, 1) %Buf5_h, ptr @Buf5, align 4
+
+// CHECK: define internal void @_GLOBAL__sub_I_StructuredBuffers_constructors.hlsl()
+// CHECK: entry:
+// CHECK: call void @_init_resource_bindings()
diff --git a/clang/test/CodeGenHLSL/cbuf.hlsl b/clang/test/CodeGenHLSL/cbuf.hlsl
deleted file mode 100644
index 3f9d4514967dd2..00000000000000
--- a/clang/test/CodeGenHLSL/cbuf.hlsl
+++ /dev/null
@@ -1,26 +0,0 @@
-// RUN: %clang_cc1 -finclude-default-header -x hlsl -triple \
-// RUN: dxil-pc-shadermodel6.3-library %s \
-// RUN: -emit-llvm -disable-llvm-passes -o - | FileCheck %s
-
-// CHECK: @[[CB:.+]] = external constant { float, double }
-cbuffer A : register(b0, space2) {
- float a;
- double b;
-}
-
-// CHECK: @[[TB:.+]] = external constant { float, double }
-tbuffer A : register(t2, space1) {
- float c;
- double d;
-}
-
-float foo() {
-// CHECK: load float, ptr @[[CB]], align 4
-// CHECK: load double, ptr getelementptr ({ float, double }, ptr @[[CB]], i32 0, i32 1), align 8
-// CHECK: load float, ptr @[[TB]], align 4
-// CHECK: load double, ptr getelementptr ({ float, double }, ptr @[[TB]], i32 0, i32 1), align 8
- return a + b + c*d;
-}
-
-// CHECK: !hlsl.cbufs = !{![[CBMD:[0-9]+]]}
-// CHECK: ![[CBMD]] = !{ptr @[[CB]], i32 13, i32 0, i1 false, i32 0, i32 2}
diff --git a/clang/test/CodeGenHLSL/cbuf_in_namespace.hlsl b/clang/test/CodeGenHLSL/cbuf_in_namespace.hlsl
deleted file mode 100644
index 73dc376942dfb7..00000000000000
--- a/clang/test/CodeGenHLSL/cbuf_in_namespace.hlsl
+++ /dev/null
@@ -1,23 +0,0 @@
-// RUN: %clang_cc1 -finclude-default-header -x hlsl -triple \
-// RUN: dxil-pc-shadermodel6.3-library %s \
-// RUN: -emit-llvm -disable-llvm-passes -o - | FileCheck %s
-
-// Make sure cbuffer inside namespace works.
-// CHECK: @[[CB:.+]] = external constant { float }
-// CHECK: @[[TB:.+]] = external constant { float }
-namespace n0 {
-namespace n1 {
- cbuffer A {
- float a;
- }
-}
- tbuffer B {
- float b;
- }
-}
-
-float foo() {
-// CHECK: load float, ptr @[[CB]], align 4
-// CHECK: load float, ptr @[[TB]], align 4
- return n0::n1::a + n0::b;
-}
diff --git a/clang/test/CodeGenHLSL/cbuffer.hlsl b/clang/test/CodeGenHLSL/cbuffer.hlsl
new file mode 100644
index 00000000000000..4d6b55157f30a5
--- /dev/null
+++ b/clang/test/CodeGenHLSL/cbuffer.hlsl
@@ -0,0 +1,67 @@
+// RUN: %clang_cc1 -finclude-default-header -x hlsl -triple \
+// RUN: dxil-pc-shadermodel6.3-compute %s \
+// RUN: -emit-llvm -disable-llvm-passes -o - | FileCheck %s
+
+// CHECK: @CB1.cb = external constant target("dx.CBuffer", { float, double }, 16, 0, 8)
+cbuffer CB1 : register(b0, space2) {
+ float a;
+ double b;
+}
+
+// CHECK: @ParticleLifeCB.cb = external constant target("dx.CBuffer", { i32, i32, <2 x float>, float, float }, 24, 0, 4, 8, 16, 20)
+cbuffer ParticleLifeCB : register(b2, space1) {
+ uint ParticleTypeMax;
+ uint NumParticles;
+ float2 WorldSize;
+ float Friction;
+ float ForceMultipler;
+}
+
+float foo() {
+// CHECK: %[[HANDLE1:[0-9]+]] = load target("dx.CBuffer", { float, double }, 16, 0, 8), ptr @CB1.cb, align 4
+// CHECK: %[[PTR1:[0-9]+]] = call ptr @llvm.dx.resource.getpointer.p0.tdx.CBuffer_sl_f32f64s_16_0_8t(target("dx.CBuffer", { float, double }, 16, 0, 8) %[[HANDLE1]], i32 0)
+// CHECK: load float, ptr %[[PTR1]], align 4
+
+// CHECK: %[[HANDLE2:[0-9]+]] = load target("dx.CBuffer", { float, double }, 16, 0, 8), ptr @CB1.cb, align 4
+// CHECK: %[[PTR2:[0-9]+]] = call ptr @llvm.dx.resource.getpointer.p0.tdx.CBuffer_sl_f32f64s_16_0_8t(target("dx.CBuffer", { float, double }, 16, 0, 8) %[[HANDLE2]], i32 4)
+// CHECK: load double, ptr %[[PTR2]], align 8
+
+// CHECK: %[[HANDLE3:[0-9]+]] = load target("dx.CBuffer", { i32, i32, <2 x float>, float, float }, 24, 0, 4, 8, 16, 20), ptr @ParticleLifeCB.cb, align 4
+// CHECK: %[[PTR3:[0-9]+]] = call ptr @llvm.dx.resource.getpointer.p0.tdx.CBuffer_sl_i32i32v2f32f32f32s_24_0_4_8_16_20t(
+// CHECK-SAME: target("dx.CBuffer", { i32, i32, <2 x float>, float, float }, 24, 0, 4, 8, 16, 20) %[[HANDLE3]], i32 0)
+// CHECK: load i32, ptr %[[PTR3]], align 4
+
+// CHECK: %[[HANDLE4:[0-9]+]] = load target("dx.CBuffer", { i32, i32, <2 x float>, float, float }, 24, 0, 4, 8, 16, 20), ptr @ParticleLifeCB.cb, align 4
+// CHECK: %[[PTR4:[0-9]+]] = call ptr @llvm.dx.resource.getpointer.p0.tdx.CBuffer_sl_i32i32v2f32f32f32s_24_0_4_8_16_20t(
+// CHECK-SAME: target("dx.CBuffer", { i32, i32, <2 x float>, float, float }, 24, 0, 4, 8, 16, 20) %[[HANDLE4]], i32 8)
+// CHECK: load <2 x float>, ptr %[[PTR4]], align 8
+
+// CHECK: %[[HANDLE5:[0-9]+]] = load target("dx.CBuffer", { i32, i32, <2 x float>, float, float }, 24, 0, 4, 8, 16, 20), ptr @ParticleLifeCB.cb, align 4
+// CHECK: %[[PTR5:[0-9]+]] = call ptr @llvm.dx.resource.getpointer.p0.tdx.CBuffer_sl_i32i32v2f32f32f32s_24_0_4_8_16_20t(
+// CHECK-SAME: target("dx.CBuffer", { i32, i32, <2 x float>, float, float }, 24, 0, 4, 8, 16, 20) %[[HANDLE5]], i32 20)
+// CHECK: load float, ptr %[[PTR5]], align 4
+ return a + b + ParticleTypeMax + WorldSize.y * ForceMultipler;
+}
+
+// CHECK: define void @main()
+// CHECK-NEXT: entry:
+// CHECK-NEXT: call void @_GLOBAL__sub_I_cbuffer.hlsl()
+// CHECK-NEXT: call void @_Z4mainv()
+// CHECK-NEXT: ret void
+
+// CHECK: define internal void @_init_resource_bindings() {
+// CHECK-NEXT: entry:
+// CHECK-NEXT: %CB1_h = call target("dx.CBuffer", { float, double }, 16, 0, 8)
+// CHECK-SAME: @llvm.dx.handle.fromBinding.tdx.CBuffer_sl_f32f64s_16_0_8t(i32 2, i32 0, i32 1, i32 0, i1 false)
+// CHECK-NEXT: store target("dx.CBuffer", { float, double }, 16, 0, 8) %CB1_h, ptr @CB1.cb, align 4
+// CHECK-NEXT: %ParticleLifeCB_h = call target("dx.CBuffer", { i32, i32, <2 x float>, float, float }, 24, 0, 4, 8, 16, 20)
+// CHECK-SAME: @llvm.dx.handle.fromBinding.tdx.CBuffer_sl_i32i32v2f32f32f32s_24_0_4_8_16_20t(i32 1, i32 2, i32 1, i32 0, i1 false)
+// CHECK-NEXT: store target("dx.CBuffer", { i32, i32, <2 x float>, float, float }, 24, 0, 4, 8, 16, 20) %ParticleLifeCB_h, ptr @ParticleLifeCB.cb, align 4
+
+// CHECK: define internal void @_GLOBAL__sub_I_cbuffer.hlsl()
+// CHECK-NEXT: entry:
+// CHECK-NEXT: call void @_init_resource_bindings()
+// CHECK-NEXT: ret void
+
+[numthreads(4,1,1)]
+void main() {}
diff --git a/clang/test/CodeGenHLSL/cbuffer_and_namespaces.hlsl b/clang/test/CodeGenHLSL/cbuffer_and_namespaces.hlsl
new file mode 100644
index 00000000000000..860716ad3e582a
--- /dev/null
+++ b/clang/test/CodeGenHLSL/cbuffer_and_namespaces.hlsl
@@ -0,0 +1,47 @@
+// RUN: %clang_cc1 -finclude-default-header -x hlsl -triple \
+// RUN: dxil-pc-shadermodel6.3-library %s \
+// RUN: -emit-llvm -disable-llvm-passes -o - | FileCheck %s
+
+// Make sure cbuffer inside namespace works.
+// CHECK: @A.cb = external constant target("dx.CBuffer", { float }, 4, 0)
+// CHECK: @B.cb = external constant target("dx.CBuffer", { float }, 4, 0)
+// CHECK: @C.cb = external constant target("dx.CBuffer", { float }, 4, 0)
+
+namespace n0 {
+ namespace n1 {
+ cbuffer A {
+ float a;
+ }
+ }
+ cbuffer B {
+ float a;
+ }
+ namespace n2 {
+ cbuffer C {
+ float a;
+ }
+ }
+}
+
+float foo() {
+// CHECK: %[[HANDLE1:[0-9]+]] = load target("dx.CBuffer", { float }, 4, 0), ptr @A.cb, align 4
+// CHECK: %[[PTR1:[0-9]+]] = call ptr @llvm.dx.resource.getpointer.p0.tdx.CBuffer_sl_f32s_4_0t(target("dx.CBuffer", { float }, 4, 0) %[[HANDLE1]], i32 0)
+// CHECK: %[[VAL1:[0-9]+]] = load float, ptr %[[PTR1]], align 4
+
+// CHECK: %[[HANDLE2:[0-9]+]] = load target("dx.CBuffer", { float }, 4, 0), ptr @B.cb, align 4
+// CHECK: %[[PTR2:[0-9]+]] = call ptr @llvm.dx.resource.getpointer.p0.tdx.CBuffer_sl_f32s_4_0t(target("dx.CBuffer", { float }, 4, 0) %[[HANDLE2]], i32 0)
+// CHECK: %[[VAL2:[0-9]+]] = load float, ptr %[[PTR2]], align 4
+
+// CHECK: %add = fadd float %[[VAL1]], %[[VAL2]]
+
+// CHECK: %[[HANDLE3:[0-9]+]] = load target("dx.CBuffer", { float }, 4, 0), ptr @C.cb, align 4
+// CHECK: %[[PTR3:[0-9]+]] = call ptr @llvm.dx.resource.getpointer.p0.tdx.CBuffer_sl_f32s_4_0t(target("dx.CBuffer", { float }, 4, 0) %[[HANDLE3]], i32 0)
+// CHECK: %[[VAL3:[0-9]+]] = load float, ptr %[[PTR3]], align 4
+
+// CHECK: %add1 = fadd float %add, %[[VAL3]]
+
+ return n0::n1::a + n0::a + n0::n2::a;
+}
+
+[numthreads(4,1,1)]
+void main() {}
diff --git a/clang/test/CodeGenHLSL/cbuffer_with_packoffset.hlsl b/clang/test/CodeGenHLSL/cbuffer_with_packoffset.hlsl
new file mode 100644
index 00000000000000..58891659179aed
--- /dev/null
+++ b/clang/test/CodeGenHLSL/cbuffer_with_packoffset.hlsl
@@ -0,0 +1,33 @@
+// RUN: %clang_cc1 -finclude-default-header -x hlsl -triple \
+// RUN: dxil-pc-shadermodel6.3-compute %s \
+// RUN: -emit-llvm -disable-llvm-passes -o - | FileCheck %s
+
+// CHECK: @CB.cb = external constant target("dx.CBuffer", { float, double }, 176, 16, 168)
+cbuffer CB : register(b1, space3) {
+ float a : packoffset(c1.x);
+ double b : packoffset(c10.z);
+}
+
+float foo() {
+// CHECK: %[[HANDLE1:[0-9]+]] = load target("dx.CBuffer", { float, double }, 176, 16, 168), ptr @CB.cb, align 4
+// CHECK: %[[PTR1:[0-9]+]] = call ptr @llvm.dx.resource.getpointer.p0.tdx.CBuffer_sl_f32f64s_176_16_168t(
+// CHECK-SAME: target("dx.CBuffer", { float, double }, 176, 16, 168) %[[HANDLE1]], i32 0)
+// CHECK: load float, ptr %[[PTR1]], align 4
+
+// CHECK: %[[HANDLE2:[0-9]+]] = load target("dx.CBuffer", { float, double }, 176, 16, 168), ptr @CB.cb, align 4
+// CHECK: %[[PTR2:[0-9]+]] = call ptr @llvm.dx.resource.getpointer.p0.tdx.CBuffer_sl_f32f64s_176_16_168t(
+// CHECK-SAME: target("dx.CBuffer", { float, double }, 176, 16, 168) %[[HANDLE2]], i32 4)
+// CHECK: load double, ptr %[[PTR2]], align 8
+ return a + b;
+}
+
+// CHECK: define internal void @_init_resource_bindings() {
+// CHECK-NEXT: entry:
+// CHECK-NEXT: %CB_h = call target("dx.CBuffer", { float, double }, 176, 16, 168)
+// CHECK-SAME: @llvm.dx.handle.fromBinding.tdx.CBuffer_sl_f32f64s_176_16_168t(i32 3, i32 1, i32 1, i32 0, i1 false)
+// CHECK-NEXT: store target("dx.CBuffer", { float, double }, 176, 16, 168) %CB_h, ptr @CB.cb, align 4
+
+[numthreads(4,1,1)]
+void main() {
+ foo();
+}
diff --git a/clang/test/CodeGenHLSL/cbuffer_with_static_global_and_function.hlsl b/clang/test/CodeGenHLSL/cbuffer_with_static_global_and_function.hlsl
new file mode 100644
index 00000000000000..c72eac85ca675e
--- /dev/null
+++ b/clang/test/CodeGenHLSL/cbuffer_with_static_global_and_function.hlsl
@@ -0,0 +1,28 @@
+// RUN: %clang_cc1 -finclude-default-header -triple dxil-pc-shadermodel6.3-library %s \
+// RUN: -emit-llvm -disable-llvm-passes -o - | FileCheck %s
+
+// CHECK-DAG: @_ZL1b = internal global float 3.000000e+00, align 4
+// CHECK-DAG: @A.cb = external constant target("dx.CBuffer", { float }, 4, 0)
+// CHECK-NOT: @B.cb
+
+cbuffer A {
+ float a;
+ static float b = 3;
+ float foo() { return a + b; }
+}
+
+cbuffer B {
+ // intentionally empty
+}
+
+
+// CHECK: define noundef float @_Z3foov() #0 {
+// CHECK: %[[HANDLE:[0-9]+]] = load target("dx.CBuffer", { float }, 4, 0), ptr @A.cb, align 4
+// CHECK: %[[PTR:[0-9]+]] = call ptr @llvm.dx.resource.getpointer.p0.tdx.CBuffer_sl_f32s_4_0t(target("dx.CBuffer", { float }, 4, 0) %[[HANDLE]], i32 0)
+// CHECK: %[[VAL1:[0-9]+]] = load float, ptr %[[PTR]], align 4
+// CHECK: %[[VAL2:[0-9]+]] = load float, ptr @_ZL1b, align 4
+// CHECK: %add = fadd float %[[VAL1]], %[[VAL2]]
+
+extern float bar() {
+ return foo();
+}
diff --git a/clang/test/CodeGenHLSL/static_global_and_function_in_cb.hlsl b/clang/test/CodeGenHLSL/static_global_and_function_in_cb.hlsl
deleted file mode 100644
index f85bab2113170b..00000000000000
--- a/clang/test/CodeGenHLSL/static_global_and_function_in_cb.hlsl
+++ /dev/null
@@ -1,17 +0,0 @@
-// RUN: %clang_cc1 -finclude-default-header -triple dxil-pc-shadermodel6.3-library %s \
-// RUN: -emit-llvm -disable-llvm-passes -o - | FileCheck %s
-
-// CHECK-DAG: @[[CB:.+]] = external constant { float }
-
-cbuffer A {
- float a;
- // CHECK-DAG:@_ZL1b = internal global float 3.000000e+00, align 4
- static float b = 3;
- // CHECK:load float, ptr @[[CB]], align 4
- // CHECK:load float, ptr @_ZL1b, align 4
- float foo() { return a + b; }
-}
-
-float bar() {
- return foo();
-}
>From dee03ca52a009b3e71fe2c976aa59473a8d970cf Mon Sep 17 00:00:00 2001
From: Helena Kotas <hekotas at microsoft.com>
Date: Thu, 12 Dec 2024 12:35:48 -0800
Subject: [PATCH 2/4] couple of commas to improve readability
---
clang/lib/CodeGen/CGHLSLRuntime.cpp | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/clang/lib/CodeGen/CGHLSLRuntime.cpp b/clang/lib/CodeGen/CGHLSLRuntime.cpp
index 82fae11bc7bc37..cfa77ccd1054d6 100644
--- a/clang/lib/CodeGen/CGHLSLRuntime.cpp
+++ b/clang/lib/CodeGen/CGHLSLRuntime.cpp
@@ -60,8 +60,8 @@ void addDisableOptimizations(llvm::Module &M) {
M.addModuleFlag(llvm::Module::ModFlagBehavior::Override, Key, 1);
}
-// Creates the LLVM struct type representing the shape of the constant buffer
-// which will be included in the LLVM target type and calculates the memory
+// Creates the LLVM struct type representing the shape of the constant buffer,
+// which will be included in the LLVM target type, and calculates the memory
// layout and constant buffer layout offsets of each constant.
static void layoutBuffer(CGHLSLRuntime::Buffer &Buf, const DataLayout &DL) {
assert(!Buf.Constants.empty() &&
>From 7274d067aa82e178558521576df21041686b97c1 Mon Sep 17 00:00:00 2001
From: Helena Kotas <hekotas at microsoft.com>
Date: Thu, 19 Dec 2024 14:29:53 -0800
Subject: [PATCH 3/4] Move target type and cbuffer layout calculations to
DirectXTargetInfo
---
clang/lib/CodeGen/CGHLSLRuntime.cpp | 159 ++++++++----------
clang/lib/CodeGen/CGHLSLRuntime.h | 37 ++--
clang/lib/CodeGen/TargetInfo.h | 5 +-
clang/lib/CodeGen/Targets/DirectX.cpp | 127 +++++++++++++-
clang/lib/CodeGen/Targets/SPIR.cpp | 9 +-
clang/test/CodeGenHLSL/cbuffer.hlsl | 64 +++----
.../CodeGenHLSL/cbuffer_and_namespaces.hlsl | 32 ++--
.../CodeGenHLSL/cbuffer_with_packoffset.hlsl | 25 +--
...uffer_with_static_global_and_function.hlsl | 11 +-
9 files changed, 289 insertions(+), 180 deletions(-)
diff --git a/clang/lib/CodeGen/CGHLSLRuntime.cpp b/clang/lib/CodeGen/CGHLSLRuntime.cpp
index cfa77ccd1054d6..0c8a11c6885815 100644
--- a/clang/lib/CodeGen/CGHLSLRuntime.cpp
+++ b/clang/lib/CodeGen/CGHLSLRuntime.cpp
@@ -16,6 +16,7 @@
#include "CGDebugInfo.h"
#include "CodeGenModule.h"
#include "TargetInfo.h"
+#include "clang/AST/ASTContext.h"
#include "clang/AST/Decl.h"
#include "clang/Basic/TargetOptions.h"
#include "llvm/IR/GlobalVariable.h"
@@ -29,7 +30,6 @@
using namespace clang;
using namespace CodeGen;
-using namespace clang::hlsl;
using namespace llvm;
namespace {
@@ -60,97 +60,83 @@ void addDisableOptimizations(llvm::Module &M) {
M.addModuleFlag(llvm::Module::ModFlagBehavior::Override, Key, 1);
}
-// Creates the LLVM struct type representing the shape of the constant buffer,
-// which will be included in the LLVM target type, and calculates the memory
-// layout and constant buffer layout offsets of each constant.
-static void layoutBuffer(CGHLSLRuntime::Buffer &Buf, const DataLayout &DL) {
- assert(!Buf.Constants.empty() &&
- "empty constant buffer should not be created");
-
- std::vector<llvm::Type *> EltTys;
- unsigned MemOffset = 0, CBufOffset = 0, Size = 0;
-
- for (auto &C : Buf.Constants) {
- GlobalVariable *GV = C.GlobalVar;
- llvm::Type *Ty = GV->getValueType();
-
- assert(!Ty->isArrayTy() && !Ty->isStructTy() &&
- "arrays and structs in cbuffer are not yet implemened");
-
- // scalar type, vector or matrix
- EltTys.emplace_back(Ty);
- unsigned FieldSize = Ty->getScalarSizeInBits() / 8;
- if (Ty->isVectorTy())
- FieldSize *= cast<FixedVectorType>(Ty)->getNumElements();
- assert(FieldSize <= 16 && "field side larger than constant buffer row");
-
- // set memory layout offset (no padding)
- C.MemOffset = MemOffset;
- MemOffset += FieldSize;
-
- // calculate cbuffer layout offset or update total cbuffer size from
- // packoffset annotations
- if (Buf.HasPackoffset) {
- assert(C.CBufferOffset != UINT_MAX &&
- "cbuffer offset should have been set from packoffset attribute");
- unsigned OffsetAfterField = C.CBufferOffset + FieldSize;
- if (Size < OffsetAfterField)
- Size = OffsetAfterField;
- } else {
- // allign to the size of the field
- CBufOffset = llvm::alignTo(CBufOffset, FieldSize);
- C.CBufferOffset = CBufOffset;
- CBufOffset += FieldSize;
- Size = CBufOffset;
- }
- }
- Buf.LayoutStruct = llvm::StructType::get(EltTys[0]->getContext(), EltTys);
- Buf.Size = Size;
-}
-
-// Creates LLVM target type target("dx.CBuffer",..) for the constant buffer.
-// The target type includes the LLVM struct type representing the shape
-// of the constant buffer, size, and a list of offsets for each fields
-// in cbuffer layout.
-static llvm::Type *getBufferTargetType(LLVMContext &Ctx,
- CGHLSLRuntime::Buffer &Buf) {
- assert(Buf.LayoutStruct != nullptr && Buf.Size != UINT_MAX &&
- "the buffer layout has not been calculated yet");
- llvm::SmallVector<unsigned> SizeAndOffsets;
- SizeAndOffsets.reserve(Buf.Constants.size() + 1);
- SizeAndOffsets.push_back(Buf.Size);
- for (CGHLSLRuntime::BufferConstant &C : Buf.Constants) {
- SizeAndOffsets.push_back(C.CBufferOffset);
+// Creates resource handle representing the constant buffer.
+// For cbuffer declaration:
+//
+// cbuffer MyConstants {
+// float a;
+// }
+//
+// creates a structure type MyConstants and then returns the resource handle
+// that would be spelled as:
+//
+// __hlsl_resource_t [[hlsl::resource_class(CBuffer)]]
+// [[contained_type(MyConstants)]]
+//
+static const clang::Type *getBufferHandleType(CGHLSLRuntime::Buffer &Buf) {
+ HLSLBufferDecl *BD = Buf.Decl;
+ ASTContext &AST = BD->getASTContext();
+
+ // create struct type for the constant buffer; filter out any declarations
+ // that are not a VarDecls or that are static
+ CXXRecordDecl *StructDecl = CXXRecordDecl::Create(
+ BD->getASTContext(), TagDecl::TagKind::Class, BD->getDeclContext(),
+ BD->getLocation(), BD->getLocation(), BD->getIdentifier());
+ StructDecl->startDefinition();
+ for (Decl *it : Buf.Decl->decls()) {
+ const VarDecl *VD = dyn_cast<VarDecl>(it);
+ if (!VD || VD->getStorageClass() == SC_Static)
+ continue;
+ auto *Field = FieldDecl::Create(
+ AST, StructDecl, VD->getLocation(), VD->getLocation(),
+ VD->getIdentifier(), VD->getType(), VD->getTypeSourceInfo(), nullptr,
+ false, InClassInitStyle::ICIS_NoInit);
+ Field->setAccess(AccessSpecifier::AS_private);
+ StructDecl->addDecl(Field);
}
- return llvm::TargetExtType::get(Ctx, "dx.CBuffer", {Buf.LayoutStruct},
- SizeAndOffsets);
+ StructDecl->completeDefinition();
+ assert(!StructDecl->fields().empty() && "empty cbuffer should not get here");
+
+ // create the resource handle type
+ HLSLAttributedResourceType::Attributes ResAttrs(dxil::ResourceClass::CBuffer,
+ false, false);
+ QualType ContainedTy = QualType(StructDecl->getTypeForDecl(), 0);
+ return AST
+ .getHLSLAttributedResourceType(AST.HLSLResourceTy, ContainedTy, ResAttrs)
+ .getTypePtr();
}
// Replaces all uses of the temporary constant buffer global variables with
-// buffer access intrinsic resource.getpointer.
+// buffer access intrinsic resource.getpointer and GEP.
static void replaceBufferGlobals(CodeGenModule &CGM,
CGHLSLRuntime::Buffer &Buf) {
assert(Buf.IsCBuffer && "tbuffer codegen is not yet supported");
GlobalVariable *BufGV = Buf.GlobalVar;
- for (auto &Constant : Buf.Constants) {
- GlobalVariable *ConstGV = Constant.GlobalVar;
+ llvm::Type *TargetTy = BufGV->getValueType();
+ llvm::Type *BufStructTy = cast<TargetExtType>(TargetTy)->getTypeParameter(0);
+ unsigned Index = 0;
+ for (auto ConstIt = Buf.Constants.begin(); ConstIt != Buf.Constants.end();
+ ++ConstIt, ++Index) {
+ GlobalVariable *ConstGV = *ConstIt;
// TODO: Map to an hlsl_device address space.
llvm::Type *RetTy = ConstGV->getType();
- llvm::Type *TargetTy = BufGV->getValueType();
// Replace all uses of GV with CBuffer access
while (ConstGV->use_begin() != ConstGV->use_end()) {
Use &U = *ConstGV->use_begin();
if (Instruction *UserInstr = dyn_cast<Instruction>(U.getUser())) {
IRBuilder<> Builder(UserInstr);
+ Value *Zero = Builder.getInt32(0);
Value *Handle = Builder.CreateLoad(TargetTy, BufGV);
- Value *ResGetPointer = Builder.CreateIntrinsic(
- RetTy, Intrinsic::dx_resource_getpointer,
- ArrayRef<llvm::Value *>{Handle,
- Builder.getInt32(Constant.MemOffset)});
- U.set(ResGetPointer);
+ Value *ResGetPointer =
+ Builder.CreateIntrinsic(RetTy, Intrinsic::dx_resource_getpointer,
+ ArrayRef<llvm::Value *>{Handle, Zero});
+ Value *GEP = Builder.CreateGEP(BufStructTy, ResGetPointer,
+ {Zero, Builder.getInt32(Index)},
+ ConstGV->getName());
+ U.set(GEP);
} else {
llvm_unreachable("unexpected use of constant value");
}
@@ -162,11 +148,14 @@ static void replaceBufferGlobals(CodeGenModule &CGM,
} // namespace
-llvm::Type *CGHLSLRuntime::convertHLSLSpecificType(const Type *T) {
+llvm::Type *
+CGHLSLRuntime::convertHLSLSpecificType(const Type *T,
+ const HLSLBufferDecl *BufferDecl) {
assert(T->isHLSLSpecificType() && "Not an HLSL specific type!");
// Check if the target has a specific translation for this type first.
- if (llvm::Type *TargetTy = CGM.getTargetCodeGenInfo().getHLSLType(CGM, T))
+ if (llvm::Type *TargetTy =
+ CGM.getTargetCodeGenInfo().getHLSLType(CGM, T, BufferDecl))
return TargetTy;
llvm_unreachable("Generic handling of HLSL types is not supported.");
@@ -196,10 +185,8 @@ void CGHLSLRuntime::addConstant(VarDecl *D, Buffer &CB) {
CB.Constants.emplace_back(GV);
- if (HLSLPackOffsetAttr *PO = D->getAttr<HLSLPackOffsetAttr>()) {
+ if (HLSLPackOffsetAttr *PO = D->getAttr<HLSLPackOffsetAttr>())
CB.HasPackoffset = true;
- CB.Constants.back().CBufferOffset = PO->getOffsetInBytes();
- }
}
void CGHLSLRuntime::addBufferDecls(const DeclContext *DC, Buffer &CB) {
@@ -217,15 +204,14 @@ void CGHLSLRuntime::addBufferDecls(const DeclContext *DC, Buffer &CB) {
}
// Creates temporary global variables for all declarations within the constant
-// buffer context, calculates the buffer layouts, and then creates a global
-// variable for the constant buffer and adds it to the module.
+// buffer context, creates a global variable for the constant buffer and adds
+// it to the module.
// All uses of the temporary constant globals will be replaced with buffer
// access intrinsic resource.getpointer in CGHLSLRuntime::finishCodeGen.
// Later on in DXILResourceAccess pass these will be transtaled
// to dx.op.cbufferLoadLegacy instructions.
-void CGHLSLRuntime::addBuffer(const HLSLBufferDecl *D) {
+void CGHLSLRuntime::addBuffer(HLSLBufferDecl *D) {
llvm::Module &M = CGM.getModule();
- const DataLayout &DL = M.getDataLayout();
assert(D->isCBuffer() && "tbuffer codegen is not supported yet");
@@ -236,10 +222,9 @@ void CGHLSLRuntime::addBuffer(const HLSLBufferDecl *D) {
Buffers.pop_back();
return;
}
- layoutBuffer(Buf, DL);
-
// Create global variable for CB.
- llvm::Type *TargetTy = getBufferTargetType(CGM.getLLVMContext(), Buf);
+ llvm::Type *TargetTy = convertHLSLSpecificType(
+ getBufferHandleType(Buf), Buf.HasPackoffset ? Buf.Decl : nullptr);
Buf.GlobalVar = new GlobalVariable(
TargetTy, /*isConstant*/ true, GlobalValue::LinkageTypes::ExternalLinkage,
nullptr, llvm::formatv("{0}{1}", Buf.Name, Buf.IsCBuffer ? ".cb" : ".tb"),
@@ -265,9 +250,9 @@ void CGHLSLRuntime::finishCodeGen() {
}
}
-CGHLSLRuntime::Buffer::Buffer(const HLSLBufferDecl *D)
+CGHLSLRuntime::Buffer::Buffer(HLSLBufferDecl *D)
: Name(D->getName()), IsCBuffer(D->isCBuffer()), HasPackoffset(false),
- LayoutStruct(nullptr), Decl(D), GlobalVar(nullptr) {}
+ Decl(D), GlobalVar(nullptr) {}
void CGHLSLRuntime::addBufferResourceAnnotation(llvm::GlobalVariable *GV,
llvm::hlsl::ResourceClass RC,
diff --git a/clang/lib/CodeGen/CGHLSLRuntime.h b/clang/lib/CodeGen/CGHLSLRuntime.h
index 9c3bbf5bbfe190..6e5d26a93b253b 100644
--- a/clang/lib/CodeGen/CGHLSLRuntime.h
+++ b/clang/lib/CodeGen/CGHLSLRuntime.h
@@ -18,15 +18,13 @@
#include "llvm/IR/GlobalVariable.h"
#include "llvm/IR/IRBuilder.h"
#include "llvm/IR/Intrinsics.h"
-#include "llvm/IR/IntrinsicsDirectX.h"
-#include "llvm/IR/IntrinsicsSPIRV.h"
-
-#include "clang/Basic/Builtins.h"
-#include "clang/Basic/HLSLRuntime.h"
#include "llvm/ADT/SmallVector.h"
#include "llvm/ADT/StringRef.h"
#include "llvm/Frontend/HLSL/HLSLResource.h"
+#include "llvm/IR/IntrinsicsDirectX.h"
+#include "llvm/IR/IntrinsicsSPIRV.h"
+#include "llvm/TargetParser/Triple.h"
#include <optional>
#include <vector>
@@ -122,35 +120,20 @@ class CGHLSLRuntime {
BufferResBinding(HLSLResourceBindingAttr *Attr);
};
- struct BufferConstant {
- llvm::GlobalVariable *GlobalVar;
- // offset in memory layout (in bytes)
- unsigned MemOffset;
- // offset in cbuffer layout (in bytes)
- unsigned CBufferOffset;
-
- BufferConstant(llvm::GlobalVariable *GV)
- : GlobalVar(GV), MemOffset(UINT_MAX), CBufferOffset(UINT_MAX) {}
- };
-
struct Buffer {
llvm::StringRef Name;
// Whether the buffer is a cbuffer (and not a tbuffer).
bool IsCBuffer;
// Whether the buffer has packoffset annotations
bool HasPackoffset;
- // List of global constants with memory and cbuffer layout ofsets
- std::vector<BufferConstant> Constants;
- // LLVM layout type
- llvm::StructType *LayoutStruct;
- // size of the buffer in cbuffer layout
- unsigned Size;
+ // List of global constants
+ std::vector<llvm::GlobalVariable *> Constants;
// reference to the AST Decl node with resource binding attribute
- const HLSLBufferDecl *Decl;
+ HLSLBufferDecl *Decl;
// global variable for the constant buffer
llvm::GlobalVariable *GlobalVar;
- Buffer(const HLSLBufferDecl *D);
+ Buffer(HLSLBufferDecl *D);
};
protected:
@@ -163,12 +146,14 @@ class CGHLSLRuntime {
CGHLSLRuntime(CodeGenModule &CGM) : CGM(CGM) {}
virtual ~CGHLSLRuntime() {}
- llvm::Type *convertHLSLSpecificType(const Type *T);
+ llvm::Type *
+ convertHLSLSpecificType(const Type *T,
+ const HLSLBufferDecl *BufferDecl = nullptr);
void annotateHLSLResource(const VarDecl *D, llvm::GlobalVariable *GV);
void generateGlobalCtorDtorCalls();
- void addBuffer(const HLSLBufferDecl *D);
+ void addBuffer(HLSLBufferDecl *D);
void finishCodeGen();
void setHLSLEntryAttributes(const FunctionDecl *FD, llvm::Function *Fn);
diff --git a/clang/lib/CodeGen/TargetInfo.h b/clang/lib/CodeGen/TargetInfo.h
index ab3142bdea684e..28c511249c1630 100644
--- a/clang/lib/CodeGen/TargetInfo.h
+++ b/clang/lib/CodeGen/TargetInfo.h
@@ -33,6 +33,7 @@ class Value;
namespace clang {
class Decl;
+class HLSLBufferDecl;
namespace CodeGen {
class ABIInfo;
@@ -439,7 +440,9 @@ class TargetCodeGenInfo {
}
/// Return an LLVM type that corresponds to a HLSL type
- virtual llvm::Type *getHLSLType(CodeGenModule &CGM, const Type *T) const {
+ virtual llvm::Type *
+ getHLSLType(CodeGenModule &CGM, const Type *T,
+ const HLSLBufferDecl *BufDecl = nullptr) const {
return nullptr;
}
diff --git a/clang/lib/CodeGen/Targets/DirectX.cpp b/clang/lib/CodeGen/Targets/DirectX.cpp
index 7935f7ae370047..e5d36cd0ba3478 100644
--- a/clang/lib/CodeGen/Targets/DirectX.cpp
+++ b/clang/lib/CodeGen/Targets/DirectX.cpp
@@ -8,6 +8,8 @@
#include "ABIInfoImpl.h"
#include "TargetInfo.h"
+#include "clang/AST/Attrs.inc"
+#include "clang/AST/Decl.h"
#include "llvm/IR/DerivedTypes.h"
using namespace clang;
@@ -24,11 +26,116 @@ class DirectXTargetCodeGenInfo : public TargetCodeGenInfo {
DirectXTargetCodeGenInfo(CodeGen::CodeGenTypes &CGT)
: TargetCodeGenInfo(std::make_unique<DefaultABIInfo>(CGT)) {}
- llvm::Type *getHLSLType(CodeGenModule &CGM, const Type *T) const override;
+ llvm::Type *
+ getHLSLType(CodeGenModule &CGM, const Type *T,
+ const HLSLBufferDecl *BufDecl = nullptr) const override;
};
-llvm::Type *DirectXTargetCodeGenInfo::getHLSLType(CodeGenModule &CGM,
- const Type *Ty) const {
+static bool hasPackoffset(const HLSLBufferDecl *BufferDecl) {
+ // If one valid constant buffer declaration has a packoffset annotation
+ // then they all need to have them.
+ for (auto *D : BufferDecl->decls())
+ if (VarDecl *VD = dyn_cast<VarDecl>(D))
+ if (VD->getStorageClass() != SC_Static)
+ return VD->hasAttr<HLSLPackOffsetAttr>();
+ return false;
+}
+
+// Fills in the Layout based on the constant buffer packoffset annotations
+// found in the HLSLBufferDecl instance.
+// The first item in the Layout vector will be set to the size of the buffer,
+// which is the highest packoffset value + size of its field.
+// After the size there will be a list of offsets (in bytes) for each field.
+// This layout encoding will be used in the LLVM target type
+// for constant buffers target("dx.CBuffer",..).
+static void createConstantBufferLayoutFromPackoffset(
+ CodeGenModule &CGM, llvm::Type *BufferTy, SmallVector<unsigned> &Layout,
+ const HLSLBufferDecl *BufferDecl) {
+ assert(BufferDecl && hasPackoffset(BufferDecl) &&
+ "expected non-null buffer declaration with packoffset attributes on "
+ "its fields");
+ assert(isa<llvm::StructType>(BufferTy) && "expected struct");
+
+ // total buffer size - equals to the highest packoffset value plus the size of
+ // its element
+ unsigned Size = 0;
+ // reserve the first spot in the layout vector for the buffer size
+ Layout.push_back(UINT_MAX);
+
+ auto DeclIt = BufferDecl->decls_begin();
+ for (llvm::Type *Ty : cast<llvm::StructType>(BufferTy)->elements()) {
+ assert(!Ty->isArrayTy() && !Ty->isStructTy() &&
+ "arrays and structs in cbuffer are not yet implemened");
+
+ VarDecl *VD = nullptr;
+ // ignore any declaration that is not var decls or that is static
+ while (DeclIt != BufferDecl->decls_end()) {
+ VD = llvm::dyn_cast<VarDecl>(*DeclIt);
+ DeclIt++;
+ if (VD && VD->getStorageClass() != SC_Static)
+ break;
+ }
+ assert(VD && "number of declaration in constant buffer does not match "
+ "number of element in buffer struct");
+ assert(CGM.getTypes().ConvertType(VD->getType()) == Ty &&
+ "constant types do not match");
+
+ HLSLPackOffsetAttr *POAttr = VD->getAttr<HLSLPackOffsetAttr>();
+ assert(POAttr && "expected packoffset attribute on every declaration");
+
+ unsigned Offset = POAttr->getOffsetInBytes();
+ Layout.push_back(Offset);
+
+ unsigned FieldSize = Ty->getScalarSizeInBits() / 8;
+ if (Offset + FieldSize > Size)
+ Size = Offset + FieldSize;
+ }
+ Layout[0] = Size;
+}
+
+// Calculated constant buffer layout. The first item in the Layout
+// vector will be set to the size of the buffer followed by the offsets
+// (in bytes) for each field.
+// This layout encoding will be used in the LLVM target type
+// for constant buffers target("dx.CBuffer",..).
+static void
+calculateConstantBufferLayout(CodeGenModule &CGM, llvm::Type *BufferTy,
+ SmallVector<unsigned> &Layout,
+ const HLSLBufferDecl *BufferDecl = nullptr) {
+ assert(isa<llvm::StructType>(BufferTy) && "expected struct");
+ assert(BufferTy->getStructNumElements() != 0 &&
+ "empty constant buffer should not be created");
+
+ if (BufferDecl && hasPackoffset(BufferDecl)) {
+ createConstantBufferLayoutFromPackoffset(CGM, BufferTy, Layout, BufferDecl);
+ return;
+ }
+
+ unsigned CBufOffset = 0, Size = 0;
+ Layout.push_back(UINT_MAX); // reserve first spot for the buffer size
+
+ for (const llvm::Type *ElTy : cast<llvm::StructType>(BufferTy)->elements()) {
+ assert(!ElTy->isArrayTy() && !ElTy->isStructTy() &&
+ "arrays and structs in cbuffer are not yet implemened");
+
+ // scalar type, vector or matrix
+ unsigned FieldSize = ElTy->getScalarSizeInBits() / 8;
+ if (ElTy->isVectorTy())
+ FieldSize *= cast<llvm::FixedVectorType>(ElTy)->getNumElements();
+ assert(FieldSize <= 16 && "field side larger than constant buffer row");
+
+ // align to the size of the field
+ CBufOffset = llvm::alignTo(CBufOffset, FieldSize);
+ Layout.push_back(CBufOffset);
+ CBufOffset += FieldSize;
+ Size = CBufOffset;
+ }
+ Layout[0] = Size;
+}
+
+llvm::Type *
+DirectXTargetCodeGenInfo::getHLSLType(CodeGenModule &CGM, const Type *Ty,
+ const HLSLBufferDecl *BufDecl) const {
auto *ResType = dyn_cast<HLSLAttributedResourceType>(Ty);
if (!ResType)
return nullptr;
@@ -56,9 +163,17 @@ llvm::Type *DirectXTargetCodeGenInfo::getHLSLType(CodeGenModule &CGM,
return llvm::TargetExtType::get(Ctx, TypeName, {ElemType}, Ints);
}
- case llvm::dxil::ResourceClass::CBuffer:
- llvm_unreachable("dx.CBuffer handles are not implemented yet");
- break;
+ case llvm::dxil::ResourceClass::CBuffer: {
+ QualType StructTy = ResType->getContainedType();
+ if (StructTy.isNull())
+ return nullptr;
+
+ llvm::Type *Ty = CGM.getTypes().ConvertType(StructTy);
+
+ SmallVector<unsigned> BufferLayout;
+ calculateConstantBufferLayout(CGM, Ty, BufferLayout, BufDecl);
+ return llvm::TargetExtType::get(Ctx, "dx.CBuffer", {Ty}, BufferLayout);
+ }
case llvm::dxil::ResourceClass::Sampler:
llvm_unreachable("dx.Sampler handles are not implemented yet");
break;
diff --git a/clang/lib/CodeGen/Targets/SPIR.cpp b/clang/lib/CodeGen/Targets/SPIR.cpp
index a48fe9d5f1ee9c..d3b0e8874b56ad 100644
--- a/clang/lib/CodeGen/Targets/SPIR.cpp
+++ b/clang/lib/CodeGen/Targets/SPIR.cpp
@@ -52,7 +52,9 @@ class CommonSPIRTargetCodeGenInfo : public TargetCodeGenInfo {
unsigned getOpenCLKernelCallingConv() const override;
llvm::Type *getOpenCLType(CodeGenModule &CGM, const Type *T) const override;
- llvm::Type *getHLSLType(CodeGenModule &CGM, const Type *Ty) const override;
+ llvm::Type *
+ getHLSLType(CodeGenModule &CGM, const Type *T,
+ const HLSLBufferDecl *BufDecl = nullptr) const override;
llvm::Type *getSPIRVImageTypeFromHLSLResource(
const HLSLAttributedResourceType::Attributes &attributes,
llvm::Type *ElementType, llvm::LLVMContext &Ctx) const;
@@ -327,8 +329,9 @@ llvm::Type *CommonSPIRTargetCodeGenInfo::getOpenCLType(CodeGenModule &CGM,
return nullptr;
}
-llvm::Type *CommonSPIRTargetCodeGenInfo::getHLSLType(CodeGenModule &CGM,
- const Type *Ty) const {
+llvm::Type *
+CommonSPIRTargetCodeGenInfo::getHLSLType(CodeGenModule &CGM, const Type *Ty,
+ const HLSLBufferDecl *BufDecl) const {
auto *ResType = dyn_cast<HLSLAttributedResourceType>(Ty);
if (!ResType)
return nullptr;
diff --git a/clang/test/CodeGenHLSL/cbuffer.hlsl b/clang/test/CodeGenHLSL/cbuffer.hlsl
index 4d6b55157f30a5..77d408c9251cc3 100644
--- a/clang/test/CodeGenHLSL/cbuffer.hlsl
+++ b/clang/test/CodeGenHLSL/cbuffer.hlsl
@@ -2,14 +2,17 @@
// RUN: dxil-pc-shadermodel6.3-compute %s \
// RUN: -emit-llvm -disable-llvm-passes -o - | FileCheck %s
-// CHECK: @CB1.cb = external constant target("dx.CBuffer", { float, double }, 16, 0, 8)
-cbuffer CB1 : register(b0, space2) {
+// CHECK: %class.CB = type { float, double }
+// CHECK: %class.ParticleLife = type { i32, i32, <2 x float>, float, float }
+
+// CHECK: @CB.cb = external constant target("dx.CBuffer", %class.CB, 16, 0, 8)
+cbuffer CB : register(b0, space2) {
float a;
double b;
}
-// CHECK: @ParticleLifeCB.cb = external constant target("dx.CBuffer", { i32, i32, <2 x float>, float, float }, 24, 0, 4, 8, 16, 20)
-cbuffer ParticleLifeCB : register(b2, space1) {
+// CHECK: @ParticleLife.cb = external constant target("dx.CBuffer", %class.ParticleLife, 24, 0, 4, 8, 16, 20)
+cbuffer ParticleLife : register(b2, space1) {
uint ParticleTypeMax;
uint NumParticles;
float2 WorldSize;
@@ -18,28 +21,31 @@ cbuffer ParticleLifeCB : register(b2, space1) {
}
float foo() {
-// CHECK: %[[HANDLE1:[0-9]+]] = load target("dx.CBuffer", { float, double }, 16, 0, 8), ptr @CB1.cb, align 4
-// CHECK: %[[PTR1:[0-9]+]] = call ptr @llvm.dx.resource.getpointer.p0.tdx.CBuffer_sl_f32f64s_16_0_8t(target("dx.CBuffer", { float, double }, 16, 0, 8) %[[HANDLE1]], i32 0)
-// CHECK: load float, ptr %[[PTR1]], align 4
+// CHECK: %[[HANDLE1:[0-9]+]] = load target("dx.CBuffer", %class.CB, 16, 0, 8), ptr @CB.cb, align 4
+// CHECK: %[[PTR1:[0-9]+]] = call ptr @llvm.dx.resource.getpointer.p0.tdx.CBuffer_s_class.CBs_16_0_8t(target("dx.CBuffer", %class.CB, 16, 0, 8) %[[HANDLE1]], i32 0)
+// CHECK: %a = getelementptr %class.CB, ptr %[[PTR1]], i32 0, i32 0
+// CHECK: load float, ptr %a, align 4
-// CHECK: %[[HANDLE2:[0-9]+]] = load target("dx.CBuffer", { float, double }, 16, 0, 8), ptr @CB1.cb, align 4
-// CHECK: %[[PTR2:[0-9]+]] = call ptr @llvm.dx.resource.getpointer.p0.tdx.CBuffer_sl_f32f64s_16_0_8t(target("dx.CBuffer", { float, double }, 16, 0, 8) %[[HANDLE2]], i32 4)
-// CHECK: load double, ptr %[[PTR2]], align 8
+// CHECK: %[[HANDLE2:[0-9]+]] = load target("dx.CBuffer", %class.CB, 16, 0, 8), ptr @CB.cb, align 4
+// CHECK: %[[PTR2:[0-9]+]] = call ptr @llvm.dx.resource.getpointer.p0.tdx.CBuffer_s_class.CBs_16_0_8t(target("dx.CBuffer", %class.CB, 16, 0, 8) %[[HANDLE2]], i32 0)
+// CHECK: %b = getelementptr %class.CB, ptr %[[PTR2]], i32 0, i32 1
+// CHECK: load double, ptr %b, align 8
-// CHECK: %[[HANDLE3:[0-9]+]] = load target("dx.CBuffer", { i32, i32, <2 x float>, float, float }, 24, 0, 4, 8, 16, 20), ptr @ParticleLifeCB.cb, align 4
-// CHECK: %[[PTR3:[0-9]+]] = call ptr @llvm.dx.resource.getpointer.p0.tdx.CBuffer_sl_i32i32v2f32f32f32s_24_0_4_8_16_20t(
-// CHECK-SAME: target("dx.CBuffer", { i32, i32, <2 x float>, float, float }, 24, 0, 4, 8, 16, 20) %[[HANDLE3]], i32 0)
-// CHECK: load i32, ptr %[[PTR3]], align 4
-
-// CHECK: %[[HANDLE4:[0-9]+]] = load target("dx.CBuffer", { i32, i32, <2 x float>, float, float }, 24, 0, 4, 8, 16, 20), ptr @ParticleLifeCB.cb, align 4
-// CHECK: %[[PTR4:[0-9]+]] = call ptr @llvm.dx.resource.getpointer.p0.tdx.CBuffer_sl_i32i32v2f32f32f32s_24_0_4_8_16_20t(
-// CHECK-SAME: target("dx.CBuffer", { i32, i32, <2 x float>, float, float }, 24, 0, 4, 8, 16, 20) %[[HANDLE4]], i32 8)
-// CHECK: load <2 x float>, ptr %[[PTR4]], align 8
+// CHECK: %[[HANDLE3:[0-9]+]] = load target("dx.CBuffer", %class.ParticleLife, 24, 0, 4, 8, 16, 20), ptr @ParticleLife.cb, align 4
+// CHECK: %[[PTR3:[0-9]+]] = call ptr @llvm.dx.resource.getpointer.p0.tdx.CBuffer_s_class.ParticleLifes_24_0_4_8_16_20t(target("dx.CBuffer", %class.ParticleLife, 24, 0, 4, 8, 16, 20) %[[HANDLE3]], i32 0)
+// CHECK: %ParticleTypeMax = getelementptr %class.ParticleLife, ptr %[[PTR3]], i32 0, i32 0
+// CHECK: load i32, ptr %ParticleTypeMax, align 4
-// CHECK: %[[HANDLE5:[0-9]+]] = load target("dx.CBuffer", { i32, i32, <2 x float>, float, float }, 24, 0, 4, 8, 16, 20), ptr @ParticleLifeCB.cb, align 4
-// CHECK: %[[PTR5:[0-9]+]] = call ptr @llvm.dx.resource.getpointer.p0.tdx.CBuffer_sl_i32i32v2f32f32f32s_24_0_4_8_16_20t(
-// CHECK-SAME: target("dx.CBuffer", { i32, i32, <2 x float>, float, float }, 24, 0, 4, 8, 16, 20) %[[HANDLE5]], i32 20)
-// CHECK: load float, ptr %[[PTR5]], align 4
+// CHECK: %[[HANDLE4:[0-9]+]] = load target("dx.CBuffer", %class.ParticleLife, 24, 0, 4, 8, 16, 20), ptr @ParticleLife.cb, align 4
+// CHECK: %[[PTR4:[0-9]+]] = call ptr @llvm.dx.resource.getpointer.p0.tdx.CBuffer_s_class.ParticleLifes_24_0_4_8_16_20t(target("dx.CBuffer", %class.ParticleLife, 24, 0, 4, 8, 16, 20) %[[HANDLE4]], i32 0)
+// CHECK: %WorldSize = getelementptr %class.ParticleLife, ptr %[[PTR4]], i32 0, i32 2
+// CHECK: %[[VEC:[0-9]+]] = load <2 x float>, ptr %WorldSize, align 8
+// CHECK: extractelement <2 x float> %[[VEC]], i32 1
+
+// CHECK: %[[HANDLE5:[0-9]+]] = load target("dx.CBuffer", %class.ParticleLife, 24, 0, 4, 8, 16, 20), ptr @ParticleLife.cb, align 4
+// CHECK: %[[PTR5:[0-9]+]] = call ptr @llvm.dx.resource.getpointer.p0.tdx.CBuffer_s_class.ParticleLifes_24_0_4_8_16_20t(target("dx.CBuffer", %class.ParticleLife, 24, 0, 4, 8, 16, 20) %[[HANDLE5]], i32 0)
+// CHECK: %ForceMultipler = getelementptr %class.ParticleLife, ptr %[[PTR5]], i32 0, i32 4
+// CHECK: %15 = load float, ptr %ForceMultipler, align 4
return a + b + ParticleTypeMax + WorldSize.y * ForceMultipler;
}
@@ -51,12 +57,12 @@ float foo() {
// CHECK: define internal void @_init_resource_bindings() {
// CHECK-NEXT: entry:
-// CHECK-NEXT: %CB1_h = call target("dx.CBuffer", { float, double }, 16, 0, 8)
-// CHECK-SAME: @llvm.dx.handle.fromBinding.tdx.CBuffer_sl_f32f64s_16_0_8t(i32 2, i32 0, i32 1, i32 0, i1 false)
-// CHECK-NEXT: store target("dx.CBuffer", { float, double }, 16, 0, 8) %CB1_h, ptr @CB1.cb, align 4
-// CHECK-NEXT: %ParticleLifeCB_h = call target("dx.CBuffer", { i32, i32, <2 x float>, float, float }, 24, 0, 4, 8, 16, 20)
-// CHECK-SAME: @llvm.dx.handle.fromBinding.tdx.CBuffer_sl_i32i32v2f32f32f32s_24_0_4_8_16_20t(i32 1, i32 2, i32 1, i32 0, i1 false)
-// CHECK-NEXT: store target("dx.CBuffer", { i32, i32, <2 x float>, float, float }, 24, 0, 4, 8, 16, 20) %ParticleLifeCB_h, ptr @ParticleLifeCB.cb, align 4
+// CHECK-NEXT: %CB_h = call target("dx.CBuffer", %class.CB, 16, 0, 8)
+// CHECK-SAME: @llvm.dx.handle.fromBinding.tdx.CBuffer_s_class.CBs_16_0_8t(i32 2, i32 0, i32 1, i32 0, i1 false)
+// CHECK-NEXT: store target("dx.CBuffer", %class.CB, 16, 0, 8) %CB_h, ptr @CB.cb, align 4
+// CHECK-NEXT: %ParticleLife_h = call target("dx.CBuffer", %class.ParticleLife, 24, 0, 4, 8, 16, 20)
+// CHECK-SAME: @llvm.dx.handle.fromBinding.tdx.CBuffer_s_class.ParticleLifes_24_0_4_8_16_20t(i32 1, i32 2, i32 1, i32 0, i1 false)
+// CHECK-NEXT: store target("dx.CBuffer", %class.ParticleLife, 24, 0, 4, 8, 16, 20) %ParticleLife_h, ptr @ParticleLife.cb, align 4
// CHECK: define internal void @_GLOBAL__sub_I_cbuffer.hlsl()
// CHECK-NEXT: entry:
diff --git a/clang/test/CodeGenHLSL/cbuffer_and_namespaces.hlsl b/clang/test/CodeGenHLSL/cbuffer_and_namespaces.hlsl
index 860716ad3e582a..0c2592e32df51d 100644
--- a/clang/test/CodeGenHLSL/cbuffer_and_namespaces.hlsl
+++ b/clang/test/CodeGenHLSL/cbuffer_and_namespaces.hlsl
@@ -3,9 +3,14 @@
// RUN: -emit-llvm -disable-llvm-passes -o - | FileCheck %s
// Make sure cbuffer inside namespace works.
-// CHECK: @A.cb = external constant target("dx.CBuffer", { float }, 4, 0)
-// CHECK: @B.cb = external constant target("dx.CBuffer", { float }, 4, 0)
-// CHECK: @C.cb = external constant target("dx.CBuffer", { float }, 4, 0)
+
+// CHECK: %"class.n0::n1::A" = type { float }
+// CHECK: %"class.n0::B" = type { float }
+// CHECK: %"class.n0::n2::C" = type { float }
+
+// CHECK: @A.cb = external constant target("dx.CBuffer", %"class.n0::n1::A", 4, 0)
+// CHECK: @B.cb = external constant target("dx.CBuffer", %"class.n0::B", 4, 0)
+// CHECK: @C.cb = external constant target("dx.CBuffer", %"class.n0::n2::C", 4, 0)
namespace n0 {
namespace n1 {
@@ -24,19 +29,22 @@ namespace n0 {
}
float foo() {
-// CHECK: %[[HANDLE1:[0-9]+]] = load target("dx.CBuffer", { float }, 4, 0), ptr @A.cb, align 4
-// CHECK: %[[PTR1:[0-9]+]] = call ptr @llvm.dx.resource.getpointer.p0.tdx.CBuffer_sl_f32s_4_0t(target("dx.CBuffer", { float }, 4, 0) %[[HANDLE1]], i32 0)
-// CHECK: %[[VAL1:[0-9]+]] = load float, ptr %[[PTR1]], align 4
+// CHECK: %[[HANDLE1:[0-9]+]] = load target("dx.CBuffer", %"class.n0::n1::A", 4, 0), ptr @A.cb, align 4
+// CHECK: %[[PTR1:[0-9]+]] = call ptr @"llvm.dx.resource.getpointer.p0.tdx.CBuffer_s_class.n0::n1::As_4_0t"(target("dx.CBuffer", %"class.n0::n1::A", 4, 0) %[[HANDLE1]], i32 0)
+// CHECK: %_ZN2n02n11aE = getelementptr %"class.n0::n1::A", ptr %[[PTR1]], i32 0, i32 0
+// CHECK: %[[VAL1:[0-9]+]] = load float, ptr %_ZN2n02n11aE, align 4
-// CHECK: %[[HANDLE2:[0-9]+]] = load target("dx.CBuffer", { float }, 4, 0), ptr @B.cb, align 4
-// CHECK: %[[PTR2:[0-9]+]] = call ptr @llvm.dx.resource.getpointer.p0.tdx.CBuffer_sl_f32s_4_0t(target("dx.CBuffer", { float }, 4, 0) %[[HANDLE2]], i32 0)
-// CHECK: %[[VAL2:[0-9]+]] = load float, ptr %[[PTR2]], align 4
+// CHECK: %[[HANDLE2:[0-9]+]] = load target("dx.CBuffer", %"class.n0::B", 4, 0), ptr @B.cb, align 4
+// CHECK: %[[PTR2:[0-9]+]] = call ptr @"llvm.dx.resource.getpointer.p0.tdx.CBuffer_s_class.n0::Bs_4_0t"(target("dx.CBuffer", %"class.n0::B", 4, 0) %[[HANDLE2]], i32 0)
+// CHECK: %_ZN2n01aE = getelementptr %"class.n0::B", ptr %[[PTR2]], i32 0, i32 0
+// CHECK: %[[VAL2:[0-9]+]] = load float, ptr %_ZN2n01aE, align 4
// CHECK: %add = fadd float %[[VAL1]], %[[VAL2]]
-// CHECK: %[[HANDLE3:[0-9]+]] = load target("dx.CBuffer", { float }, 4, 0), ptr @C.cb, align 4
-// CHECK: %[[PTR3:[0-9]+]] = call ptr @llvm.dx.resource.getpointer.p0.tdx.CBuffer_sl_f32s_4_0t(target("dx.CBuffer", { float }, 4, 0) %[[HANDLE3]], i32 0)
-// CHECK: %[[VAL3:[0-9]+]] = load float, ptr %[[PTR3]], align 4
+// CHECK: %[[HANDLE3:[0-9]+]] = load target("dx.CBuffer", %"class.n0::n2::C", 4, 0), ptr @C.cb, align 4
+// CHECK: %[[PTR3:[0-9]+]] = call ptr @"llvm.dx.resource.getpointer.p0.tdx.CBuffer_s_class.n0::n2::Cs_4_0t"(target("dx.CBuffer", %"class.n0::n2::C", 4, 0) %[[HANDLE3]], i32 0)
+// CHECK: %_ZN2n02n21aE = getelementptr %"class.n0::n2::C", ptr %[[PTR3]], i32 0, i32 0
+// CHECK: %[[VAL3:[0-9]+]] = load float, ptr %_ZN2n02n21aE, align 4
// CHECK: %add1 = fadd float %add, %[[VAL3]]
diff --git a/clang/test/CodeGenHLSL/cbuffer_with_packoffset.hlsl b/clang/test/CodeGenHLSL/cbuffer_with_packoffset.hlsl
index 58891659179aed..b05c8c044ca4b5 100644
--- a/clang/test/CodeGenHLSL/cbuffer_with_packoffset.hlsl
+++ b/clang/test/CodeGenHLSL/cbuffer_with_packoffset.hlsl
@@ -2,30 +2,31 @@
// RUN: dxil-pc-shadermodel6.3-compute %s \
// RUN: -emit-llvm -disable-llvm-passes -o - | FileCheck %s
-// CHECK: @CB.cb = external constant target("dx.CBuffer", { float, double }, 176, 16, 168)
+// CHCEK: %class.CB = type { float, double }
+// CHECK: @CB.cb = external constant target("dx.CBuffer", %class.CB, 176, 16, 168)
cbuffer CB : register(b1, space3) {
float a : packoffset(c1.x);
double b : packoffset(c10.z);
}
float foo() {
-// CHECK: %[[HANDLE1:[0-9]+]] = load target("dx.CBuffer", { float, double }, 176, 16, 168), ptr @CB.cb, align 4
-// CHECK: %[[PTR1:[0-9]+]] = call ptr @llvm.dx.resource.getpointer.p0.tdx.CBuffer_sl_f32f64s_176_16_168t(
-// CHECK-SAME: target("dx.CBuffer", { float, double }, 176, 16, 168) %[[HANDLE1]], i32 0)
-// CHECK: load float, ptr %[[PTR1]], align 4
+// CHECK: %[[HANDLE1:[0-9]+]] = load target("dx.CBuffer", %class.CB, 176, 16, 168), ptr @CB.cb, align 4
+// CHECK: %[[PTR1:[0-9]+]] = call ptr @llvm.dx.resource.getpointer.p0.tdx.CBuffer_s_class.CBs_176_16_168t(target("dx.CBuffer", %class.CB, 176, 16, 168) %[[HANDLE1]], i32 0)
+// CHECK: %a = getelementptr %class.CB, ptr %[[PTR1]], i32 0, i32 0
+// CHECK: load float, ptr %a, align 4
-// CHECK: %[[HANDLE2:[0-9]+]] = load target("dx.CBuffer", { float, double }, 176, 16, 168), ptr @CB.cb, align 4
-// CHECK: %[[PTR2:[0-9]+]] = call ptr @llvm.dx.resource.getpointer.p0.tdx.CBuffer_sl_f32f64s_176_16_168t(
-// CHECK-SAME: target("dx.CBuffer", { float, double }, 176, 16, 168) %[[HANDLE2]], i32 4)
-// CHECK: load double, ptr %[[PTR2]], align 8
+// CHECK: %[[HANDLE2:[0-9]+]] = load target("dx.CBuffer", %class.CB, 176, 16, 168), ptr @CB.cb, align 4
+// CHECK: %[[PTR2:[0-9]+]] = call ptr @llvm.dx.resource.getpointer.p0.tdx.CBuffer_s_class.CBs_176_16_168t(target("dx.CBuffer", %class.CB, 176, 16, 168) %[[HANDLE2]], i32 0)
+// CHECK: %b = getelementptr %class.CB, ptr %[[PTR2]], i32 0, i32 1
+// CHECK: load double, ptr %b, align 8
return a + b;
}
// CHECK: define internal void @_init_resource_bindings() {
// CHECK-NEXT: entry:
-// CHECK-NEXT: %CB_h = call target("dx.CBuffer", { float, double }, 176, 16, 168)
-// CHECK-SAME: @llvm.dx.handle.fromBinding.tdx.CBuffer_sl_f32f64s_176_16_168t(i32 3, i32 1, i32 1, i32 0, i1 false)
-// CHECK-NEXT: store target("dx.CBuffer", { float, double }, 176, 16, 168) %CB_h, ptr @CB.cb, align 4
+// CHECK-NEXT: %CB_h = call target("dx.CBuffer", %class.CB, 176, 16, 168)
+// CHECK-SAME: @llvm.dx.handle.fromBinding.tdx.CBuffer_s_class.CBs_176_16_168t(i32 3, i32 1, i32 1, i32 0, i1 false)
+// CHECK-NEXT: store target("dx.CBuffer", %class.CB, 176, 16, 168) %CB_h, ptr @CB.cb, align 4
[numthreads(4,1,1)]
void main() {
diff --git a/clang/test/CodeGenHLSL/cbuffer_with_static_global_and_function.hlsl b/clang/test/CodeGenHLSL/cbuffer_with_static_global_and_function.hlsl
index c72eac85ca675e..e205f48015977c 100644
--- a/clang/test/CodeGenHLSL/cbuffer_with_static_global_and_function.hlsl
+++ b/clang/test/CodeGenHLSL/cbuffer_with_static_global_and_function.hlsl
@@ -1,8 +1,10 @@
// RUN: %clang_cc1 -finclude-default-header -triple dxil-pc-shadermodel6.3-library %s \
// RUN: -emit-llvm -disable-llvm-passes -o - | FileCheck %s
+// CHECK: %class.A = type { float }
+
// CHECK-DAG: @_ZL1b = internal global float 3.000000e+00, align 4
-// CHECK-DAG: @A.cb = external constant target("dx.CBuffer", { float }, 4, 0)
+// CHECK-DAG: @A.cb = external constant target("dx.CBuffer", %class.A, 4, 0)
// CHECK-NOT: @B.cb
cbuffer A {
@@ -17,9 +19,10 @@ cbuffer B {
// CHECK: define noundef float @_Z3foov() #0 {
-// CHECK: %[[HANDLE:[0-9]+]] = load target("dx.CBuffer", { float }, 4, 0), ptr @A.cb, align 4
-// CHECK: %[[PTR:[0-9]+]] = call ptr @llvm.dx.resource.getpointer.p0.tdx.CBuffer_sl_f32s_4_0t(target("dx.CBuffer", { float }, 4, 0) %[[HANDLE]], i32 0)
-// CHECK: %[[VAL1:[0-9]+]] = load float, ptr %[[PTR]], align 4
+// CHECK: %[[HANDLE:[0-9]+]] = load target("dx.CBuffer", %class.A, 4, 0), ptr @A.cb, align 4
+// CHECK: %[[PTR:[0-9]+]] = call ptr @llvm.dx.resource.getpointer.p0.tdx.CBuffer_s_class.As_4_0t(target("dx.CBuffer", %class.A, 4, 0) %[[HANDLE]], i32 0)
+// CHECK: %a = getelementptr %class.A, ptr %[[PTR]], i32 0, i32 0
+// CHECK: %[[VAL1:[0-9]+]] = load float, ptr %a, align 4
// CHECK: %[[VAL2:[0-9]+]] = load float, ptr @_ZL1b, align 4
// CHECK: %add = fadd float %[[VAL1]], %[[VAL2]]
>From a150b1e000e2ecceb504b3fda4690f24bbfd8ecd Mon Sep 17 00:00:00 2001
From: Helena Kotas <hekotas at microsoft.com>
Date: Thu, 19 Dec 2024 16:56:10 -0800
Subject: [PATCH 4/4] update tests after merge
---
clang/test/CodeGenHLSL/cbuffer.hlsl | 4 ++--
clang/test/CodeGenHLSL/cbuffer_with_packoffset.hlsl | 2 +-
2 files changed, 3 insertions(+), 3 deletions(-)
diff --git a/clang/test/CodeGenHLSL/cbuffer.hlsl b/clang/test/CodeGenHLSL/cbuffer.hlsl
index 77d408c9251cc3..b5be856d994f5b 100644
--- a/clang/test/CodeGenHLSL/cbuffer.hlsl
+++ b/clang/test/CodeGenHLSL/cbuffer.hlsl
@@ -58,10 +58,10 @@ float foo() {
// CHECK: define internal void @_init_resource_bindings() {
// CHECK-NEXT: entry:
// CHECK-NEXT: %CB_h = call target("dx.CBuffer", %class.CB, 16, 0, 8)
-// CHECK-SAME: @llvm.dx.handle.fromBinding.tdx.CBuffer_s_class.CBs_16_0_8t(i32 2, i32 0, i32 1, i32 0, i1 false)
+// CHECK-SAME: @llvm.dx.resource.handlefrombinding.tdx.CBuffer_s_class.CBs_16_0_8t(i32 2, i32 0, i32 1, i32 0, i1 false)
// CHECK-NEXT: store target("dx.CBuffer", %class.CB, 16, 0, 8) %CB_h, ptr @CB.cb, align 4
// CHECK-NEXT: %ParticleLife_h = call target("dx.CBuffer", %class.ParticleLife, 24, 0, 4, 8, 16, 20)
-// CHECK-SAME: @llvm.dx.handle.fromBinding.tdx.CBuffer_s_class.ParticleLifes_24_0_4_8_16_20t(i32 1, i32 2, i32 1, i32 0, i1 false)
+// CHECK-SAME: @llvm.dx.resource.handlefrombinding.tdx.CBuffer_s_class.ParticleLifes_24_0_4_8_16_20t(i32 1, i32 2, i32 1, i32 0, i1 false)
// CHECK-NEXT: store target("dx.CBuffer", %class.ParticleLife, 24, 0, 4, 8, 16, 20) %ParticleLife_h, ptr @ParticleLife.cb, align 4
// CHECK: define internal void @_GLOBAL__sub_I_cbuffer.hlsl()
diff --git a/clang/test/CodeGenHLSL/cbuffer_with_packoffset.hlsl b/clang/test/CodeGenHLSL/cbuffer_with_packoffset.hlsl
index b05c8c044ca4b5..b6bb8e0428c9c4 100644
--- a/clang/test/CodeGenHLSL/cbuffer_with_packoffset.hlsl
+++ b/clang/test/CodeGenHLSL/cbuffer_with_packoffset.hlsl
@@ -25,7 +25,7 @@ float foo() {
// CHECK: define internal void @_init_resource_bindings() {
// CHECK-NEXT: entry:
// CHECK-NEXT: %CB_h = call target("dx.CBuffer", %class.CB, 176, 16, 168)
-// CHECK-SAME: @llvm.dx.handle.fromBinding.tdx.CBuffer_s_class.CBs_176_16_168t(i32 3, i32 1, i32 1, i32 0, i1 false)
+// CHECK-SAME: @llvm.dx.resource.handlefrombinding.tdx.CBuffer_s_class.CBs_176_16_168t(i32 3, i32 1, i32 1, i32 0, i1 false)
// CHECK-NEXT: store target("dx.CBuffer", %class.CB, 176, 16, 168) %CB_h, ptr @CB.cb, align 4
[numthreads(4,1,1)]
More information about the cfe-commits
mailing list