Skip to content
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

[Validation] Add validation and tests for invalid system values in incompatible node launch type #6108

Merged
1 change: 1 addition & 0 deletions docs/DXIL.rst
Original file line number Diff line number Diff line change
Expand Up @@ -3124,6 +3124,7 @@ INSTR.SAMPLERMODEFORSAMPLEC sample_c_*/gather_c instructions requi
INSTR.SIGNATUREOPERATIONNOTINENTRY Dxil operation for input output signature must be in entryPoints.
INSTR.STATUS Resource status should only be used by CheckAccessFullyMapped.
INSTR.STRUCTBITCAST Bitcast on struct types is not allowed.
INSTR.SVCONFLICTINGLAUNCHMODE Input system values are compatible with node shader launch mode.
INSTR.TEXTUREOFFSET offset texture instructions must take offset which can resolve to integer literal in the range -8 to 7.
INSTR.TGSMRACECOND Race condition writing to shared memory detected, consider making this write conditional.
INSTR.UNDEFINEDVALUEFORUAVSTORE Assignment of undefined values to UAV.
Expand Down
82 changes: 79 additions & 3 deletions lib/HLSL/DxilValidation.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2134,17 +2134,35 @@ static void ValidateBarrierFlagArg(ValidationContext &ValCtx, CallInst *CI,
}
}

std::string GetLaunchTypeStr(DXIL::NodeLaunchType LT) {
switch (LT) {
case DXIL::NodeLaunchType::Broadcasting:
return "Broadcasting";
case DXIL::NodeLaunchType::Coalescing:
return "Coalescing";
case DXIL::NodeLaunchType::Thread:
return "Thread";
default:
return "Invalid";
}
}

static void ValidateDxilOperationCallInProfile(CallInst *CI,
DXIL::OpCode opcode,
const ShaderModel *pSM,
ValidationContext &ValCtx) {
DXIL::ShaderKind shaderKind =
pSM ? pSM->GetKind() : DXIL::ShaderKind::Invalid;
llvm::Function *F = CI->getParent()->getParent();
DXIL::NodeLaunchType nodeLaunchType = DXIL::NodeLaunchType::Invalid;
if (DXIL::ShaderKind::Library == shaderKind) {
if (ValCtx.DxilMod.HasDxilFunctionProps(F))
if (ValCtx.DxilMod.HasDxilFunctionProps(F)) {
DxilEntryProps &entryProps = ValCtx.DxilMod.GetDxilEntryProps(F);
shaderKind = ValCtx.DxilMod.GetDxilFunctionProps(F).shaderKind;
else if (ValCtx.DxilMod.IsPatchConstantShader(F))
if (shaderKind == DXIL::ShaderKind::Node)
nodeLaunchType = entryProps.props.Node.LaunchType;

} else if (ValCtx.DxilMod.IsPatchConstantShader(F))
shaderKind = DXIL::ShaderKind::Hull;
}

Expand Down Expand Up @@ -2346,6 +2364,65 @@ static void ValidateDxilOperationCallInProfile(CallInst *CI,
{"CreateHandle", "Shader model 6.5 and below"});
}
break;

case DXIL::OpCode::ThreadId: // SV_DispatchThreadID
if (shaderKind != DXIL::ShaderKind::Node) {
break;
}

if (nodeLaunchType == DXIL::NodeLaunchType::Broadcasting)
break;

ValCtx.EmitInstrFormatError(
CI, ValidationRule::InstrSVConflictingLaunchMode,
{"ThreadId", "SV_DispatchThreadID", GetLaunchTypeStr(nodeLaunchType)});
break;

case DXIL::OpCode::GroupId: // SV_GroupId
if (shaderKind != DXIL::ShaderKind::Node) {
break;
}

if (nodeLaunchType == DXIL::NodeLaunchType::Broadcasting)
break;

ValCtx.EmitInstrFormatError(
CI, ValidationRule::InstrSVConflictingLaunchMode,
{"GroupId", "SV_GroupId", GetLaunchTypeStr(nodeLaunchType)});
break;

case DXIL::OpCode::ThreadIdInGroup: // SV_GroupThreadID
if (shaderKind != DXIL::ShaderKind::Node) {
break;
}

