diff --git a/docs/ReleaseNotes.md b/docs/ReleaseNotes.md index d426b955f2..609fd82f15 100644 --- a/docs/ReleaseNotes.md +++ b/docs/ReleaseNotes.md @@ -39,6 +39,7 @@ line upon naming the release. Refer to previous for appropriate section names. #### Other Changes - Fixed mesh shader semantics that were incorrectly case sensitive. +- DXIL validation now rejects non-standard integer bit widths (e.g. `i25`) in instructions. ### Version 1.9.2602 diff --git a/lib/DxilValidation/DxilValidation.cpp b/lib/DxilValidation/DxilValidation.cpp index 2236dd11f7..e8eb2b9c74 100644 --- a/lib/DxilValidation/DxilValidation.cpp +++ b/lib/DxilValidation/DxilValidation.cpp @@ -2659,6 +2659,19 @@ static bool IsDxilBuiltinStructType(StructType *ST, hlsl::OP *HlslOP) { } } +static bool IsValidIntBitWidth(unsigned Width) { + switch (Width) { + case 1: + case 8: + case 16: + case 32: + case 64: + return true; + default: + return false; + } +} + // outer type may be: [ptr to][1 dim array of]( UDT struct | scalar ) // inner type (UDT struct member) may be: [N dim array of]( UDT struct | scalar // ) scalar type may be: ( float(16|32|64) | int(16|32|64) ) @@ -2717,8 +2730,7 @@ static bool ValidateType(Type *Ty, ValidationContext &ValCtx, return true; } if (Ty->isIntegerTy()) { - unsigned Width = Ty->getIntegerBitWidth(); - if (Width != 1 && Width != 8 && Width != 16 && Width != 32 && Width != 64) { + if (!IsValidIntBitWidth(Ty->getIntegerBitWidth())) { ValCtx.EmitTypeError(Ty, ValidationRule::TypesIntWidth); return false; } @@ -3388,10 +3400,13 @@ static void ValidateFunctionBody(Function *F, ValidationContext &ValCtx) { } } if (IntegerType *IT = dyn_cast(op->getType())) { - if (IT->getBitWidth() == 8) { + unsigned BW = IT->getBitWidth(); + if (BW == 8) { // We always fail if we see i8 as operand type of a non-lifetime // instruction. ValCtx.EmitInstrError(&I, ValidationRule::TypesI8); + } else { + ValidateType(IT, ValCtx); } } } @@ -3402,12 +3417,15 @@ static void ValidateFunctionBody(Function *F, ValidationContext &ValCtx) { while (isa(Ty)) Ty = Ty->getArrayElementType(); if (IntegerType *IT = dyn_cast(Ty)) { - if (IT->getBitWidth() == 8) { + unsigned BW = IT->getBitWidth(); + if (BW == 8) { // Allow i8* cast for llvm.lifetime.* intrinsics. if (!SupportsLifetimeIntrinsics || !isa(I) || !onlyUsedByLifetimeMarkers(&I)) { ValCtx.EmitInstrError(&I, ValidationRule::TypesI8); } + } else { + ValidateType(IT, ValCtx); } } diff --git a/tools/clang/test/LitDXILValidation/int-width-validation.ll b/tools/clang/test/LitDXILValidation/int-width-validation.ll new file mode 100644 index 0000000000..e1ee2c975f --- /dev/null +++ b/tools/clang/test/LitDXILValidation/int-width-validation.ll @@ -0,0 +1,35 @@ +; RUN: not %dxv %s 2>&1 | 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: Int type 'i25' has an invalid width. +; CHECK: Int type 'i25' has an invalid width. +; CHECK: Validation failed. + +define void @main() { + ; Test invalid int width in operand and result types. + %1 = add i25 0, 1 + ; Test invalid int width inside array result type. + %2 = select i1 true, [2 x i25] zeroinitializer, [2 x i25] zeroinitializer + call void @dx.op.storeOutput.f32(i32 5, i32 0, i32 0, i8 0, float 0.000000e+00) + ret void +} + +declare void @dx.op.storeOutput.f32(i32, i32, i32, i8, float) #0 + +attributes #0 = { nounwind } + +!dx.version = !{!0} +!dx.valver = !{!0} +!dx.shaderModel = !{!1} +!dx.entryPoints = !{!2} + +!0 = !{i32 1, i32 0} +!1 = !{!"ps", i32 6, i32 0} +!2 = !{void ()* @main, !"main", !3, null, null} +!3 = !{null, !4, null} +!4 = !{!5} +!5 = !{i32 0, !"SV_Target", i8 9, i8 16, !6, i8 0, i32 1, i8 1, i32 0, i8 0, !7} +!6 = !{i32 0} +!7 = !{i32 3, i32 1}