Skip to content

Commit

Permalink
add validation and tests
Browse files Browse the repository at this point in the history
  • Loading branch information
bob80905 committed Dec 14, 2023
1 parent ad3958c commit 0043cea
Show file tree
Hide file tree
Showing 6 changed files with 301 additions and 3,417 deletions.
3,361 changes: 0 additions & 3,361 deletions docs/DXIL.rst

Large diffs are not rendered by default.

192 changes: 136 additions & 56 deletions lib/HLSL/DxilValidation.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2333,7 +2333,7 @@ static void ValidateDxilOperationCallInProfile(CallInst *CI,
DXIL::ResourceClass::UAV)
ValCtx.EmitInstrError(CI, ValidationRule::InstrAtomicIntrinNonUAV);
} break;
case DXIL::OpCode::CreateHandle:
case DXIL::OpCode::CreateHandle: {
if (ValCtx.isLibProfile) {
ValCtx.EmitInstrFormatError(CI, ValidationRule::SmOpcodeInInvalidFunction,
{"CreateHandle", "non-library targets"});
Expand All @@ -2345,7 +2345,83 @@ static void ValidateDxilOperationCallInProfile(CallInst *CI,
CI, ValidationRule::SmOpcodeInInvalidFunction,
{"CreateHandle", "Shader model 6.5 and below"});
}
} break;

// this intrinsic is generated when the SV_DispatchThreadID system value is used
case DXIL::OpCode::ThreadId: {
// get the node launch type
DxilModule &DM = ValCtx.DxilMod;
if (!DM.HasDxilEntryProps(F)) {
break;
}

DxilEntryProps &entryProps = DM.GetDxilEntryProps(F);
DXIL::NodeLaunchType NLT = entryProps.props.Node.LaunchType;
if (NLT == DXIL::NodeLaunchType::Thread || NLT == DXIL::NodeLaunchType::Coalescing) {
ValCtx.EmitInstrFormatError(CI, ValidationRule::InstrInvalidSVInFunction,
{"ThreadId", NLT ==
DXIL::NodeLaunchType::Thread
? "Thread"
: "Coalescing"});
}
} break;
// this intrinsic is generated when the SV_GroupId
// system value is used

case DXIL::OpCode::GroupId: {
// get the node launch type
DxilModule &DM = ValCtx.DxilMod;
if (!DM.HasDxilEntryProps(F)) {
break;
}

DxilEntryProps &entryProps = DM.GetDxilEntryProps(F);
DXIL::NodeLaunchType NLT = entryProps.props.Node.LaunchType;
if (NLT == DXIL::NodeLaunchType::Thread || NLT == DXIL::NodeLaunchType::Coalescing) {
ValCtx.EmitInstrFormatError(CI, ValidationRule::InstrInvalidSVInFunction,
{"GroupId", NLT ==
DXIL::NodeLaunchType::Thread
? "Thread"
: "Coalescing"});
}
}
break;

// this intrinsic is generated when the SV_GroupThreadID
// system value is used
case DXIL::OpCode::ThreadIdInGroup: {
// get the node launch type
DxilModule &DM = ValCtx.DxilMod;
if (!DM.HasDxilEntryProps(F)) {
break;
}

DxilEntryProps &entryProps = DM.GetDxilEntryProps(F);
DXIL::NodeLaunchType NLT = entryProps.props.Node.LaunchType;
if (NLT == DXIL::NodeLaunchType::Thread) {
ValCtx.EmitInstrFormatError(
CI, ValidationRule::InstrInvalidSVInFunction,
{"ThreadIdInGroup", "Thread"});
}
} break;

// this intrinsic is generated when the SV_GroupIndex
// system value is used
case DXIL::OpCode::FlattenedThreadIdInGroup: {
// get the node launch type
DxilModule &DM = ValCtx.DxilMod;
if (!DM.HasDxilEntryProps(F)) {
break;
}

DxilEntryProps &entryProps = DM.GetDxilEntryProps(F);
DXIL::NodeLaunchType NLT = entryProps.props.Node.LaunchType;
if (NLT == DXIL::NodeLaunchType::Thread) {
ValCtx.EmitInstrFormatError(
CI, ValidationRule::InstrInvalidSVInFunction,
{"FlattenedThreadIdInGroup", "Thread"});
}
} break;
default:
// TODO: make sure every opcode is checked.
// Skip opcodes don't need special check.
Expand Down Expand Up @@ -3463,6 +3539,62 @@ static void ValidateNodeInputRecord(Function *F, ValidationContext &ValCtx) {
}
}