if (nodeLaunchType == DXIL::NodeLaunchType::Broadcasting ||
nodeLaunchType == DXIL::NodeLaunchType::Coalescing)
break;

ValCtx.EmitInstrFormatError(CI,
ValidationRule::InstrSVConflictingLaunchMode,
{"ThreadIdInGroup", "SV_GroupThreadID",
GetLaunchTypeStr(nodeLaunchType)});

break;

case DXIL::OpCode::FlattenedThreadIdInGroup: // SV_GroupIndex
if (shaderKind != DXIL::ShaderKind::Node) {
break;
}

if (nodeLaunchType == DXIL::NodeLaunchType::Broadcasting ||
nodeLaunchType == DXIL::NodeLaunchType::Coalescing)
break;

ValCtx.EmitInstrFormatError(CI,
ValidationRule::InstrSVConflictingLaunchMode,
{"FlattenedThreadIdInGroup", "SV_GroupIndex",
GetLaunchTypeStr(nodeLaunchType)});

break;

default:
// TODO: make sure every opcode is checked.
// Skip opcodes don't need special check.
Expand Down Expand Up @@ -3520,7 +3597,6 @@ static void ValidateFunction(Function &F, ValidationContext &ValCtx) {
{std::to_string(arg.getArgNo()), F.getName()});
};

