Skip to content

Commit 5dee81c

Browse files
authored
Fix crash in DXIL.dll caused by illegal DXIL intrinsic. (#6302)
Replace assert on illegal DXIL op with return illegal value. Check the illegal cases in validation. Fixes #6168
1 parent 2314d06 commit 5dee81c

File tree

8 files changed

+211
-52
lines changed

8 files changed

+211
-52
lines changed

docs/DXIL.rst

+2
Original file line numberDiff line numberDiff line change
@@ -3080,6 +3080,8 @@ INSTR.EVALINTERPOLATIONMODE Interpolation mode on %0 used with eva
30803080
INSTR.EXTRACTVALUE ExtractValue should only be used on dxil struct types and cmpxchg.
30813081
INSTR.FAILTORESLOVETGSMPOINTER TGSM pointers must originate from an unambiguous TGSM global variable.
30823082
INSTR.HANDLENOTFROMCREATEHANDLE Resource handle should returned by createHandle.
3083+
INSTR.ILLEGALDXILOPCODE DXILOpCode must be [0..%0]. %1 specified.
3084+
INSTR.ILLEGALDXILOPFUNCTION '%0' is not a DXILOpFuncition for DXILOpcode '%1'.
30833085
INSTR.IMMBIASFORSAMPLEB bias amount for sample_b must be in the range [%0,%1], but %2 was specified as an immediate.
30843086
INSTR.INBOUNDSACCESS Access to out-of-bounds memory is disallowed.
30853087
INSTR.MINPRECISIONNOTPRECISE Instructions marked precise may not refer to minprecision values.

lib/DXIL/DxilCounters.cpp

+1-3
Original file line numberDiff line numberDiff line change
@@ -336,9 +336,7 @@ void CountInstructions(llvm::Module &M, DxilCounters &counters) {
336336
}
337337
} else if (CallInst *CI = dyn_cast<CallInst>(I)) {
338338
if (hlsl::OP::IsDxilOpFuncCallInst(CI)) {
339-
unsigned opcode =
340-
(unsigned)llvm::cast<llvm::ConstantInt>(I->getOperand(0))
341-
->getZExtValue();
339+
unsigned opcode = static_cast<unsigned>(hlsl::OP::getOpCode(CI));
342340
CountDxilOp(opcode, counters);
343341
}
344342
} else if (isa<LoadInst>(I) || isa<StoreInst>(I)) {

lib/DXIL/DxilOperations.cpp

+42-40
Original file line numberDiff line numberDiff line change
@@ -2705,8 +2705,6 @@ llvm::StringRef OP::ConstructOverloadName(Type *Ty, DXIL::OpCode opCode,
27052705
}
27062706

27072707
const char *OP::GetOpCodeName(OpCode opCode) {
2708-
DXASSERT(0 <= (unsigned)opCode && opCode < OpCode::NumOpCodes,
2709-
"otherwise caller passed OOB index");
27102708
return m_OpCodeProps[(unsigned)opCode].pOpCodeName;
27112709
}
27122710

@@ -2719,26 +2717,22 @@ const char *OP::GetAtomicOpName(DXIL::AtomicBinOpCode OpCode) {
27192717
}
27202718

27212719
OP::OpCodeClass OP::GetOpCodeClass(OpCode opCode) {
2722-
DXASSERT(0 <= (unsigned)opCode && opCode < OpCode::NumOpCodes,
2723-
"otherwise caller passed OOB index");
27242720
return m_OpCodeProps[(unsigned)opCode].opCodeClass;
27252721
}
27262722

27272723
const char *OP::GetOpCodeClassName(OpCode opCode) {
2728-
DXASSERT(0 <= (unsigned)opCode && opCode < OpCode::NumOpCodes,
2729-
"otherwise caller passed OOB index");
27302724
return m_OpCodeProps[(unsigned)opCode].pOpCodeClassName;
27312725
}
27322726

27332727
llvm::Attribute::AttrKind OP::GetMemAccessAttr(OpCode opCode) {
2734-
DXASSERT(0 <= (unsigned)opCode && opCode < OpCode::NumOpCodes,
2735-
"otherwise caller passed OOB index");
27362728
return m_OpCodeProps[(unsigned)opCode].FuncAttr;
27372729
}
27382730

27392731
bool OP::IsOverloadLegal(OpCode opCode, Type *pType) {
2740-
DXASSERT(0 <= (unsigned)opCode && opCode < OpCode::NumOpCodes,
2741-
"otherwise caller passed OOB index");
2732+
if (!pType)
2733+
return false;
2734+
if (opCode == OpCode::NumOpCodes)
2735+
return false;
27422736
unsigned TypeSlot = GetTypeSlot(pType);
27432737
return TypeSlot != UINT_MAX &&
27442738
m_OpCodeProps[(unsigned)opCode].bAllowOverload[TypeSlot];
@@ -2814,8 +2808,13 @@ bool OP::IsDxilOpFuncCallInst(const llvm::Instruction *I, OpCode opcode) {
28142808
}
28152809

28162810
OP::OpCode OP::getOpCode(const llvm::Instruction *I) {
2817-
return (OP::OpCode)llvm::cast<llvm::ConstantInt>(I->getOperand(0))
2818-
->getZExtValue();
2811+
auto *OpConst = llvm::dyn_cast<llvm::ConstantInt>(I->getOperand(0));
2812+
if (!OpConst)
2813+
return OpCode::NumOpCodes;
2814+
uint64_t OpCodeVal = OpConst->getZExtValue();
2815+
if (OpCodeVal >= static_cast<uint64_t>(OP::OpCode::NumOpCodes))
2816+
return OP::OpCode::NumOpCodes;
2817+
return static_cast<OP::OpCode>(OpCodeVal);
28192818
}
28202819

28212820
OP::OpCode OP::GetDxilOpFuncCallInst(const llvm::Instruction *I) {
@@ -3525,9 +3524,7 @@ void OP::RefreshCache() {
35253524
CallInst *CI = cast<CallInst>(*F.user_begin());
35263525
OpCode OpCode = OP::GetDxilOpFuncCallInst(CI);
35273526
Type *pOverloadType = OP::GetOverloadType(OpCode, &F);
3528-
Function *OpFunc = GetOpFunc(OpCode, pOverloadType);
3529-
(void)(OpFunc);
3530-
DXASSERT_NOMSG(OpFunc == &F);
3527+
GetOpFunc(OpCode, pOverloadType);
35313528
}
35323529
}
35333530
}
@@ -3546,13 +3543,15 @@ void OP::FixOverloadNames() {
35463543
CallInst *CI = cast<CallInst>(*F.user_begin());
35473544
DXIL::OpCode opCode = OP::GetDxilOpFuncCallInst(CI);
35483545
llvm::Type *Ty = OP::GetOverloadType(opCode, &F);
3549-
if (isa<StructType>(Ty) || isa<PointerType>(Ty)) {
3550-
std::string funcName;
3551-
if (OP::ConstructOverloadName(Ty, opCode, funcName)
3552-
.compare(F.getName()) != 0) {
3553-
F.setName(funcName);
3554-
}
3555-
}
3546+
if (!OP::IsOverloadLegal(opCode, Ty))
3547+
continue;
3548+
if (!isa<StructType>(Ty) && !isa<PointerType>(Ty))
3549+
continue;
3550+
3551+
std::string funcName;
3552+
if (OP::ConstructOverloadName(Ty, opCode, funcName)
3553+
.compare(F.getName()) != 0)
3554+
F.setName(funcName);
35563555
}
35573556
}
35583557
}
@@ -3563,12 +3562,11 @@ void OP::UpdateCache(OpCodeClass opClass, Type *Ty, llvm::Function *F) {
35633562
}
35643563

