Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion include/dxc/HlslIntrinsicOp.h
Original file line number Diff line number Diff line change
Expand Up @@ -369,9 +369,9 @@ enum class IntrinsicOp {
MOP_TraceRayInline = 325,
MOP_WorldRayDirection = 326,
MOP_WorldRayOrigin = 327,
MOP_DxHitObject_ClusterID = 400,
MOP_DxHitObject_FromRayQuery = 363,
MOP_DxHitObject_GetAttributes = 364,
MOP_DxHitObject_GetClusterID = 400,
MOP_DxHitObject_GetGeometryIndex = 365,
MOP_DxHitObject_GetHitKind = 366,
MOP_DxHitObject_GetInstanceID = 367,
Expand Down
19 changes: 19 additions & 0 deletions lib/DxilValidation/DxilValidation.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2349,6 +2349,25 @@ static void ValidateDxilOperationCallInProfile(CallInst *CI,
ValCtx.EmitInstrError(CI, ValidationRule::InstrNoReadingUninitialized);
DxilInst_HitObject_TraceRay HOTraceRay(CI);
} break;

// Clustered Geometry intrinsics
case DXIL::OpCode::RayQuery_CandidateClusterID:
case DXIL::OpCode::RayQuery_CommittedClusterID: {
// Validate rayQueryHandle is not undef
Value *RayQueryHandle = CI->getArgOperand(1);
if (isa<UndefValue>(RayQueryHandle))
ValCtx.EmitInstrError(CI, ValidationRule::InstrNoReadingUninitialized);
break;
}

case DXIL::OpCode::HitObject_ClusterID: {
// Validate HitObject is not undef
Value *HitObject = CI->getArgOperand(1);
if (isa<UndefValue>(HitObject))
ValCtx.EmitInstrError(CI, ValidationRule::InstrUndefHitObject);
break;
}

case DXIL::OpCode::AtomicBinOp:
case DXIL::OpCode::AtomicCompareExchange: {
Type *pOverloadType = OP::GetOverloadType(Opcode, CI->getCalledFunction());
Expand Down
23 changes: 19 additions & 4 deletions lib/HLSL/HLOperationLower.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1327,6 +1327,20 @@ Value *TrivialNoArgWithRetOperation(CallInst *CI, IntrinsicOp IOP,
return dxilOp;
}

Value *TrivialNoArgWithRetNoOverloadOperation(
CallInst *CI, IntrinsicOp IOP, OP::OpCode opcode,
HLOperationLowerHelper &helper, HLObjectOperationLowerHelper *pObjHelper,
bool &Translated) {
hlsl::OP *hlslOP = &helper.hlslOP;
Type *Ty = CI->getType();

Constant *opArg = hlslOP->GetU32Const((unsigned)opcode);
Value *args[] = {opArg};
IRBuilder<> Builder(CI);
return TrivialDxilOperation(opcode, args, Builder.getVoidTy(), Ty, hlslOP,
Builder);
}

Value *TranslateGetRTSamplePos(CallInst *CI, IntrinsicOp IOP, OP::OpCode op,
HLOperationLowerHelper &helper,
HLObjectOperationLowerHelper *pObjHelper,
Expand Down Expand Up @@ -7520,12 +7534,13 @@ constexpr IntrinsicLower gLowerTable[] = {
{IntrinsicOp::IOP_GetGroupWaveIndex, TranslateWaveToVal,
DXIL::OpCode::GetGroupWaveIndex},

{IntrinsicOp::IOP_ClusterID, EmptyLower, DXIL::OpCode::ClusterID},
{IntrinsicOp::MOP_CandidateClusterID, EmptyLower,
{IntrinsicOp::IOP_ClusterID, TrivialNoArgWithRetNoOverloadOperation,
DXIL::OpCode::ClusterID},
{IntrinsicOp::MOP_CandidateClusterID, TranslateGenericRayQueryMethod,
DXIL::OpCode::RayQuery_CandidateClusterID},
{IntrinsicOp::MOP_CommittedClusterID, EmptyLower,
{IntrinsicOp::MOP_CommittedClusterID, TranslateGenericRayQueryMethod,
DXIL::OpCode::RayQuery_CommittedClusterID},
{IntrinsicOp::MOP_DxHitObject_ClusterID, EmptyLower,
{IntrinsicOp::MOP_DxHitObject_GetClusterID, TranslateHitObjectScalarGetter,
DXIL::OpCode::HitObject_ClusterID},

{IntrinsicOp::IOP_TriangleObjectPosition, EmptyLower,
Expand Down
3 changes: 3 additions & 0 deletions tools/clang/lib/AST/ASTContextHLSL.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -662,6 +662,9 @@ void hlsl::AddRaytracingConstants(ASTContext &context) {
AddConstUInt(context, StringRef("HIT_KIND_TRIANGLE_BACK_FACE"),
(unsigned)DXIL::HitKind::TriangleBackFace);

// static const uint CLUSTER_ID_INVALID = 0xffffffff;
AddConstUInt(context, StringRef("CLUSTER_ID_INVALID"), 0xffffffff);

AddConstUInt(
context,
StringRef(
Expand Down
21 changes: 21 additions & 0 deletions tools/clang/lib/Sema/SemaHLSLDiagnoseTU.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -436,6 +436,15 @@ class HLSLReachableDiagnoseVisitor
return true;
}

bool VisitMemberExpr(MemberExpr *ME) {
// Diagnose availability for member function calls.
if (AvailabilityAttr *AAttr = GetAvailabilityAttrOnce(ME)) {
DiagnoseAvailability(AAttr, ME->getMemberDecl(), ME->getExprLoc());
}

return true;
}

AvailabilityAttr *GetAvailabilityAttrOnce(TypeLoc TL) {
QualType Ty = TL.getType();
CXXRecordDecl *RD = Ty->getAsCXXRecordDecl();
Expand Down Expand Up @@ -463,6 +472,18 @@ class HLSLReachableDiagnoseVisitor
return AAttr;
}

AvailabilityAttr *GetAvailabilityAttrOnce(MemberExpr *ME) {
AvailabilityAttr *AAttr = ME->getMemberDecl()->getAttr<AvailabilityAttr>();
if (!AAttr)
return nullptr;
// Skip redundant availability diagnostics for the same member.
// Use the member location to track if we've already diagnosed this.
if (!DiagnosedTypeLocs.insert(ME->getMemberLoc()).second)
return nullptr;

return AAttr;
}

bool CheckSMVersion(VersionTuple AAttrVT) {
VersionTuple SMVT = VersionTuple(SM->GetMajor(), SM->GetMinor());
return SMVT >= AAttrVT;
Expand Down
109 changes: 109 additions & 0 deletions tools/clang/test/CodeGenDXIL/hlsl/intrinsics/clusterid.hlsl
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
// REQUIRES: dxil-1-10
// RUN: %dxc -T lib_6_10 %s | FileCheck %s
// RUN: %dxc -T lib_6_10 %s -ast-dump-implicit | FileCheck %s --check-prefix AST
// RUN: %dxc -T lib_6_10 %s -fcgl | FileCheck %s --check-prefix FCGL

// Test ClusterID intrinsics for SM 6.10

// AST: `-CXXMethodDecl {{.*}} used GetClusterID 'unsigned int ()' extern
// AST-NEXT: {{.*}}|-TemplateArgument type 'unsigned int'
// AST-NEXT: {{.*}}|-HLSLIntrinsicAttr {{.*}} Implicit "op" "" 400
// AST-NEXT: {{.*}}|-ConstAttr {{.*}} Implicit
// AST-NEXT: {{.*}}`-AvailabilityAttr {{.*}} Implicit 6.10 0 0 ""

// AST: `-CXXMethodDecl {{.*}} used CandidateClusterID 'unsigned int ()' extern
// AST-NEXT: {{.*}}|-TemplateArgument type 'unsigned int'
// AST-NEXT: {{.*}}|-HLSLIntrinsicAttr {{.*}} Implicit "op" "" 398
// AST-NEXT: {{.*}}|-PureAttr {{.*}} Implicit
// AST-NEXT: {{.*}}`-AvailabilityAttr {{.*}} Implicit 6.10 0 0 ""

// AST: `-CXXMethodDecl {{.*}} used CommittedClusterID 'unsigned int ()' extern
// AST-NEXT: {{.*}}|-TemplateArgument type 'unsigned int'
// AST-NEXT: {{.*}}|-HLSLIntrinsicAttr {{.*}} Implicit "op" "" 399
// AST-NEXT: {{.*}}|-PureAttr {{.*}} Implicit
// AST-NEXT: {{.*}}`-AvailabilityAttr {{.*}} Implicit 6.10 0 0 ""

// AST: -FunctionDecl {{.*}} implicit used ClusterID 'unsigned int ()' extern
// AST-NEXT: {{.*}}|-HLSLIntrinsicAttr {{.*}} Implicit "op" "" 397
// AST-NEXT: {{.*}}|-ConstAttr {{.*}} Implicit
// AST-NEXT: {{.*}}|-AvailabilityAttr {{.*}} Implicit 6.10 0 0 ""
// AST-NEXT: {{.*}}`-HLSLBuiltinCallAttr {{.*}} Implicit

RWByteAddressBuffer outbuf : register(u0);

struct [raypayload] Payload {
float dummy : read(caller, closesthit, miss, anyhit) : write(caller, closesthit, miss, anyhit);
};

// Global ClusterID intrinsic
// CHECK-LABEL: define void @{{.*}}test_cluster_id{{.*}}(
// CHECK: call i32 @dx.op.clusterID(i32 -2147483645)
// CHECK: call void @dx.op.rawBufferStore.i32

// FCGL-LABEL: define void @{{.*}}test_cluster_id{{.*}}(
// FCGL: call i32 @"dx.hl.op.rn.i32 (i32)"(i32 397)
[shader("closesthit")]
void test_cluster_id(inout Payload payload, in BuiltInTriangleIntersectionAttributes attr) {
uint cid = ClusterID();
outbuf.Store(0, cid);
}

// RayQuery CandidateClusterID
// CHECK-LABEL: define void @{{.*}}test_rayquery_candidate_cluster_id{{.*}}(
// CHECK: call i32 @dx.op.rayQuery_StateScalar.i32(i32 -2147483644
// CHECK: call void @dx.op.rawBufferStore.i32

// FCGL-LABEL: define void @{{.*}}test_rayquery_candidate_cluster_id{{.*}}(
// FCGL: call i32 @"dx.hl.op.ro.i32 (i32, %{{.*}}"(i32 398
[shader("raygeneration")]
void test_rayquery_candidate_cluster_id() {
RayQuery<RAY_FLAG_NONE> rq;
RaytracingAccelerationStructure as;
RayDesc ray;
ray.Origin = float3(0, 0, 0);
ray.Direction = float3(0, 0, 1);
ray.TMin = 0.0;
ray.TMax = 1000.0;

rq.TraceRayInline(as, 0, 0xff, ray);
rq.Proceed();
uint cid = rq.CandidateClusterID();
outbuf.Store(4, cid);
}

// RayQuery CommittedClusterID
// CHECK-LABEL: define void @{{.*}}test_rayquery_committed_cluster_id{{.*}}(
// CHECK: call i32 @dx.op.rayQuery_StateScalar.i32(i32 -2147483643
// CHECK: call void @dx.op.rawBufferStore.i32

// FCGL-LABEL: define void @{{.*}}test_rayquery_committed_cluster_id{{.*}}(
// FCGL: call i32 @"dx.hl.op.ro.i32 (i32, %{{.*}}"(i32 399
[shader("raygeneration")]
void test_rayquery_committed_cluster_id() {
RayQuery<RAY_FLAG_NONE> rq;
RaytracingAccelerationStructure as;
RayDesc ray;
ray.Origin = float3(0, 0, 0);
ray.Direction = float3(0, 0, 1);
ray.TMin = 0.0;
ray.TMax = 1000.0;

rq.TraceRayInline(as, 0, 0xff, ray);
uint cid = rq.CommittedClusterID();
outbuf.Store(8, cid);
}

// HitObject GetClusterID
// CHECK-LABEL: define void @{{.*}}test_hitobject_cluster_id{{.*}}(
// CHECK: call i32 @dx.op.hitObject_StateScalar.i32(i32 -2147483642
// CHECK: call void @dx.op.rawBufferStore.i32

// FCGL-LABEL: define void @{{.*}}test_hitobject_cluster_id{{.*}}(
// FCGL: call i32 @"dx.hl.op.rn.i32 (i32, %dx.types.HitObject{{.*}}"(i32 400
[shader("raygeneration")]
void test_hitobject_cluster_id() {
dx::HitObject ho = dx::HitObject::MakeNop();
uint cid = ho.GetClusterID();
outbuf.Store(12, cid);
}

Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
// REQUIRES: dxil-1-10
// RUN: %dxc -T lib_6_10 %s | FileCheck %s

// Test CLUSTER_ID_INVALID constant

RWByteAddressBuffer outbuf : register(u0);

struct [raypayload] Payload {
float dummy : read(caller, closesthit, miss, anyhit) : write(caller, closesthit, miss, anyhit);
};

// CHECK-LABEL: define void @{{.*}}test_cluster_id_invalid{{.*}}(
// CHECK: %[[CID:[0-9]+]] = call i32 @dx.op.clusterID(i32 -2147483645)
// CHECK: %[[CMP:[0-9]+]] = icmp eq i32 %[[CID]], -1
// CHECK: br i1 %[[CMP]]
// 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)
// 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)
[shader("closesthit")]
void test_cluster_id_invalid(inout Payload payload, in BuiltInTriangleIntersectionAttributes attr) {
uint cid = ClusterID();

// Test the CLUSTER_ID_INVALID constant (0xffffffff = -1 as signed)
if (cid == CLUSTER_ID_INVALID) {
outbuf.Store(0, CLUSTER_ID_INVALID);
} else {
outbuf.Store(0, cid);
}
}

// CHECK-LABEL: define void @{{.*}}test_constant_value{{.*}}(
// 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)
[shader("raygeneration")]
void test_constant_value() {
// Verify the constant value is 0xffffffff
outbuf.Store(0, CLUSTER_ID_INVALID);
}

Loading