Skip to content

Commit 17bf204

Browse files
committed
Add support for assigning whole array.
1 parent 58161a2 commit 17bf204

File tree

4 files changed

+79
-9
lines changed

4 files changed

+79
-9
lines changed

clang/lib/CodeGen/CGExpr.cpp

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6291,8 +6291,15 @@ LValue CodeGenFunction::EmitBinaryOperatorLValue(const BinaryOperator *E) {
62916291
LValue CodeGenFunction::EmitHLSLArrayAssignLValue(const BinaryOperator *E) {
62926292
// Don't emit an LValue for the RHS because it might not be an LValue
62936293
LValue LHS = EmitLValue(E->getLHS());
6294+
6295+
// If the RHS is a global resource array, copy all individual resources
6296+
// into LHS.
6297+
if (E->getRHS()->getType()->isHLSLResourceRecordArray())
6298+
if (CGM.getHLSLRuntime().emitResourceArrayCopy(LHS, E->getRHS(), *this))
6299+
return LHS;
6300+
62946301
// In C the RHS of an assignment operator is an RValue.
6295-
// EmitAggregateAssign takes anan LValue for the RHS. Instead we can call
6302+
// EmitAggregateAssign takes an LValue for the RHS. Instead we can call
62966303
// EmitInitializationToLValue to emit an RValue into an LValue.
62976304
EmitInitializationToLValue(E->getRHS(), LHS);
62986305
return LHS;

clang/lib/CodeGen/CGHLSLRuntime.cpp

Lines changed: 53 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
#include "clang/AST/ASTContext.h"
2222
#include "clang/AST/Attrs.inc"
2323
#include "clang/AST/Decl.h"
24+
#include "clang/AST/Expr.h"
2425
#include "clang/AST/HLSLResource.h"
2526
#include "clang/AST/RecursiveASTVisitor.h"
2627
#include "clang/AST/Type.h"
@@ -91,6 +92,14 @@ void addRootSignatureMD(llvm::dxbc::RootSignatureVersion RootSigVer,
9192
RootSignatureValMD->addOperand(MDVals);
9293
}
9394

95+
// Find array variable declaration from DeclRef expression
96+
static const ValueDecl *getArrayDecl(const Expr *E) {
97+
if (const DeclRefExpr *DRE =
98+
dyn_cast_or_null<DeclRefExpr>(E->IgnoreImpCasts()))
99+
return DRE->getDecl();
100+
return nullptr;
101+
}
102+
94103
// Find array variable declaration from nested array subscript AST nodes
95104
static const ValueDecl *getArrayDecl(const ArraySubscriptExpr *ASE) {
96105
const Expr *E = nullptr;
@@ -100,9 +109,7 @@ static const ValueDecl *getArrayDecl(const ArraySubscriptExpr *ASE) {
100109
return nullptr;
101110
ASE = dyn_cast<ArraySubscriptExpr>(E);
102111
}
103-
if (const DeclRefExpr *DRE = dyn_cast_or_null<DeclRefExpr>(E))
104-
return DRE->getDecl();
105-
return nullptr;
112+
return getArrayDecl(E);
106113
}
107114

108115
// Get the total size of the array, or -1 if the array is unbounded.
@@ -1116,3 +1123,46 @@ std::optional<LValue> CGHLSLRuntime::emitResourceArraySubscriptExpr(
11161123
}
11171124
return CGF.MakeAddrLValue(TmpVar, ResultTy, AlignmentSource::Decl);
11181125
}
1126+
1127+
// If RHSExpr is a global resource array, initialize all of its resources and
1128+
// set them into LHS. Returns false if no copy has been performed and the
1129+
// array copy should be handled by Clang codegen.
1130+
bool CGHLSLRuntime::emitResourceArrayCopy(LValue &LHS, Expr *RHSExpr,
1131+
CodeGenFunction &CGF) {
1132+
QualType ResultTy = RHSExpr->getType();
1133+
assert((ResultTy->isHLSLResourceRecordArray()) && "expected resource array");
1134+
1135+
// Let Clang codegen handle local and static resource array copies.
1136+
const VarDecl *ArrayDecl = dyn_cast_or_null<VarDecl>(getArrayDecl(RHSExpr));
1137+
if (!ArrayDecl || !ArrayDecl->hasGlobalStorage() ||
1138+
ArrayDecl->getStorageClass() == SC_Static)
1139+
return false;
1140+
1141+
// Find binding info for the resource array. For implicit binding
1142+
// the HLSLResourceBindingAttr should have been added by SemaHLSL.
1143+
ResourceBindingAttrs Binding(ArrayDecl);
1144+
assert((Binding.hasBinding()) &&
1145+
"resource array must have a binding attribute");
1146+
1147+
// Find the individual resource type.
1148+
ASTContext &AST = ArrayDecl->getASTContext();
1149+
QualType ResTy = AST.getBaseElementType(ResultTy);
1150+
const auto *ResArrayTy = cast<ConstantArrayType>(ResultTy.getTypePtr());
1151+
1152+
// Use the provided LHS for the result.
1153+
AggValueSlot ValueSlot = AggValueSlot::forAddr(
1154+
LHS.getAddress(), Qualifiers(), AggValueSlot::IsDestructed_t(true),
1155+
AggValueSlot::DoesNotNeedGCBarriers, AggValueSlot::IsAliased_t(false),
1156+
AggValueSlot::DoesNotOverlap);
1157+
1158+
// Create Value for index and total array size (= range size).
1159+
int Size = getTotalArraySize(AST, ResArrayTy);
1160+
llvm::Value *Zero = llvm::ConstantInt::get(CGM.IntTy, 0);
1161+
llvm::Value *Range = llvm::ConstantInt::get(CGM.IntTy, Size);
1162+
1163+
// Initialize individual resources in the array into LHS.
1164+
std::optional<llvm::Value *> EndIndex = initializeLocalResourceArray(
1165+
CGF, ResTy->getAsCXXRecordDecl(), ResArrayTy, ValueSlot, Range, Zero,
1166+
ArrayDecl->getName(), Binding, {Zero}, RHSExpr->getExprLoc());
1167+
return EndIndex.has_value();
1168+
}

clang/lib/CodeGen/CGHLSLRuntime.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -195,6 +195,8 @@ class CGHLSLRuntime {
195195
emitResourceArraySubscriptExpr(const ArraySubscriptExpr *E,
196196
CodeGenFunction &CGF);
197197

198+
bool emitResourceArrayCopy(LValue &LHS, Expr *RHSExpr, CodeGenFunction &CGF);
199+
198200
private:
199201
void emitBufferGlobalsAndMetadata(const HLSLBufferDecl *BufDecl,
200202
llvm::GlobalVariable *BufGV);

clang/test/SemaHLSL/static_resources.hlsl

Lines changed: 16 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
// CHECK-NOT: private unnamed_addr constant [{{[0-9]+}} x i8] c"Static
66

77
RWBuffer<float> One : register(u1, space5);
8-
RWBuffer<float> Array[4][2] : register(u10, space6);
8+
RWBuffer<float> Array[2] : register(u10, space6);
99

1010
// Check that the non-static resource One is initialized from binding on
1111
// startup (register 1, space 5).
@@ -51,20 +51,31 @@ void main() {
5151
// CHECK-NEXT: %[[TMP0:.*]] = alloca %"class.hlsl::RWBuffer"
5252

5353
static RWBuffer<float> StaticLocal;
54-
// Check that StaticLocal is initialized to by default constructor to poison and not from binding
54+
// Check that StaticLocal is initialized by default constructor (handle set to poison)
55+
// and not from binding.
5556
// call void @hlsl::RWBuffer<float>::RWBuffer()(ptr {{.*}} @main()::StaticLocal)
5657

57-
StaticLocal = Array[2][0];
58-
// A[2][0] is accessed here, so it should be initialized from binding (register 10, space 6, index 4),
58+
StaticLocal = Array[1];
59+
// A[2][0] is accessed here, so it should be initialized from binding (register 10, space 6, index 1),
5960
// and then assigned to StaticLocal using = operator.
6061
// CHECK: call void @hlsl::RWBuffer<float>::__createFromBinding(unsigned int, unsigned int, int, unsigned int, char const*)
61-
// CHECK-SAME: (ptr {{.*}} %[[TMP0]], i32 noundef 10, i32 noundef 6, i32 noundef 8, i32 noundef 4, ptr noundef [[ARRAY_STR]])
62+
// CHECK-SAME: (ptr {{.*}} %[[TMP0]], i32 noundef 10, i32 noundef 6, i32 noundef 2, i32 noundef 1, ptr noundef [[ARRAY_STR]])
6263
// CHECK-NEXT: call {{.*}} ptr @hlsl::RWBuffer<float>::operator=({{.*}})(ptr {{.*}} @main()::StaticLocal, ptr {{.*}} %[[TMP0]])
6364

6465
StaticOne = One;
66+
// Operator = call to assign non-static One handle to static StaticOne.
6567
// CHECK-NEXT: call {{.*}} ptr @hlsl::RWBuffer<float>::operator=({{.*}})(ptr {{.*}} @StaticOne, ptr {{.*}} @One)
6668

69+
StaticArray = Array;
70+
// Check that each elements of StaticArray is initialized from binding (register 10, space 6, indices 0 and 1).
71+
// CHECK: call void @hlsl::RWBuffer<float>::__createFromBinding(unsigned int, unsigned int, int, unsigned int, char const*)
72+
// CHECK-SAME: (ptr {{.*}} sret(%"class.hlsl::RWBuffer") align 4 @StaticArray, i32 noundef 10, i32 noundef 6, i32 noundef 2, i32 noundef 0, ptr noundef [[ARRAY_STR]])
73+
// CHECK-NEXT: call void @hlsl::RWBuffer<float>::__createFromBinding(unsigned int, unsigned int, int, unsigned int, char const*)
74+
// CHECK-SAME: (ptr {{.*}} sret(%"class.hlsl::RWBuffer") align 4 getelementptr ([2 x %"class.hlsl::RWBuffer"], ptr @StaticArray, i32 0, i32 1),
75+
// CHECK-SAME: i32 noundef 10, i32 noundef 6, i32 noundef 2, i32 noundef 1, ptr noundef [[ARRAY_STR]]
76+
6777
StaticArray[1] = One;
78+
// Operator = call to assign non-static One handle to StaticArray element.
6879
// CHECK-NEXT: call {{.*}} ptr @hlsl::RWBuffer<float>::operator=(hlsl::RWBuffer<float> const&)
6980
// CHECK-SAME: (ptr {{.*}} getelementptr inbounds ([2 x %"class.hlsl::RWBuffer"], ptr @StaticArray, i32 0, i32 1), ptr {{.*}} @One)
7081

0 commit comments

Comments
 (0)