35653564
Function *OP::GetOpFunc(OpCode opCode, Type *pOverloadType) {
3566-
DXASSERT(0 <= (unsigned)opCode && opCode < OpCode::NumOpCodes,
3567-
"otherwise caller passed OOB OpCode");
3568-
assert(0 <= (unsigned)opCode && opCode < OpCode::NumOpCodes);
3569-
DXASSERT(IsOverloadLegal(opCode, pOverloadType),
3570-
"otherwise the caller requested illegal operation overload (eg HLSL "
3571-
"function with unsupported types for mapped intrinsic function)");
3565+
if (opCode == OpCode::NumOpCodes)
3566+
return nullptr;
3567+
if (!IsOverloadLegal(opCode, pOverloadType))
3568+
return nullptr;
3569+
35723570
OpCodeClass opClass = m_OpCodeProps[(unsigned)opCode].opCodeClass;
35733571
Function *&F =
35743572
m_OpCodeClassCache[(unsigned)opClass].pOverloads[pOverloadType];
@@ -5511,8 +5509,8 @@ Function *OP::GetOpFunc(OpCode opCode, Type *pOverloadType) {
55115509
// and return values to ensure that ResRetType is constructed in the
55125510
// RefreshCache case.
55135511
if (Function *existF = m_pModule->getFunction(funcName)) {
5514-
DXASSERT(existF->getFunctionType() == pFT,
5515-
"existing function must have the expected function type");
5512+
if (existF->getFunctionType() != pFT)
5513+
return nullptr;
55165514
F = existF;
55175515
UpdateCache(opClass, pOverloadType, F);
55185516
return F;
@@ -5531,9 +5529,6 @@ Function *OP::GetOpFunc(OpCode opCode, Type *pOverloadType) {
55315529

55325530
const SmallMapVector<llvm::Type *, llvm::Function *, 8> &
55335531
OP::GetOpFuncList(OpCode opCode) const {
5534-
DXASSERT(0 <= (unsigned)opCode && opCode < OpCode::NumOpCodes,
5535-
"otherwise caller passed OOB OpCode");
5536-
assert(0 <= (unsigned)opCode && opCode < OpCode::NumOpCodes);
55375532
return m_OpCodeClassCache[(unsigned)m_OpCodeProps[(unsigned)opCode]
55385533
.opCodeClass]
55395534
.pOverloads;
@@ -5631,7 +5626,8 @@ llvm::Type *OP::GetOverloadType(OpCode opCode, llvm::Function *F) {
56315626
case OpCode::CallShader:
56325627
case OpCode::Pack4x8:
56335628
case OpCode::WaveMatrix_Fill:
5634-
DXASSERT_NOMSG(FT->getNumParams() > 2);
5629+
if (FT->getNumParams() <= 2)
5630+
return nullptr;
56355631
return FT->getParamType(2);
56365632
case OpCode::MinPrecXRegStore:
56375633
case OpCode::StoreOutput:
@@ -5641,7 +5637,8 @@ llvm::Type *OP::GetOverloadType(OpCode opCode, llvm::Function *F) {
56415637
case OpCode::StoreVertexOutput:
56425638
case OpCode::StorePrimitiveOutput:
56435639
case OpCode::DispatchMesh:
5644-
DXASSERT_NOMSG(FT->getNumParams() > 4);
5640+
if (FT->getNumParams() <= 4)
5641+
return nullptr;
56455642
return FT->getParamType(4);
56465643
case OpCode::IsNaN:
56475644
case OpCode::IsInf:
@@ -5659,22 +5656,27 @@ llvm::Type *OP::GetOverloadType(OpCode opCode, llvm::Function *F) {
56595656
case OpCode::WaveActiveAllEqual:
56605657
case OpCode::CreateHandleForLib:
56615658
case OpCode::WaveMatch:
5662-
DXASSERT_NOMSG(FT->getNumParams() > 1);
5659+
if (FT->getNumParams() <= 1)
5660+
return nullptr;
56635661
return FT->getParamType(1);
56645662
case OpCode::TextureStore:
56655663
case OpCode::TextureStoreSample:
5666-
DXASSERT_NOMSG(FT->getNumParams() > 5);
5664+
if (FT->getNumParams() <= 5)
5665+
return nullptr;
56675666
return FT->getParamType(5);
56685667
case OpCode::TraceRay:
5669-
DXASSERT_NOMSG(FT->getNumParams() > 15);
5668+
if (FT->getNumParams() <= 15)
5669+
return nullptr;
56705670
return FT->getParamType(15);
56715671
case OpCode::ReportHit:
56725672
case OpCode::WaveMatrix_ScalarOp:
5673-
DXASSERT_NOMSG(FT->getNumParams() > 3);
5673+
if (FT->getNumParams() <= 3)
5674+
return nullptr;
56745675
return FT->getParamType(3);
56755676
case OpCode::WaveMatrix_LoadGroupShared:
56765677
case OpCode::WaveMatrix_StoreGroupShared:
5677-
DXASSERT_NOMSG(FT->getNumParams() > 2);
5678+
if (FT->getNumParams() <= 2)
5679+
return nullptr;
56785680
return FT->getParamType(2)->getPointerElementType();
56795681
case OpCode::CreateHandle:
56805682
case OpCode::BufferUpdateCounter:

lib/DXIL/DxilShaderFlags.cpp

+3-7
Original file line numberDiff line numberDiff line change
@@ -585,13 +585,9 @@ ShaderFlags ShaderFlags::CollectShaderFlags(const Function *F,
585585
if (const CallInst *CI = dyn_cast<CallInst>(&I)) {
586586
if (!OP::IsDxilOpFunc(CI->getCalledFunction()))
587587
continue;
588-
Value *opcodeArg = CI->getArgOperand(DXIL::OperandIndex::kOpcodeIdx);
589-
ConstantInt *opcodeConst = dyn_cast<ConstantInt>(opcodeArg);
590-
DXASSERT(opcodeConst, "DXIL opcode arg must be immediate");
591-
unsigned opcode = opcodeConst->getLimitedValue();
592-
DXASSERT(opcode < static_cast<unsigned>(DXIL::OpCode::NumOpCodes),
593-
"invalid DXIL opcode");
594-
DXIL::OpCode dxilOp = static_cast<DXIL::OpCode>(opcode);
588+
DXIL::OpCode dxilOp = hlsl::OP::getOpCode(CI);
589+
if (dxilOp == DXIL::OpCode::NumOpCodes)
590+
continue;
595591
if (hlsl::OP::IsDxilOpWave(dxilOp))
596592
hasWaveOps = true;
597593
switch (dxilOp) {

lib/HLSL/DxilValidation.cpp

+24
Original file line numberDiff line numberDiff line change
@@ -3201,6 +3201,8 @@ static void ValidateFunctionBody(Function *F, ValidationContext &ValCtx) {
32013201
CallInst *setMeshOutputCounts = nullptr;
32023202
CallInst *getMeshPayload = nullptr;
32033203
CallInst *dispatchMesh = nullptr;
3204+
hlsl::OP *hlslOP = ValCtx.DxilMod.GetOP();
3205+
32043206
for (auto b = F->begin(), bend = F->end(); b != bend; ++b) {
32053207
for (auto i = b->begin(), iend = b->end(); i != iend; ++i) {
32063208
llvm::Instruction &I = *i;
@@ -3250,8 +3252,30 @@ static void ValidateFunctionBody(Function *F, ValidationContext &ValCtx) {
32503252
}
32513253

32523254
unsigned opcode = OpcodeConst->getLimitedValue();
3255+
if (opcode >= static_cast<unsigned>(DXIL::OpCode::NumOpCodes)) {
3256+
ValCtx.EmitInstrFormatError(
3257+
&I, ValidationRule::InstrIllegalDXILOpCode,
3258+
{std::to_string((unsigned)DXIL::OpCode::NumOpCodes),
3259+
std::to_string(opcode)});
3260+
continue;
3261+
}
32533262
DXIL::OpCode dxilOpcode = (DXIL::OpCode)opcode;
32543263

3264+
bool IllegalOpFunc = true;
3265+
for (auto &it : hlslOP->GetOpFuncList(dxilOpcode)) {
3266+
if (it.second == FCalled) {
3267+
IllegalOpFunc = false;
3268+
break;
3269+
}
3270+
}
3271+
3272+
if (IllegalOpFunc) {
3273+
ValCtx.EmitInstrFormatError(
3274+
&I, ValidationRule::InstrIllegalDXILOpFunction,
3275+
{FCalled->getName(), OP::GetOpCodeName(dxilOpcode)});
3276+
continue;
3277+
}
3278+
32553279
if (OP::IsDxilOpGradient(dxilOpcode)) {
32563280
gradientOps.push_back(CI);
32573281
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,120 @@
1+
; REQUIRES: dxil-1-8
2+
; RUN: not %dxv %s 2>&1 | FileCheck %s
3+
4+
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"
5+
target triple = "dxil-ms-dx"
6+
7+
%dx.types.Handle = type { i8* }
8+
%dx.types.ResBind = type { i32, i32, i32, i8 }
9+
%dx.types.ResourceProperties = type { i32, i32 }
10+
%dx.types.ResRet.f32 = type { float, float, float, float, i32 }
11+
%"class.Texture2D<float>" = type { float, %"class.Texture2D<float>::mips_type" }
12+
%"class.Texture2D<float>::mips_type" = type { i32 }
13+
%struct.SamplerComparisonState = type { i32 }
14+
15+
16+
define void @main() {
17+
%1 = call %dx.types.Handle @dx.op.createHandleFromBinding(i32 217, %dx.types.ResBind zeroinitializer, i32 0, i1 false) ; CreateHandleFromBinding(bind,index,nonUniformIndex)
18+
%2 = call %dx.types.Handle @dx.op.createHandleFromBinding(i32 217, %dx.types.ResBind { i32 0, i32 0, i32 0, i8 3 }, i32 0, i1 false) ; CreateHandleFromBinding(bind,index,nonUniformIndex)
19+
20+
21+
; CHECK: error: 'dx.op.loadInput.f32' is not a DXILOpFuncition for DXILOpcode 'LoadInput'.
22+
; CHECK: note: at '%3 = call float @dx.op.loadInput.f32(i32 4, i32 0, i32 0, i8 0)' in block '#0' of function 'main'.
23+
24+
%3 = call float @dx.op.loadInput.f32(i32 4, i32 0, i32 0, i8 0) ; LoadInput(inputSigId,rowIndex,colIndex,gsVertexAxis)
25+
26+
; CHECK: error: 'dx.op.loadInput.f32' is not a DXILOpFuncition for DXILOpcode 'LoadInput'.
27+
; CHECK: note: at '%4 = call float @dx.op.loadInput.f32(i32 4, i32 0, i32 0, i8 1)' in block '#0' of function 'main'.
28+
29+
%4 = call float @dx.op.loadInput.f32(i32 4, i32 0, i32 0, i8 1) ; LoadInput(inputSigId,rowIndex,colIndex,gsVertexAxis)
30+
31+
32+
; CHECK: error: 'dx.op.annotateHandle' is not a DXILOpFuncition for DXILOpcode 'MinPrecXRegStore'.
33+
; CHECK: note: at '%5 = call %dx.types.Handle @dx.op.annotateHandle(i32 3, %dx.types.Handle %1, %dx.types.ResourceProperties { i32 2, i32 265 })' in block '#0' of function 'main'.
34+
35+
%5 = call %dx.types.Handle @dx.op.annotateHandle(i32 3, %dx.types.Handle %1, %dx.types.ResourceProperties { i32 2, i32 265 }) ; AnnotateHandle(res,props) resource: Texture2D<F32>
36+
37+
; CHECK: error: 'dx.op.annotateHandle2' is not a DXILOpFuncition for DXILOpcode 'AnnotateHandle'.
38+
; CHECK: note: at '%6 = call %dx.types.Handle @dx.op.annotateHandle2(i32 216, %dx.types.Handle %2, %dx.types.ResourceProperties { i32 32782, i32 0 })' in block '#0' of function 'main'.
39+
40+
%6 = call %dx.types.Handle @dx.op.annotateHandle2(i32 216, %dx.types.Handle %2, %dx.types.ResourceProperties { i32 32782, i32 0 }) ; AnnotateHandle(res,props) resource: SamplerComparisonState
41+
42+
; CHECK: error: DXILOpCode must be [0..258]. 1999981 specified.
43+
; CHECK: note: at '%7 = call float @dx.op.calculateLOD.f32(i32 1999981, %dx.types.Handle %5, %dx.types.Handle %6, float %3, float %4, float undef, i1 true)' in block '#0' of function 'main'.
44+
45+
%7 = call float @dx.op.calculateLOD.f32(i32 1999981, %dx.types.Handle %5, %dx.types.Handle %6, float %3, float %4, float undef, i1 true) ; CalculateLOD(handle,sampler,coord0,coord1,coord2,clamped)
46+
47+
%I = call i32 @dx.op.loadInput.i32(i32 4, i32 0, i32 0, i8 0, i32 undef) ; LoadInput(inputSigId,rowIndex,colIndex,gsVertexAxis)
48+
49+
; CHECK: error: Opcode of DXIL operation must be an immediate constant.
50+
; CHECK: note: at 'call void @dx.op.storeOutput.f32(i32 %I, i32 0, i32 0, i8 0, float %7)' in block '#0' of function 'main'.
51+
call void @dx.op.storeOutput.f32(i32 %I, i32 0, i32 0, i8 0, float %7) ; StoreOutput(outputSigId,rowIndex,colIndex,value)
52+
53+
54+
; CHECK-DAG: error: Opcode SampleCmpBias not valid in shader model ps_6_7.
55+
%CmpBias = call %dx.types.ResRet.f32 @dx.op.sampleCmpBias.f32(i32 255, %dx.types.Handle %5, %dx.types.Handle %6, float %3, float %4, float undef, float undef, i32 0, i32 0, i32 undef, float 5.000000e-01, float 5.000000e-01, float undef) ; SampleCmpBias(srv,sampler,coord0,coord1,coord2,coord3,offset0,offset1,offset2,compareValue,bias,clamp)
56+
57+
ret void
58+
}
59+
60+
61+
; CHECK-DAG: error: DXIL intrinsic overload must be valid.
62+
; CHECK-DAG: note: at '%4 = call float @dx.op.loadInput.f32(i32 4, i32 0, i32 0, i8 1)' in block '#0' of function 'main'.
63+
; CHECK-DAG: error: DXIL intrinsic overload must be valid.
64+
; CHECK-DAG: note: at '%3 = call float @dx.op.loadInput.f32(i32 4, i32 0, i32 0, i8 0)' in block '#0' of function 'main'.
65+
; CHECK-DAG: error: DXIL intrinsic overload must be valid.
66+
; CHECK-DAG: note: at '%5 = call %dx.types.Handle @dx.op.annotateHandle(i32 3, %dx.types.Handle %1, %dx.types.ResourceProperties { i32 2, i32 265 })' in block '#0' of function 'main'.
67+
68+
; Function Attrs: nounwind readnone
69+
declare float @dx.op.loadInput.f32(i32, i32, i32, i8) #0
70+
71+
; Function Attrs: nounwind
72+
declare void @dx.op.storeOutput.f32(i32, i32, i32, i8, float) #1
73+
74+
; Function Attrs: nounwind readonly
75+
declare float @dx.op.calculateLOD.f32(i32, %dx.types.Handle, %dx.types.Handle, float, float, float, i1) #2
76+
77+
; Function Attrs: nounwind readnone
78+
declare %dx.types.Handle @dx.op.annotateHandle(i32, %dx.types.Handle, %dx.types.ResourceProperties) #0
79+
80+
declare %dx.types.Handle @dx.op.annotateHandle2(i32, %dx.types.Handle, %dx.types.ResourceProperties) #0
81+
82+
; Function Attrs: nounwind readnone
83+
declare %dx.types.Handle @dx.op.createHandleFromBinding(i32, %dx.types.ResBind, i32, i1) #0
84+
85+
declare i32 @dx.op.loadInput.i32(i32, i32, i32, i8, i32) #0
86+
87+
; Function Attrs: nounwind readonly
88+
declare %dx.types.ResRet.f32 @dx.op.sampleCmpBias.f32(i32, %dx.types.Handle, %dx.types.Handle, float, float, float, float, i32, i32, i32, float, float, float) #2
89+
90+
attributes #0 = { nounwind readnone }
91+
attributes #1 = { nounwind }
92+
attributes #2 = { nounwind readonly }
93+
94+
!llvm.ident = !{!0}
95+
!dx.version = !{!1}
96+
!dx.valver = !{!1}
97+
!dx.shaderModel = !{!2}
98+
!dx.resources = !{!3}
99+
!dx.viewIdState = !{!9}
100+
!dx.entryPoints = !{!10}
101+
102+
!0 = !{!"dxc(private) 1.7.0.4396 (test_time, 849f8b884-dirty)"}
103+
!1 = !{i32 1, i32 7}
104+
!2 = !{!"ps", i32 6, i32 7}
105+
!3 = !{!4, null, null, !7}
106+
!4 = !{!5}
107+
!5 = !{i32 0, %"class.Texture2D<float>"* undef, !"", i32 0, i32 0, i32 1, i32 2, i32 0, !6}
108+
!6 = !{i32 0, i32 9}
109+
!7 = !{!8}
110+
!8 = !{i32 0, %struct.SamplerComparisonState* undef, !"", i32 0, i32 0, i32 1, i32 1, null}
111+
!9 = !{[4 x i32] [i32 2, i32 1, i32 1, i32 1]}
112+
!10 = !{void ()* @main, !"main", !11, !3, null}
113+
!11 = !{!12, !16, null}
114+
!12 = !{!13}
115+
!13 = !{i32 0, !"A", i8 9, i8 0, !14, i8 2, i32 1, i8 2, i32 0, i8 0, !15}
116+
!14 = !{i32 0}
117+
!15 = !{i32 3, i32 3}
118+
!16 = !{!17}
119+
!17 = !{i32 0, !"SV_Target", i8 9, i8 16, !14, i8 0, i32 1, i8 1, i32 0, i8 0, !18}
120+
!18 = !{i32 3, i32 1}

utils/hct/hctdb.py

+7
Original file line numberDiff line numberDiff line change
@@ -7324,6 +7324,13 @@ def build_valrules(self):
73247324
"Instr.ImmBiasForSampleB",
73257325
"bias amount for sample_b must be in the range [%0,%1], but %2 was specified as an immediate.",
73267326
)
7327+
self.add_valrule(
7328+
"Instr.IllegalDXILOpCode", "DXILOpCode must be [0..%0]. %1 specified."
7329+
)
7330+
self.add_valrule(
7331+
"Instr.IllegalDXILOpFunction",
7332+
"'%0' is not a DXILOpFuncition for DXILOpcode '%1'.",
7333+
)
73277334
# If streams have not been declared, you must use cut instead of cut_stream in GS - is there an equivalent rule here?
73287335

73297336
# Need to clean up all error messages and actually implement.

0 commit comments

Comments
 (0)