-
Notifications
You must be signed in to change notification settings - Fork 15.2k
Explicit types in cbuffer layouts #156919
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Conversation
You can test this locally with the following command:git-clang-format --diff origin/main HEAD --extensions h,c,cpp -- clang/include/clang/AST/CharUnits.h clang/lib/AST/APValue.cpp clang/lib/AST/RecordLayoutBuilder.cpp clang/lib/Basic/Targets/DirectX.h clang/lib/CodeGen/CGAtomic.cpp clang/lib/CodeGen/CGExpr.cpp clang/lib/CodeGen/CGExprAgg.cpp clang/lib/CodeGen/CGExprConstant.cpp clang/lib/CodeGen/CGHLSLRuntime.cpp clang/lib/CodeGen/CGHLSLRuntime.h clang/lib/CodeGen/CGObjCMac.cpp clang/lib/CodeGen/CGRecordLayoutBuilder.cpp clang/lib/CodeGen/HLSLBufferLayoutBuilder.cpp clang/lib/CodeGen/HLSLBufferLayoutBuilder.h clang/lib/CodeGen/TargetInfo.h clang/lib/CodeGen/Targets/DirectX.cpp clang/lib/CodeGen/Targets/SPIR.cpp clang/lib/Sema/SemaChecking.cpp clang/lib/StaticAnalyzer/Core/Store.cpp clang/test/CodeGenHLSL/basic-target.c llvm/include/llvm/Analysis/DXILResource.h llvm/include/llvm/Frontend/HLSL/CBuffer.h llvm/lib/Analysis/DXILResource.cpp llvm/lib/Frontend/HLSL/CBuffer.cpp llvm/lib/IR/Type.cpp llvm/lib/Target/DirectX/DXILCBufferAccess.cpp llvm/lib/Target/SPIRV/SPIRVCBufferAccess.cpp llvm/lib/Target/SPIRV/SPIRVEmitIntrinsics.cpp llvm/lib/TargetParser/TargetDataLayout.cpp llvm/unittests/Analysis/DXILResourceTest.cpp
View the diff from clang-format here.diff --git a/clang/include/clang/AST/CharUnits.h b/clang/include/clang/AST/CharUnits.h
index bd7457f1c..e570bfae6 100644
--- a/clang/include/clang/AST/CharUnits.h
+++ b/clang/include/clang/AST/CharUnits.h
@@ -165,7 +165,7 @@ namespace clang {
CharUnits operator% (QuantityType N) const {
return CharUnits(Quantity % N);
}
- CharUnits operator% (const CharUnits &Other) const {
+ CharUnits operator%(const CharUnits &Other) const {
return CharUnits(Quantity % Other.Quantity);
}
CharUnits operator+ (const CharUnits &Other) const {
diff --git a/clang/lib/CodeGen/CGExpr.cpp b/clang/lib/CodeGen/CGExpr.cpp
index 6c6a84709..5571356e7 100644
--- a/clang/lib/CodeGen/CGExpr.cpp
+++ b/clang/lib/CodeGen/CGExpr.cpp
@@ -4681,7 +4681,7 @@ LValue CodeGenFunction::EmitArraySubscriptExpr(const ArraySubscriptExpr *E,
} else if (E->getType().getAddressSpace() == LangAS::hlsl_constant) {
// This is an array inside of a cbuffer.
Addr = EmitPointerWithAlignment(E->getBase(), &EltBaseInfo, &EltTBAAInfo);
- auto *Idx = EmitIdxAfterBase(/*Promote*/true);
+ auto *Idx = EmitIdxAfterBase(/*Promote*/ true);
// ...
CharUnits RowAlignedSize = getContext()
@@ -4693,7 +4693,7 @@ LValue CodeGenFunction::EmitArraySubscriptExpr(const ArraySubscriptExpr *E,
llvm::Value *ScaledIdx = Builder.CreateMul(Idx, RowAlignedSizeVal);
CharUnits EltAlign =
- getArrayElementAlign(Addr.getAlignment(), Idx, RowAlignedSize);
+ getArrayElementAlign(Addr.getAlignment(), Idx, RowAlignedSize);
llvm::Value *EltPtr =
emitArraySubscriptGEP(*this, Int8Ty, Addr.emitRawPointer(*this),
ScaledIdx, false, SignedIndices, E->getExprLoc());
diff --git a/clang/lib/CodeGen/HLSLBufferLayoutBuilder.h b/clang/lib/CodeGen/HLSLBufferLayoutBuilder.h
index 0515b469f..20ebd6bb3 100644
--- a/clang/lib/CodeGen/HLSLBufferLayoutBuilder.h
+++ b/clang/lib/CodeGen/HLSLBufferLayoutBuilder.h
@@ -46,8 +46,7 @@ public:
const llvm::SmallVector<int32_t> *Packoffsets = nullptr);
/// Lays out an array type following HLSL buffer rules.
- llvm::Type *
- layOutArray(const ConstantArrayType *AT);
+ llvm::Type *layOutArray(const ConstantArrayType *AT);
/// Lays out a type following HLSL buffer rules. Arrays and structures will be
/// padded appropriately and nested objects will be converted as appropriate.
diff --git a/clang/lib/CodeGen/TargetInfo.h b/clang/lib/CodeGen/TargetInfo.h
index 8b59fde4b..ba26f9a98 100644
--- a/clang/lib/CodeGen/TargetInfo.h
+++ b/clang/lib/CodeGen/TargetInfo.h
@@ -448,8 +448,8 @@ public:
return nullptr;
}
- virtual llvm::Type *
- getHLSLPadding(CodeGenModule &CGM, CharUnits NumBytes) const {
+ virtual llvm::Type *getHLSLPadding(CodeGenModule &CGM,
+ CharUnits NumBytes) const {
return llvm::ArrayType::get(llvm::Type::getInt8Ty(CGM.getLLVMContext()),
NumBytes.getQuantity());
}
diff --git a/clang/lib/CodeGen/Targets/SPIR.cpp b/clang/lib/CodeGen/Targets/SPIR.cpp
index 9db3daebd..3aa2b4554 100644
--- a/clang/lib/CodeGen/Targets/SPIR.cpp
+++ b/clang/lib/CodeGen/Targets/SPIR.cpp
@@ -57,8 +57,8 @@ public:
getHLSLType(CodeGenModule &CGM, const Type *Ty,
const SmallVector<int32_t> *Packoffsets = nullptr) const override;
- llvm::Type *
- getHLSLPadding(CodeGenModule &CGM, CharUnits NumBytes) const override {
+ llvm::Type *getHLSLPadding(CodeGenModule &CGM,
+ CharUnits NumBytes) const override {
unsigned Size = NumBytes.getQuantity();
return llvm::TargetExtType::get(CGM.getLLVMContext(), "spirv.Padding", {},
{Size});
|
This shader fails to compile due to hitting an assert: // compile args: -T cs_6_2 -E CSMain
typedef uint32_t4 uint32_t8[2];
void Foo(uint32_t8) {}
cbuffer Constants {
uint32_t8 s;
}
[numthreads(1, 1, 1)]
void CSMain() {
Foo(s);
}
Removing the typedef and just using Edit: This issue has been fixed! |
6aa172d
to
24a61c4
Compare
I'm seeing a problem for SPIR-V that we may need to work out. I understand why you do it, and I don't have a solution yet.
|
24a61c4
to
8e728c5
Compare
clang/lib/CodeGen/CGExpr.cpp
Outdated
llvm::Value *EltPtr = | ||
emitArraySubscriptGEP(*this, Int8Ty, Addr.emitRawPointer(*this), | ||
ScaledIdx, false, SignedIndices, E->getExprLoc()); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Doing an i8 gep does work for SPIR-V. We want to avoid that as much as possible. Can this be turned into a typed GEP with the padded type when needed? I tried writing it myself so I could make a suggestion, but I can't get it right.
See https://discourse.llvm.org/t/type-based-gep-plans/87183/14
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@bogner You are still generating this GEP with an i8. Can we change this to a GEP on the array type.
Start with the test at the end. Compile with clang-dxc test_minimal_peeling.hlsl -T cs_6_8 -spirv -fcgl
The access to myArray is:
%3 = load i32, ptr %index, align 4, !tbaa !4
%idxprom = zext i32 %3 to i64
%4 = mul i64 %idxprom, 16
%arrayidx = getelementptr i8, ptr addrspace(12) @myArray, i64 %4 ; <-- problem for SPIR-V.
%f = getelementptr inbounds nuw %struct.OrigType, ptr addrspace(12) %arrayidx, i32 0, i32 0
%5 = load float, ptr addrspace(12) %f, align 1, !tbaa !14
It would be better if it could be
%3 = load i32, ptr %index, align 4, !tbaa !4
%idxprom = zext i32 %3 to i64
%arrayidx = getelementptr [4 x <{ %OrigType, target("spirv.Padding", 12) }>], ptr addrspace(12) @myArray, i64 %idxprom ; <-- Explicit array
%f = getelementptr inbounds nuw %struct.OrigType, ptr addrspace(12) %arrayidx, i32 0, i32 0
%5 = load float, ptr addrspace(12) %f, align 1, !tbaa !14
You use the original array size with the padding.
struct OrigType {
float f;
};
cbuffer MyCBuffer {
OrigType myArray[4];
float anotherValue;
};
RWBuffer<float4> output;
[numthreads(1, 1, 1)]
void main(uint3 DTid : SV_DispatchThreadID) {
uint index = DTid.x % 4;
float v = myArray[index].f;
float f = anotherValue;
output[0] = float4(v, f, 0, 0);
}
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I've tried this out in 92bd225 (which still needs test updates). This looks mostly reasonable with the caveat that we do need a bit of a fictional type for this to work (the array with padding on all elements including the last one). Since we don't actually read the padding this is probably fine.
8e728c5
to
90e49a2
Compare
Updated with typed GEPs and padding types if you want to take a look at what code we're generating, but the diff is kind of unreadable at the moment. I'll be cleaning this up and getting things ready for staging next. |
This explicitly adds two 3-element vectors to the DataLayout so that they'll be element-aligned. We need to do this more generally for vectors, but this unblocks some very common cases. Workaround for llvm#123968
This introduces the `dx.Padding` type as an alternative to the `dx.Layout` types that are currently used for cbuffers. Later, we'll remove the `dx.Layout` types completely, but making the backend handle either makes it easier to stage the necessary changes to get there. See llvm#147352 for details.
Update the `operator%` overload that accepts `CharUnits` to return `CharUnits` to match the other `operator%`. This is more logical than returning an `int64` and cleans up users that want to continue to do math with the result. Many users of this were explicitly comparing against 0. I considered updating these to compare against `CharUnits::Zero` or even introducing an `explicit operator bool()`, but they all feel clearer if we update them to use the existing `isMultipleOf()` function instead.
CHECK-lines ignore whitespace, so we can remove some here and make this a bit easier to read.
DXILResource was falling over trying to name a resource type that contained an array, such as `StructuredBuffer<float[3][2]>`. Handle this by walking through array types to gather the dimensions.
This abandons the `dx.Layout` idea and just uses explicit padding. Note: Reordered fields break stuff, including ones from implicit bindings.
TODO: This must go in after the frontend changes
90e49a2
to
c73d2a3
Compare
This is a bit tricky - when we have a padded array we have a struct with a slightly smaller array followed by the last element, since that last element doesn't itself have padding. Here, we create an imaginary array type with the padding on every element and index into that - this looks like we index out of bounds of the smaller array for the last element but this is okay because we only read the memory of the value that is legitimately there.
This should demonstrate #147352 well enough to look at how it will affect the backends, but it still needs a fair amount of work and cleanup.