Skip to content

Commit 90ae8d8

Browse files
damyanpCopilot
andauthored
[Validation] Make validator reject unsupported llvm integer sizes (#8207)
There are a limited number of supported integer sizes in DXIL. This change updates the validator to reject shaders that use unsupported integer sizes. Fixes #6563 --------- Co-authored-by: copilot-swe-agent[bot] <[email protected]> Co-authored-by: damyanp <[email protected]>
1 parent fbc8aed commit 90ae8d8

3 files changed

Lines changed: 58 additions & 4 deletions

File tree

docs/ReleaseNotes.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@ line upon naming the release. Refer to previous for appropriate section names.
4141

4242
- Fixed non-deterministic DXIL/PDB output when compiling shaders with resource arrays, debug info, and SM 6.6+. [#8171](https://github.com/microsoft/DirectXShaderCompiler/issues/8171)
4343
- Fixed mesh shader semantics that were incorrectly case sensitive.
44+
- DXIL validation now rejects non-standard integer bit widths (e.g. `i25`) in instructions.
4445

4546
### Version 1.9.2602
4647

lib/DxilValidation/DxilValidation.cpp

Lines changed: 22 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2659,6 +2659,19 @@ static bool IsDxilBuiltinStructType(StructType *ST, hlsl::OP *HlslOP) {
26592659
}
26602660
}
26612661

2662+
static bool IsValidIntBitWidth(unsigned Width) {
2663+
switch (Width) {
2664+
case 1:
2665+
case 8:
2666+
case 16:
2667+
case 32:
2668+
case 64:
2669+
return true;
2670+
default:
2671+
return false;
2672+
}
2673+
}
2674+
26622675
// outer type may be: [ptr to][1 dim array of]( UDT struct | scalar )
26632676
// inner type (UDT struct member) may be: [N dim array of]( UDT struct | scalar
26642677
// ) scalar type may be: ( float(16|32|64) | int(16|32|64) )
@@ -2717,8 +2730,7 @@ static bool ValidateType(Type *Ty, ValidationContext &ValCtx,
27172730
return true;
27182731
}
27192732
if (Ty->isIntegerTy()) {
2720-
unsigned Width = Ty->getIntegerBitWidth();
2721-
if (Width != 1 && Width != 8 && Width != 16 && Width != 32 && Width != 64) {
2733+
if (!IsValidIntBitWidth(Ty->getIntegerBitWidth())) {
27222734
ValCtx.EmitTypeError(Ty, ValidationRule::TypesIntWidth);
27232735
return false;
27242736
}
@@ -3388,10 +3400,13 @@ static void ValidateFunctionBody(Function *F, ValidationContext &ValCtx) {
33883400
}
33893401
}
33903402
if (IntegerType *IT = dyn_cast<IntegerType>(op->getType())) {
3391-
if (IT->getBitWidth() == 8) {
3403+
unsigned BW = IT->getBitWidth();
3404+
if (BW == 8) {
33923405
// We always fail if we see i8 as operand type of a non-lifetime
33933406
// instruction.
33943407
ValCtx.EmitInstrError(&I, ValidationRule::TypesI8);
3408+
} else {
3409+
ValidateType(IT, ValCtx);
33953410
}
33963411
}
33973412
}
@@ -3402,12 +3417,15 @@ static void ValidateFunctionBody(Function *F, ValidationContext &ValCtx) {
34023417
while (isa<ArrayType>(Ty))
34033418
Ty = Ty->getArrayElementType();
34043419
if (IntegerType *IT = dyn_cast<IntegerType>(Ty)) {
3405-
if (IT->getBitWidth() == 8) {
3420+
unsigned BW = IT->getBitWidth();
3421+
if (BW == 8) {
34063422
// Allow i8* cast for llvm.lifetime.* intrinsics.
34073423
if (!SupportsLifetimeIntrinsics || !isa<BitCastInst>(I) ||
34083424
!onlyUsedByLifetimeMarkers(&I)) {
34093425
ValCtx.EmitInstrError(&I, ValidationRule::TypesI8);
34103426
}
3427+
} else {
3428+
ValidateType(IT, ValCtx);
34113429
}
34123430
}
34133431

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
; RUN: not %dxv %s 2>&1 | FileCheck %s
2+
3+
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"
4+
target triple = "dxil-ms-dx"
5+
6+
; CHECK: Int type 'i25' has an invalid width.
7+
; CHECK: Int type 'i25' has an invalid width.
8+
; CHECK: Validation failed.
9+
10+
define void @main() {
11+
; Test invalid int width in operand and result types.
12+
%1 = add i25 0, 1
13+
; Test invalid int width inside array result type.
14+
%2 = select i1 true, [2 x i25] zeroinitializer, [2 x i25] zeroinitializer
15+
call void @dx.op.storeOutput.f32(i32 5, i32 0, i32 0, i8 0, float 0.000000e+00)
16+
ret void
17+
}
18+
19+
declare void @dx.op.storeOutput.f32(i32, i32, i32, i8, float) #0
20+
21+
attributes #0 = { nounwind }
22+
23+
!dx.version = !{!0}
24+
!dx.valver = !{!0}
25+
!dx.shaderModel = !{!1}
26+
!dx.entryPoints = !{!2}
27+
28+
!0 = !{i32 1, i32 0}
29+
!1 = !{!"ps", i32 6, i32 0}
30+
!2 = !{void ()* @main, !"main", !3, null, null}
31+
!3 = !{null, !4, null}
32+
!4 = !{!5}
33+
!5 = !{i32 0, !"SV_Target", i8 9, i8 16, !6, i8 0, i32 1, i8 1, i32 0, i8 0, !7}
34+
!6 = !{i32 0}
35+
!7 = !{i32 3, i32 1}

0 commit comments

Comments
 (0)