Skip to content

Commit 4fc141c

Browse files
authored
[SPIRV] Evaluate RawBuffer alignment argument (microsoft#5654)
Before this change, the alignment argument needed to be an integer literal to be evaluated correctly at compile time. This change now makes a reasonable attempts to evaluate it if it is a constant value. Fixes microsoft#4594
1 parent 66d0ed8 commit 4fc141c

File tree

4 files changed

+44
-53
lines changed

4 files changed

+44
-53
lines changed

tools/clang/lib/SPIRV/SpirvEmitter.cpp

Lines changed: 24 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -13754,60 +13754,28 @@ SpirvEmitter::processSpvIntrinsicCallExpr(const CallExpr *expr) {
1375413754
/*isInstr*/ true, expr->getExprLoc());
1375513755
}
1375613756

13757-
uint32_t SpirvEmitter::getAlignmentForRawBufferLoad(const CallExpr *callExpr) {
13758-
if (callExpr->getNumArgs() == 1)
13759-
return 4;
13760-
13761-
if (callExpr->getNumArgs() > 2) {
13762-
emitError("number of arguments for vk::RawBufferLoad() must be 1 or 2",
13763-
callExpr->getExprLoc());
13764-
return 0;
13757+
uint32_t SpirvEmitter::getRawBufferAlignment(const Expr *expr) {
13758+
llvm::APSInt value;
13759+
if (expr->EvaluateAsInt(value, astContext) && value.isNonNegative()) {
13760+
return static_cast<uint32_t>(value.getZExtValue());
1376513761
}
1376613762

13767-
const Expr *alignmentArgExpr = callExpr->getArg(1);
13768-
if (const auto *templateParmExpr =
13769-
dyn_cast<SubstNonTypeTemplateParmExpr>(alignmentArgExpr)) {
13770-
alignmentArgExpr = templateParmExpr->getReplacement();
13771-
}
13772-
const auto *intLiteral =
13773-
dyn_cast<IntegerLiteral>(alignmentArgExpr->IgnoreImplicit());
13774-
if (intLiteral == nullptr) {
13775-
emitError("alignment argument of vk::RawBufferLoad() must be a constant "
13776-
"integer",
13777-
callExpr->getArg(1)->getExprLoc());
13778-
return 0;
13779-
}
13780-
return static_cast<uint32_t>(intLiteral->getValue().getZExtValue());
13763+
// Unable to determine a valid alignment at compile time
13764+
emitError("alignment argument must be a constant unsigned integer",
13765+
expr->getExprLoc());
13766+
return 0;
1378113767
}
1378213768

13783-
uint32_t SpirvEmitter::getAlignmentForRawBufferStore(const CallExpr *callExpr) {
13784-
if (callExpr->getNumArgs() == 2)
13785-
return 4;
13786-
13787-
if (callExpr->getNumArgs() != 2 && callExpr->getNumArgs() != 3) {
13788-
emitError("number of arguments for vk::RawBufferStore() must be 2 or 3",
13769+
SpirvInstruction *SpirvEmitter::processRawBufferLoad(const CallExpr *callExpr) {
13770+
if (callExpr->getNumArgs() > 2) {
13771+
emitError("number of arguments for vk::RawBufferLoad() must be 1 or 2",
1378913772
callExpr->getExprLoc());
13790-
return 0;
13791-
}
13792-
13793-
const Expr *alignmentArgExpr = callExpr->getArg(2);
13794-
if (const auto *templateParmExpr =
13795-
dyn_cast<SubstNonTypeTemplateParmExpr>(alignmentArgExpr)) {
13796-
alignmentArgExpr = templateParmExpr->getReplacement();
13797-
}
13798-
const auto *intLiteral =
13799-
dyn_cast<IntegerLiteral>(alignmentArgExpr->IgnoreImplicit());
13800-
if (intLiteral == nullptr) {
13801-
emitError("alignment argument of vk::RawBufferStore() must be a constant "
13802-
"integer",
13803-
callExpr->getArg(2)->getExprLoc());
13804-
return 0;
13773+
return nullptr;
1380513774
}
13806-
return static_cast<uint32_t>(intLiteral->getValue().getZExtValue());
13807-
}
1380813775

13809-
SpirvInstruction *SpirvEmitter::processRawBufferLoad(const CallExpr *callExpr) {
13810-
uint32_t alignment = getAlignmentForRawBufferLoad(callExpr);
13776+
uint32_t alignment = callExpr->getNumArgs() == 1
13777+
? 4
13778+
: getRawBufferAlignment(callExpr->getArg(1));
1381113779
if (alignment == 0)
1381213780
return nullptr;
1381313781

@@ -13900,7 +13868,15 @@ SpirvEmitter::storeDataToRawAddress(SpirvInstruction *addressInUInt64,
1390013868

1390113869
SpirvInstruction *
1390213870
SpirvEmitter::processRawBufferStore(const CallExpr *callExpr) {
13903-
uint32_t alignment = getAlignmentForRawBufferStore(callExpr);
13871+
if (callExpr->getNumArgs() != 2 && callExpr->getNumArgs() != 3) {
13872+
emitError("number of arguments for vk::RawBufferStore() must be 2 or 3",
13873+
callExpr->getExprLoc());
13874+
return nullptr;
13875+
}
13876+
13877+
uint32_t alignment = callExpr->getNumArgs() == 2
13878+
? 4
13879+
: getRawBufferAlignment(callExpr->getArg(2));
1390413880
if (alignment == 0)
1390513881
return nullptr;
1390613882

tools/clang/lib/SPIRV/SpirvEmitter.h

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -704,11 +704,9 @@ class SpirvEmitter : public ASTConsumer {
704704
SourceLocation loc,
705705
SourceRange range);
706706

707-
/// Returns the alignment of `vk::RawBufferLoad()`.
708-
uint32_t getAlignmentForRawBufferLoad(const CallExpr *callExpr);
709-
710-
/// Returns the alignment of `vk::RawBufferStore()`.
711-
uint32_t getAlignmentForRawBufferStore(const CallExpr *callExpr);
707+
/// Returns the value of the alignment argument for `vk::RawBufferLoad()` and
708+
/// `vk::RawBufferStore()`.
709+
uint32_t getRawBufferAlignment(const Expr *expr);
712710

713711
/// Process vk::ext_execution_mode intrinsic
714712
SpirvInstruction *processIntrinsicExecutionMode(const CallExpr *expr,

tools/clang/test/CodeGenSPIRV/intrinsics.vkrawbufferload.hlsl

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,5 +34,12 @@ float4 main() : SV_Target0 {
3434
// CHECK-NEXT: OpStore %v [[load]]
3535
uint v = vk::RawBufferLoad(Address);
3636

37+
// CHECK: [[addr:%\d+]] = OpLoad %ulong
38+
// CHECK-NEXT: [[buf:%\d+]] = OpBitcast %_ptr_PhysicalStorageBuffer_float [[addr]]
39+
// CHECK-NEXT: [[load:%\d+]] = OpLoad %float [[buf]] Aligned 4
40+
// CHECK-NEXT: OpStore %u [[load]]
41+
const uint alignment = 4;
42+
float u = vk::RawBufferLoad<float>(Address, alignment);
43+
3744
return float4(w.x, x, y, z);
3845
}
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
// RUN: not %dxc -T ps_6_0 -E main -fcgl -spirv %s -spirv 2>&1 | FileCheck %s
2+
3+
// CHECK: error: alignment argument must be a constant unsigned integer
4+
5+
uint64_t Address;
6+
float4 main() : SV_Target0 {
7+
float4 x = vk::RawBufferLoad<float4>(Address, -16);
8+
9+
return x;
10+
}

0 commit comments

Comments
 (0)