// Validate parameter type.
unsigned numArgs = 0;
for (auto &arg : F.args()) {
Type *argTy = arg.getType();
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
; RUN: %dxv %s | FileCheck %s

target datalayout = "e-m:e-p:32:32-i1:32-i8:32-i16:32-i32:32-i64:64-f16:32-f32:32-f64:64-n8:16:32:64"
target triple = "dxil-ms-dx"

; CHECK: Function: entry3: error: Call to DXIL intrinsic ThreadId (SV_DispatchThreadID) is not allowed in node shader launch type Coalescing
; CHECK: note: at '%1 = call i32 @dx.op.threadId.i32(i32 93, i32 1)' in block '#0' of function 'entry3'.
; CHECK: Function: entry3: error: Call to DXIL intrinsic GroupId (SV_GroupId) is not allowed in node shader launch type Coalescing
; CHECK: note: at '%2 = call i32 @dx.op.groupId.i32(i32 94, i32 2)' in block '#0' of function 'entry3'.

define void @entry3() {
%1 = call i32 @dx.op.threadId.i32(i32 93, i32 1)
%2 = call i32 @dx.op.groupId.i32(i32 94, i32 2)
%3 = call i32 @dx.op.threadIdInGroup.i32(i32 95, i32 1)
%4 = call i32 @dx.op.flattenedThreadIdInGroup.i32(i32 96)
ret void
}

!llvm.ident = !{!0}
!dx.version = !{!1}
!dx.valver = !{!2}
!dx.shaderModel = !{!3}
!dx.typeAnnotations = !{!4}
!dx.entryPoints = !{!8, !9}

!0 = !{!"dxc(private) 1.7.0.14317 (main, e3c311409675)"}
!1 = !{i32 1, i32 3}
!2 = !{i32 1, i32 8}
!3 = !{!"lib", i32 6, i32 3}
!4 = !{i32 1, void ()* @entry3, !5}
!5 = !{!6}
!6 = !{i32 0, !7, !7}
!7 = !{}
!8 = !{null, !"", null, null, null}
!9 = !{void ()* @entry3, !"entry3", null, null, !10}
!10 = !{i32 8, i32 15, i32 13, i32 2, i32 15, !11, i32 16, i32 -1, i32 4, !12, i32 5, !13}
!11 = !{!"entry3", i32 0}
!12 = !{i32 1, i32 1, i32 1}
!13 = !{i32 0}

; Function Attrs: nounwind readnone
declare i32 @dx.op.threadId.i32(i32, i32) #1

; Function Attrs: nounwind readnone
declare i32 @dx.op.groupId.i32(i32, i32) #1

; Function Attrs: nounwind readnone
declare i32 @dx.op.threadIdInGroup.i32(i32, i32) #0

; Function Attrs: nounwind readnone
declare i32 @dx.op.flattenedThreadIdInGroup.i32(i32) #0
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
; RUN: %dxv %s | FileCheck %s

target datalayout = "e-m:e-p:32:32-i1:32-i8:32-i16:32-i32:32-i64:64-f16:32-f32:32-f64:64-n8:16:32:64"
target triple = "dxil-ms-dx"

; CHECK: Function: entry: error: Call to DXIL intrinsic ThreadId (SV_DispatchThreadID) is not allowed in node shader launch type Thread
; CHECK: note: at '%1 = call i32 @dx.op.threadId.i32(i32 93, i32 1)' in block '#0' of function 'entry'.
; CHECK: Function: entry: error: Call to DXIL intrinsic GroupId (SV_GroupId) is not allowed in node shader launch type Thread
; CHECK: note: at '%2 = call i32 @dx.op.groupId.i32(i32 94, i32 2)' in block '#0' of function 'entry'.
; CHECK: Function: entry: error: Call to DXIL intrinsic ThreadIdInGroup (SV_GroupThreadID) is not allowed in node shader launch type Thread
; CHECK: note: at '%3 = call i32 @dx.op.threadIdInGroup.i32(i32 95, i32 1)' in block '#0' of function 'entry'.
; CHECK: Function: entry: error: Call to DXIL intrinsic FlattenedThreadIdInGroup (SV_GroupIndex) is not allowed in node shader launch type Thread
; CHECK: note: at '%4 = call i32 @dx.op.flattenedThreadIdInGroup.i32(i32 96)' in block '#0' of function 'entry'.

define void @entry() {
%1 = call i32 @dx.op.threadId.i32(i32 93, i32 1)
%2 = call i32 @dx.op.groupId.i32(i32 94, i32 2)
%3 = call i32 @dx.op.threadIdInGroup.i32(i32 95, i32 1)
%4 = call i32 @dx.op.flattenedThreadIdInGroup.i32(i32 96)
ret void
}

!llvm.ident = !{!0}
!dx.version = !{!1}
!dx.valver = !{!2}
!dx.shaderModel = !{!3}
!dx.typeAnnotations = !{!4}
!dx.entryPoints = !{!8, !9}

!0 = !{!"dxc(private) 1.7.0.14317 (main, e3c311409675)"}
!1 = !{i32 1, i32 3}
!2 = !{i32 1, i32 8}
!3 = !{!"lib", i32 6, i32 3}
!4 = !{i32 1, void ()* @entry, !5}
!5 = !{!6}
!6 = !{i32 0, !7, !7}
!7 = !{}
!8 = !{null, !"", null, null, null}
!9 = !{void ()* @entry, !"entry", null, null, !10}
!10 = !{i32 8, i32 15, i32 13, i32 3, i32 15, !11, i32 16, i32 -1, i32 4, !12, i32 5, !13}
!11 = !{!"entry", i32 0}
!12 = !{i32 1, i32 1, i32 1}
!13 = !{i32 0}

; Function Attrs: nounwind readnone
declare i32 @dx.op.threadId.i32(i32, i32) #1

; Function Attrs: nounwind readnone
declare i32 @dx.op.groupId.i32(i32, i32) #1

; Function Attrs: nounwind readnone
declare i32 @dx.op.threadIdInGroup.i32(i32, i32) #0

; Function Attrs: nounwind readnone
declare i32 @dx.op.flattenedThreadIdInGroup.i32(i32) #0
5 changes: 5 additions & 0 deletions utils/hct/hctdb.py
Original file line number Diff line number Diff line change
Expand Up @@ -7552,6 +7552,11 @@ def build_valrules(self):
self.add_valrule(
"Instr.AtomicIntrinNonUAV", "Non-UAV destination to atomic intrinsic."
)
self.add_valrule_msg(
"Instr.SVConflictingLaunchMode",
"Input system values are compatible with node shader launch mode.",
"Call to DXIL intrinsic %0 (%1) is not allowed in node shader launch type %2"
)
self.add_valrule("Instr.AtomicConst", "Constant destination to atomic.")

# Work-Graphs
Expand Down
Loading