Skip to content

Commit 96a8b32

Browse files
simolltex3d
andauthored
[SM6.10] Complete ClusterID implementation (#8065)
- Add logic to check AvailabilityAttribute on member functions (wasn't checked before). Required for RQ / HitObject cluster methods. - Lowering for all ClusterID variants with tests - CLUSTER_ID_INVALID definition and tests - Validation logic with expected pass and fail tests Closes #8041 --------- Co-authored-by: Tex Riddell <[email protected]>
1 parent 607e997 commit 96a8b32

13 files changed

Lines changed: 627 additions & 8 deletions

File tree

include/dxc/HlslIntrinsicOp.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -369,9 +369,9 @@ enum class IntrinsicOp {
369369
MOP_TraceRayInline = 325,
370370
MOP_WorldRayDirection = 326,
371371
MOP_WorldRayOrigin = 327,
372-
MOP_DxHitObject_ClusterID = 400,
373372
MOP_DxHitObject_FromRayQuery = 363,
374373
MOP_DxHitObject_GetAttributes = 364,
374+
MOP_DxHitObject_GetClusterID = 400,
375375
MOP_DxHitObject_GetGeometryIndex = 365,
376376
MOP_DxHitObject_GetHitKind = 366,
377377
MOP_DxHitObject_GetInstanceID = 367,

lib/DxilValidation/DxilValidation.cpp

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2349,6 +2349,25 @@ static void ValidateDxilOperationCallInProfile(CallInst *CI,
23492349
ValCtx.EmitInstrError(CI, ValidationRule::InstrNoReadingUninitialized);
23502350
DxilInst_HitObject_TraceRay HOTraceRay(CI);
23512351
} break;
2352+
2353+
// Clustered Geometry intrinsics
2354+
case DXIL::OpCode::RayQuery_CandidateClusterID:
2355+
case DXIL::OpCode::RayQuery_CommittedClusterID: {
2356+
// Validate rayQueryHandle is not undef
2357+
Value *RayQueryHandle = CI->getArgOperand(1);
2358+
if (isa<UndefValue>(RayQueryHandle))
2359+
ValCtx.EmitInstrError(CI, ValidationRule::InstrNoReadingUninitialized);
2360+
break;
2361+
}
2362+
2363+
case DXIL::OpCode::HitObject_ClusterID: {
2364+
// Validate HitObject is not undef
2365+
Value *HitObject = CI->getArgOperand(1);
2366+
if (isa<UndefValue>(HitObject))
2367+
ValCtx.EmitInstrError(CI, ValidationRule::InstrUndefHitObject);
2368+
break;
2369+
}
2370+
23522371
case DXIL::OpCode::AtomicBinOp:
23532372
case DXIL::OpCode::AtomicCompareExchange: {
23542373
Type *pOverloadType = OP::GetOverloadType(Opcode, CI->getCalledFunction());

lib/HLSL/HLOperationLower.cpp

Lines changed: 19 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1327,6 +1327,20 @@ Value *TrivialNoArgWithRetOperation(CallInst *CI, IntrinsicOp IOP,
13271327
return dxilOp;
13281328
}
13291329

1330+
Value *TrivialNoArgWithRetNoOverloadOperation(
1331+
CallInst *CI, IntrinsicOp IOP, OP::OpCode opcode,
1332+
HLOperationLowerHelper &helper, HLObjectOperationLowerHelper *pObjHelper,
1333+
bool &Translated) {
1334+
hlsl::OP *hlslOP = &helper.hlslOP;
1335+
Type *Ty = CI->getType();
1336+
1337+
Constant *opArg = hlslOP->GetU32Const((unsigned)opcode);
1338+
Value *args[] = {opArg};
1339+
IRBuilder<> Builder(CI);
1340+
return TrivialDxilOperation(opcode, args, Builder.getVoidTy(), Ty, hlslOP,
1341+
Builder);
1342+
}
1343+
13301344
Value *TranslateGetRTSamplePos(CallInst *CI, IntrinsicOp IOP, OP::OpCode op,
13311345
HLOperationLowerHelper &helper,
13321346
HLObjectOperationLowerHelper *pObjHelper,
@@ -7520,12 +7534,13 @@ constexpr IntrinsicLower gLowerTable[] = {
75207534
{IntrinsicOp::IOP_GetGroupWaveIndex, TranslateWaveToVal,
75217535
DXIL::OpCode::GetGroupWaveIndex},
75227536

7523-
{IntrinsicOp::IOP_ClusterID, EmptyLower, DXIL::OpCode::ClusterID},
7524-
{IntrinsicOp::MOP_CandidateClusterID, EmptyLower,
7537+
{IntrinsicOp::IOP_ClusterID, TrivialNoArgWithRetNoOverloadOperation,
7538+
DXIL::OpCode::ClusterID},
7539+
{IntrinsicOp::MOP_CandidateClusterID, TranslateGenericRayQueryMethod,
75257540
DXIL::OpCode::RayQuery_CandidateClusterID},
7526-
{IntrinsicOp::MOP_CommittedClusterID, EmptyLower,
7541+
{IntrinsicOp::MOP_CommittedClusterID, TranslateGenericRayQueryMethod,
75277542
DXIL::OpCode::RayQuery_CommittedClusterID},
7528-
{IntrinsicOp::MOP_DxHitObject_ClusterID, EmptyLower,
7543+
{IntrinsicOp::MOP_DxHitObject_GetClusterID, TranslateHitObjectScalarGetter,
75297544
DXIL::OpCode::HitObject_ClusterID},
75307545

75317546
{IntrinsicOp::IOP_TriangleObjectPosition, EmptyLower,

tools/clang/lib/AST/ASTContextHLSL.cpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -662,6 +662,9 @@ void hlsl::AddRaytracingConstants(ASTContext &context) {
662662
AddConstUInt(context, StringRef("HIT_KIND_TRIANGLE_BACK_FACE"),
663663
(unsigned)DXIL::HitKind::TriangleBackFace);
664664

665+
// static const uint CLUSTER_ID_INVALID = 0xffffffff;
666+
AddConstUInt(context, StringRef("CLUSTER_ID_INVALID"), 0xffffffff);
667+
665668
AddConstUInt(
666669
context,
667670
StringRef(

tools/clang/lib/Sema/SemaHLSLDiagnoseTU.cpp

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -436,6 +436,15 @@ class HLSLReachableDiagnoseVisitor
436436
return true;
437437
}
438438

439+
bool VisitMemberExpr(MemberExpr *ME) {
440+
// Diagnose availability for member function calls.
441+
if (AvailabilityAttr *AAttr = GetAvailabilityAttrOnce(ME)) {
442+
DiagnoseAvailability(AAttr, ME->getMemberDecl(), ME->getExprLoc());
443+
}
444+
445+
return true;
446+
}
447+
439448
AvailabilityAttr *GetAvailabilityAttrOnce(TypeLoc TL) {
440449
QualType Ty = TL.getType();
441450
CXXRecordDecl *RD = Ty->getAsCXXRecordDecl();
@@ -463,6 +472,18 @@ class HLSLReachableDiagnoseVisitor
463472
return AAttr;
464473
}
465474

475+
AvailabilityAttr *GetAvailabilityAttrOnce(MemberExpr *ME) {
476+
AvailabilityAttr *AAttr = ME->getMemberDecl()->getAttr<AvailabilityAttr>();
477+
if (!AAttr)
478+
return nullptr;
479+
// Skip redundant availability diagnostics for the same member.
480+
// Use the member location to track if we've already diagnosed this.
481+
if (!DiagnosedTypeLocs.insert(ME->getMemberLoc()).second)
482+
return nullptr;
483+
484+
return AAttr;
485+
}
486+
466487
bool CheckSMVersion(VersionTuple AAttrVT) {
467488
VersionTuple SMVT = VersionTuple(SM->GetMajor(), SM->GetMinor());
468489
return SMVT >= AAttrVT;
Lines changed: 109 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,109 @@
1+
// REQUIRES: dxil-1-10
2+
// RUN: %dxc -T lib_6_10 %s | FileCheck %s
3+
// RUN: %dxc -T lib_6_10 %s -ast-dump-implicit | FileCheck %s --check-prefix AST
4+
// RUN: %dxc -T lib_6_10 %s -fcgl | FileCheck %s --check-prefix FCGL
5+
6+
// Test ClusterID intrinsics for SM 6.10
7+
8+
// AST: `-CXXMethodDecl {{.*}} used GetClusterID 'unsigned int ()' extern
9+
// AST-NEXT: {{.*}}|-TemplateArgument type 'unsigned int'
10+
// AST-NEXT: {{.*}}|-HLSLIntrinsicAttr {{.*}} Implicit "op" "" 400
11+
// AST-NEXT: {{.*}}|-ConstAttr {{.*}} Implicit
12+
// AST-NEXT: {{.*}}`-AvailabilityAttr {{.*}} Implicit 6.10 0 0 ""
13+
14+
// AST: `-CXXMethodDecl {{.*}} used CandidateClusterID 'unsigned int ()' extern
15+
// AST-NEXT: {{.*}}|-TemplateArgument type 'unsigned int'
16+
// AST-NEXT: {{.*}}|-HLSLIntrinsicAttr {{.*}} Implicit "op" "" 398
17+
// AST-NEXT: {{.*}}|-PureAttr {{.*}} Implicit
18+
// AST-NEXT: {{.*}}`-AvailabilityAttr {{.*}} Implicit 6.10 0 0 ""
19+
20+
// AST: `-CXXMethodDecl {{.*}} used CommittedClusterID 'unsigned int ()' extern
21+
// AST-NEXT: {{.*}}|-TemplateArgument type 'unsigned int'
22+
// AST-NEXT: {{.*}}|-HLSLIntrinsicAttr {{.*}} Implicit "op" "" 399
23+
// AST-NEXT: {{.*}}|-PureAttr {{.*}} Implicit
24+
// AST-NEXT: {{.*}}`-AvailabilityAttr {{.*}} Implicit 6.10 0 0 ""
25+
26+
// AST: -FunctionDecl {{.*}} implicit used ClusterID 'unsigned int ()' extern
27+
// AST-NEXT: {{.*}}|-HLSLIntrinsicAttr {{.*}} Implicit "op" "" 397
28+
// AST-NEXT: {{.*}}|-ConstAttr {{.*}} Implicit
29+
// AST-NEXT: {{.*}}|-AvailabilityAttr {{.*}} Implicit 6.10 0 0 ""
30+
// AST-NEXT: {{.*}}`-HLSLBuiltinCallAttr {{.*}} Implicit
31+
32+
RWByteAddressBuffer outbuf : register(u0);
33+
34+
struct [raypayload] Payload {
35+
float dummy : read(caller, closesthit, miss, anyhit) : write(caller, closesthit, miss, anyhit);
36+
};
37+
38+
// Global ClusterID intrinsic
39+
// CHECK-LABEL: define void @{{.*}}test_cluster_id{{.*}}(
40+
// CHECK: call i32 @dx.op.clusterID(i32 -2147483645)
41+
// CHECK: call void @dx.op.rawBufferStore.i32
42+
43+
// FCGL-LABEL: define void @{{.*}}test_cluster_id{{.*}}(
44+
// FCGL: call i32 @"dx.hl.op.rn.i32 (i32)"(i32 397)
45+
[shader("closesthit")]
46+
void test_cluster_id(inout Payload payload, in BuiltInTriangleIntersectionAttributes attr) {
47+
uint cid = ClusterID();
48+
outbuf.Store(0, cid);
49+
}
50+
51+
// RayQuery CandidateClusterID
52+
// CHECK-LABEL: define void @{{.*}}test_rayquery_candidate_cluster_id{{.*}}(
53+
// CHECK: call i32 @dx.op.rayQuery_StateScalar.i32(i32 -2147483644
54+
// CHECK: call void @dx.op.rawBufferStore.i32
55+
56+
// FCGL-LABEL: define void @{{.*}}test_rayquery_candidate_cluster_id{{.*}}(
57+
// FCGL: call i32 @"dx.hl.op.ro.i32 (i32, %{{.*}}"(i32 398
58+
[shader("raygeneration")]
59+
void test_rayquery_candidate_cluster_id() {
60+
RayQuery<RAY_FLAG_NONE> rq;
61+
RaytracingAccelerationStructure as;
62+
RayDesc ray;
63+
ray.Origin = float3(0, 0, 0);
64+
ray.Direction = float3(0, 0, 1);
65+
ray.TMin = 0.0;
66+
ray.TMax = 1000.0;
67+
68+
rq.TraceRayInline(as, 0, 0xff, ray);
69+
rq.Proceed();
70+
uint cid = rq.CandidateClusterID();
71+
outbuf.Store(4, cid);
72+
}
73+
74+
// RayQuery CommittedClusterID
75+
// CHECK-LABEL: define void @{{.*}}test_rayquery_committed_cluster_id{{.*}}(
76+
// CHECK: call i32 @dx.op.rayQuery_StateScalar.i32(i32 -2147483643
77+
// CHECK: call void @dx.op.rawBufferStore.i32
78+
79+
// FCGL-LABEL: define void @{{.*}}test_rayquery_committed_cluster_id{{.*}}(
80+
// FCGL: call i32 @"dx.hl.op.ro.i32 (i32, %{{.*}}"(i32 399
81+
[shader("raygeneration")]
82+
void test_rayquery_committed_cluster_id() {
83+
RayQuery<RAY_FLAG_NONE> rq;
84+
RaytracingAccelerationStructure as;
85+
RayDesc ray;
86+
ray.Origin = float3(0, 0, 0);
87+
ray.Direction = float3(0, 0, 1);
88+
ray.TMin = 0.0;
89+
ray.TMax = 1000.0;
90+
91+
rq.TraceRayInline(as, 0, 0xff, ray);
92+
uint cid = rq.CommittedClusterID();
93+
outbuf.Store(8, cid);
94+
}
95+
96+
// HitObject GetClusterID
97+
// CHECK-LABEL: define void @{{.*}}test_hitobject_cluster_id{{.*}}(
98+
// CHECK: call i32 @dx.op.hitObject_StateScalar.i32(i32 -2147483642
99+
// CHECK: call void @dx.op.rawBufferStore.i32
100+
101+
// FCGL-LABEL: define void @{{.*}}test_hitobject_cluster_id{{.*}}(
102+
// FCGL: call i32 @"dx.hl.op.rn.i32 (i32, %dx.types.HitObject{{.*}}"(i32 400
103+
[shader("raygeneration")]
104+
void test_hitobject_cluster_id() {
105+
dx::HitObject ho = dx::HitObject::MakeNop();
106+
uint cid = ho.GetClusterID();
107+
outbuf.Store(12, cid);
108+
}
109+
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
// REQUIRES: dxil-1-10
2+
// RUN: %dxc -T lib_6_10 %s | FileCheck %s
3+
4+
// Test CLUSTER_ID_INVALID constant
5+
6+
RWByteAddressBuffer outbuf : register(u0);
7+
8+
struct [raypayload] Payload {
9+
float dummy : read(caller, closesthit, miss, anyhit) : write(caller, closesthit, miss, anyhit);
10+
};
11+
12+
// CHECK-LABEL: define void @{{.*}}test_cluster_id_invalid{{.*}}(
13+
// CHECK: %[[CID:[0-9]+]] = call i32 @dx.op.clusterID(i32 -2147483645)
14+
// CHECK: %[[CMP:[0-9]+]] = icmp eq i32 %[[CID]], -1
15+
// CHECK: br i1 %[[CMP]]
16+
// CHECK: call void @dx.op.rawBufferStore.i32(i32 140, %dx.types.Handle %{{[0-9]+}}, i32 0, i32 undef, i32 -1, i32 undef, i32 undef, i32 undef, i8 1, i32 4)
17+
// CHECK: call void @dx.op.rawBufferStore.i32(i32 140, %dx.types.Handle %{{[0-9]+}}, i32 0, i32 undef, i32 %[[CID]], i32 undef, i32 undef, i32 undef, i8 1, i32 4)
18+
[shader("closesthit")]
19+
void test_cluster_id_invalid(inout Payload payload, in BuiltInTriangleIntersectionAttributes attr) {
20+
uint cid = ClusterID();
21+
22+
// Test the CLUSTER_ID_INVALID constant (0xffffffff = -1 as signed)
23+
if (cid == CLUSTER_ID_INVALID) {
24+
outbuf.Store(0, CLUSTER_ID_INVALID);
25+
} else {
26+
outbuf.Store(0, cid);
27+
}
28+
}
29+
30+
// CHECK-LABEL: define void @{{.*}}test_constant_value{{.*}}(
31+
// CHECK: call void @dx.op.rawBufferStore.i32(i32 140, %dx.types.Handle %{{[0-9]+}}, i32 0, i32 undef, i32 -1, i32 undef, i32 undef, i32 undef, i8 1, i32 4)
32+
[shader("raygeneration")]
33+
void test_constant_value() {
34+
// Verify the constant value is 0xffffffff
35+
outbuf.Store(0, CLUSTER_ID_INVALID);
36+
}
37+

0 commit comments

Comments
 (0)