static void ValidateFunctionArgs(Function& F, unsigned numUDTShaderArgs, DXIL::ShaderKind shaderKind, ValidationContext& ValCtx) {

auto ArgFormatError = [&](Function &F, Argument &arg, ValidationRule rule) {
if (arg.hasName())
ValCtx.EmitFnFormatError(&F, rule, {arg.getName().str(), F.getName()});
else
ValCtx.EmitFnFormatError(&F, rule,
{std::to_string(arg.getArgNo()), F.getName()});
};

unsigned numArgs = 0;
for (auto &arg : F.args()) {
Type *argTy = arg.getType();
if (argTy->isPointerTy())
argTy = argTy->getPointerElementType();

numArgs++;
if (numUDTShaderArgs) {
if (arg.getArgNo() >= numUDTShaderArgs) {
ArgFormatError(F, arg, ValidationRule::DeclExtraArgs);
} else if (!argTy->isStructTy()) {
switch (shaderKind) {
case DXIL::ShaderKind::Callable:
ArgFormatError(F, arg, ValidationRule::DeclParamStruct);
break;
default:
ArgFormatError(F, arg,
arg.getArgNo() == 0 ? ValidationRule::DeclPayloadStruct
: ValidationRule::DeclAttrStruct);
}
}
continue;
}

while (argTy->isArrayTy()) {
argTy = argTy->getArrayElementType();
}

if (argTy->isStructTy() && !ValCtx.isLibProfile) {
ArgFormatError(F, arg, ValidationRule::DeclFnFlattenParam);
break;
}
}

if (numArgs < numUDTShaderArgs && shaderKind != DXIL::ShaderKind::Node) {
StringRef argType[2] = {
shaderKind == DXIL::ShaderKind::Callable ? "params" : "payload",
"attributes"};
for (unsigned i = numArgs; i < numUDTShaderArgs; i++) {
ValCtx.EmitFnFormatError(
&F, ValidationRule::DeclShaderMissingArg,
{ShaderModel::GetKindName(shaderKind), F.getName(), argType[i]});
}
}
}

static void ValidateFunction(Function &F, ValidationContext &ValCtx) {
if (F.isDeclaration()) {
ValidateExternalFunction(&F, ValCtx);
Expand Down Expand Up @@ -3494,7 +3626,7 @@ static void ValidateFunction(Function &F, ValidationContext &ValCtx) {
}
}
break;
}
}
default:
break;
}
Expand All @@ -3510,62 +3642,10 @@ static void ValidateFunction(Function &F, ValidationContext &ValCtx) {
// Shader functions should return void.
if (isShader && !F.getReturnType()->isVoidTy())
ValCtx.EmitFnFormatError(&F, ValidationRule::DeclShaderReturnVoid,
{F.getName()});

auto ArgFormatError = [&](Function &F, Argument &arg, ValidationRule rule) {
if (arg.hasName())
ValCtx.EmitFnFormatError(&F, rule, {arg.getName().str(), F.getName()});
else
ValCtx.EmitFnFormatError(&F, rule,
{std::to_string(arg.getArgNo()), F.getName()});
};
{F.getName()});

// Validate parameter type.
unsigned numArgs = 0;
for (auto &arg : F.args()) {
Type *argTy = arg.getType();
if (argTy->isPointerTy())
argTy = argTy->getPointerElementType();

numArgs++;
if (numUDTShaderArgs) {
if (arg.getArgNo() >= numUDTShaderArgs) {
ArgFormatError(F, arg, ValidationRule::DeclExtraArgs);
} else if (!argTy->isStructTy()) {
switch (shaderKind) {
case DXIL::ShaderKind::Callable:
ArgFormatError(F, arg, ValidationRule::DeclParamStruct);
break;
default:
ArgFormatError(F, arg,
arg.getArgNo() == 0
? ValidationRule::DeclPayloadStruct
: ValidationRule::DeclAttrStruct);
}
}
continue;
}

while (argTy->isArrayTy()) {
argTy = argTy->getArrayElementType();
}

if (argTy->isStructTy() && !ValCtx.isLibProfile) {
ArgFormatError(F, arg, ValidationRule::DeclFnFlattenParam);
break;
}
}

if (numArgs < numUDTShaderArgs && shaderKind != DXIL::ShaderKind::Node) {
StringRef argType[2] = {
shaderKind == DXIL::ShaderKind::Callable ? "params" : "payload",
"attributes"};
for (unsigned i = numArgs; i < numUDTShaderArgs; i++) {
ValCtx.EmitFnFormatError(
&F, ValidationRule::DeclShaderMissingArg,
{ShaderModel::GetKindName(shaderKind), F.getName(), argType[i]});
}
}
ValidateFunctionArgs(F, numUDTShaderArgs, shaderKind, ValCtx);

if (ValCtx.DxilMod.HasDxilFunctionProps(&F) &&
ValCtx.DxilMod.GetDxilFunctionProps(&F).IsNode()) {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
; RUN: %dxv %s

; There should be no errors!

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"

define void @entry2() {
%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 ()* @entry2, !5}
!5 = !{!6}
!6 = !{i32 0, !7, !7}
!7 = !{}
!8 = !{null, !"", null, null, null}
!9 = !{void ()* @entry2, !"entry2", null, null, !10}
!10 = !{i32 8, i32 15, i32 13, i32 1, i32 15, !11, i32 16, i32 -1, i32 18, !12, i32 4, !12, i32 5, !13}
!11 = !{!"entry2", 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

; this file comes from compiling launch_types.hlsl with:
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
; 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 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 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

; this file comes from compiling launch_types.hlsl with:
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
; 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 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 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 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 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

; this file comes from compiling launch_types.hlsl with:
Loading

0 comments on commit 0043cea

Please sign in to comment.