From b473eaa7876b8354941ba9c3fddb5d8ed33ef58e Mon Sep 17 00:00:00 2001 From: Ashley Coleman Date: Thu, 9 Jul 2026 14:17:31 -0600 Subject: [PATCH 1/2] [SM6.10] LinAlg Validation: CopyConvert Builtin --- docs/DXIL.rst | 3 + lib/DxilValidation/DxilValidation.cpp | 59 +++++++++++++- lib/DxilValidation/DxilValidationUtils.cpp | 14 ++++ lib/DxilValidation/DxilValidationUtils.h | 2 + .../LinAlgMatrix/linalgmatrix-copyconvert.ll | 81 +++++++++++++++++++ utils/hct/hctdb.py | 13 ++- 6 files changed, 170 insertions(+), 2 deletions(-) create mode 100644 tools/clang/test/LitDXILValidation/LinAlgMatrix/linalgmatrix-copyconvert.ll diff --git a/docs/DXIL.rst b/docs/DXIL.rst index 097c6c2e9f..9b7b5752f5 100644 --- a/docs/DXIL.rst +++ b/docs/DXIL.rst @@ -3211,6 +3211,9 @@ INSTR.IMMBIASFORSAMPLEB bias amount for sample_b m INSTR.INBOUNDSACCESS Access to out-of-bounds memory is disallowed. INSTR.LINALGILLEGALCOMPONENTTYPE Matrix Component Type '%0' not allowed in LinAlg Matrix. INSTR.LINALGILLEGALKDIM Matrix K Dimension out of bounds. K=%0 must be >= %1 and <= %2. +INSTR.LINALGMATRIXDIMMISMATCH Matrix Dimension '%0x%1' does not match expected dimension %2x%3. +INSTR.LINALGMATRIXSCOPEMISMATCH Matrix Scope '%0' does not match expected scope %1. +INSTR.LINALGMATRIXSCOPENOTALLOWED Matrix Scope '%0' not allowed in %1 operation. INSTR.MAYREORDERTHREADUNDEFCOHERENCEHINTPARAM Use of undef coherence hint or num coherence hint bits in MaybeReorderThread. INSTR.MINPRECISIONNOTPRECISE Instructions marked precise may not refer to minprecision values. INSTR.MINPRECISONBITCAST Bitcast on minprecison types is not allowed. diff --git a/lib/DxilValidation/DxilValidation.cpp b/lib/DxilValidation/DxilValidation.cpp index 89cfef14a5..f6934435be 100644 --- a/lib/DxilValidation/DxilValidation.cpp +++ b/lib/DxilValidation/DxilValidation.cpp @@ -2269,7 +2269,6 @@ static void ValidateDxilOperationCallInProfile(CallInst *CI, break; } case DXIL::OpCode::LinAlgFillMatrix: - case DXIL::OpCode::LinAlgCopyConvertMatrix: case DXIL::OpCode::LinAlgMatrixLoadFromDescriptor: case DXIL::OpCode::LinAlgMatrixLoadFromMemory: case DXIL::OpCode::LinAlgMatrixSetElement: @@ -2281,6 +2280,64 @@ static void ValidateDxilOperationCallInProfile(CallInst *CI, ValidateLinAlgOpParameters(CI, ValCtx); break; } + case DXIL::OpCode::LinAlgCopyConvertMatrix: { + ValidateLinAlgOpReturnMatrix(CI, ValCtx); + ValidateLinAlgOpParameters(CI, ValCtx); + + Type *DstMatTy = CI->getType(); + Type *SrcMatTy = CI->getArgOperand(1)->getType(); + assert(dxilutil::IsHLSLLinAlgMatrixType(DstMatTy) && + dxilutil::IsHLSLLinAlgMatrixType(DstMatTy) && + "Must be LinAlg types"); + + Value *TransposeOp = CI->getArgOperand(2); + ConstantInt *TransposeCI = dyn_cast(TransposeOp); + bool Transpose = false; + + if (TransposeCI) + Transpose = TransposeCI->isOne(); + else + ValCtx.EmitInstrFormatError(CI, ValidationRule::InstrOpConst, + {"Transpose", "LinAlgCopyConvertMatrix"}); + + auto DstIt = ValCtx.LinAlgTargetTypeMap.find(DstMatTy); + auto SrcIt = ValCtx.LinAlgTargetTypeMap.find(SrcMatTy); + if (DstIt == ValCtx.LinAlgTargetTypeMap.end()) + break; + if (SrcIt == ValCtx.LinAlgTargetTypeMap.end()) + break; + LinAlgTargetType DstLATT = DstIt->second; + LinAlgTargetType SrcLATT = SrcIt->second; + + if (DstLATT.Scope == DXIL::MatrixScope::Thread || + SrcLATT.Scope == DXIL::MatrixScope::Thread) + ValCtx.EmitInstrFormatError( + CI, ValidationRule::InstrLinAlgMatrixScopeNotAllowed, + {"Thread", "LinAlgCopyConvertMatrix"}); + + if (DstLATT.Scope != SrcLATT.Scope) + ValCtx.EmitInstrFormatError( + CI, ValidationRule::InstrLinAlgMatrixScopeMismatch, + {MatrixScopeToString(DstLATT.Scope), + MatrixScopeToString(SrcLATT.Scope)}); + + unsigned DstM = DstLATT.M; + unsigned DstN = DstLATT.N; + unsigned SrcM = SrcLATT.M; + unsigned SrcN = SrcLATT.N; + if (Transpose) { + SrcM = SrcLATT.N; + SrcN = SrcLATT.M; + } + + if (DstM != SrcM || DstN != SrcN) + ValCtx.EmitInstrFormatError(CI, + ValidationRule::InstrLinAlgMatrixDimMismatch, + {std::to_string(DstM), std::to_string(DstN), + std::to_string(SrcM), std::to_string(SrcN)}); + + break; + } default: // TODO: make sure every Opcode is checked. diff --git a/lib/DxilValidation/DxilValidationUtils.cpp b/lib/DxilValidation/DxilValidationUtils.cpp index e8d7c6c0ab..821ab4a19e 100644 --- a/lib/DxilValidation/DxilValidationUtils.cpp +++ b/lib/DxilValidation/DxilValidationUtils.cpp @@ -14,6 +14,7 @@ #include #include +#include "dxc/DXIL/DxilConstants.h" #include "dxc/DXIL/DxilEntryProps.h" #include "dxc/DXIL/DxilInstructions.h" #include "dxc/DXIL/DxilModule.h" @@ -669,4 +670,17 @@ llvm::StringRef ComponentTypeToString(DXIL::ComponentType CT) { } } +llvm::StringRef MatrixScopeToString(DXIL::MatrixScope MS) { + switch (MS) { + case DXIL::MatrixScope::Thread: + return "Thread"; + case DXIL::MatrixScope::Wave: + return "Wave"; + case DXIL::MatrixScope::ThreadGroup: + return "ThreadGroup"; + default: + return "Unknown MatrixScope"; + } +} + } // namespace hlsl diff --git a/lib/DxilValidation/DxilValidationUtils.h b/lib/DxilValidation/DxilValidationUtils.h index 5446a336c3..a535b92dd0 100644 --- a/lib/DxilValidation/DxilValidationUtils.h +++ b/lib/DxilValidation/DxilValidationUtils.h @@ -157,4 +157,6 @@ struct ValidationContext { uint32_t ValidateDxilModule(llvm::Module *pModule, llvm::Module *pDebugModule); llvm::StringRef ComponentTypeToString(DXIL::ComponentType CT); + +llvm::StringRef MatrixScopeToString(DXIL::MatrixScope MS); } // namespace hlsl diff --git a/tools/clang/test/LitDXILValidation/LinAlgMatrix/linalgmatrix-copyconvert.ll b/tools/clang/test/LitDXILValidation/LinAlgMatrix/linalgmatrix-copyconvert.ll new file mode 100644 index 0000000000..fd3b2ebd9e --- /dev/null +++ b/tools/clang/test/LitDXILValidation/LinAlgMatrix/linalgmatrix-copyconvert.ll @@ -0,0 +1,81 @@ +; REQUIRES: dxil-1-10 +; 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" + +%dx.types.LinAlgMatrixC2M5N4U1S2 = type { i8* } +%dx.types.LinAlgMatrixC4M8N4U1S2 = type { i8* } +%dx.types.LinAlgMatrixC4M5N8U1S2 = type { i8* } +%dx.types.LinAlgMatrixC4M5N4U1S2 = type { i8* } +%dx.types.LinAlgMatrixC2M4N5U1S1 = type { i8* } +%dx.types.LinAlgMatrixC2M4N5U1S0 = type { i8* } +define void @main() { + %1 = call %dx.types.LinAlgMatrixC2M5N4U1S2 @dx.op.linAlgFillMatrix.mC2M5N4U1S2.i32(i32 -2147483636, i32 1) ; LinAlgFillMatrix(value) + + ; CHECK: Function: main: error: Matrix Dimension '8x4' does not match expected dimension 5x4. + ; CHECK-NEXT: note: at {{.*}} @dx.op.linAlgCopyConvertMatrix.mC4M8N4U1S2.mC2M5N4U1S2 + %2 = call %dx.types.LinAlgMatrixC4M8N4U1S2 @dx.op.linAlgCopyConvertMatrix.mC4M8N4U1S2.mC2M5N4U1S2(i32 -2147483635, %dx.types.LinAlgMatrixC2M5N4U1S2 %1, i1 false) ; LinAlgCopyConvertMatrix(srcMatrix,transpose) + + ; CHECK-NEXT: Function: main: error: Matrix Dimension '5x8' does not match expected dimension 5x4. + ; CHECK-NEXT: note: at {{.*}} @dx.op.linAlgCopyConvertMatrix.mC4M5N8U1S2.mC2M5N4U1S2 + %3 = call %dx.types.LinAlgMatrixC4M5N8U1S2 @dx.op.linAlgCopyConvertMatrix.mC4M5N8U1S2.mC2M5N4U1S2(i32 -2147483635, %dx.types.LinAlgMatrixC2M5N4U1S2 %1, i1 false) ; LinAlgCopyConvertMatrix(srcMatrix,transpose) + + ; CHECK-NEXT: Function: main: error: Matrix Dimension '5x4' does not match expected dimension 4x5. + ; CHECK-NEXT: note: at {{.*}} @dx.op.linAlgCopyConvertMatrix.mC4M5N4U1S2.mC2M5N4U1S2 + %4 = call %dx.types.LinAlgMatrixC4M5N4U1S2 @dx.op.linAlgCopyConvertMatrix.mC4M5N4U1S2.mC2M5N4U1S2(i32 -2147483635, %dx.types.LinAlgMatrixC2M5N4U1S2 %1, i1 true) ; LinAlgCopyConvertMatrix(srcMatrix,transpose) + + ; CHECK-NEXT: Function: main: error: Matrix Scope 'Wave' does not match expected scope ThreadGroup. + ; CHECK-NEXT: note: at {{.*}} @dx.op.linAlgCopyConvertMatrix.mC2M4N5U1S1.mC2M5N4U1S2 + %5 = call %dx.types.LinAlgMatrixC2M4N5U1S1 @dx.op.linAlgCopyConvertMatrix.mC2M4N5U1S1.mC2M5N4U1S2(i32 -2147483635, %dx.types.LinAlgMatrixC2M5N4U1S2 %1, i1 true) ; LinAlgCopyConvertMatrix(srcMatrix,transpose) + + %6 = call %dx.types.LinAlgMatrixC2M4N5U1S0 @dx.op.linAlgFillMatrix.mC2M4N5U1S0.i32(i32 -2147483636, i32 1) ; LinAlgFillMatrix(value) + + ; CHECK-NEXT: Function: main: error: Matrix Scope 'Thread' not allowed in LinAlgCopyConvertMatrix operation. + ; CHECK-NEXT: note: at {{.*}} @dx.op.linAlgCopyConvertMatrix.mC2M4N5U1S0.mC2M4N5U1S0 + %7 = call %dx.types.LinAlgMatrixC2M4N5U1S0 @dx.op.linAlgCopyConvertMatrix.mC2M4N5U1S0.mC2M4N5U1S0(i32 -2147483635, %dx.types.LinAlgMatrixC2M4N5U1S0 %6, i1 false) ; LinAlgCopyConvertMatrix(srcMatrix,transpose) + ; CHECK-NEXT: Validation failed. + ret void +} + +; Function Attrs: nounwind +declare %dx.types.LinAlgMatrixC2M5N4U1S2 @dx.op.linAlgFillMatrix.mC2M5N4U1S2.i32(i32, i32) #0 + +; Function Attrs: nounwind +declare %dx.types.LinAlgMatrixC4M8N4U1S2 @dx.op.linAlgCopyConvertMatrix.mC4M8N4U1S2.mC2M5N4U1S2(i32, %dx.types.LinAlgMatrixC2M5N4U1S2, i1) #0 + +; Function Attrs: nounwind +declare %dx.types.LinAlgMatrixC4M5N8U1S2 @dx.op.linAlgCopyConvertMatrix.mC4M5N8U1S2.mC2M5N4U1S2(i32, %dx.types.LinAlgMatrixC2M5N4U1S2, i1) #0 + +; Function Attrs: nounwind +declare %dx.types.LinAlgMatrixC4M5N4U1S2 @dx.op.linAlgCopyConvertMatrix.mC4M5N4U1S2.mC2M5N4U1S2(i32, %dx.types.LinAlgMatrixC2M5N4U1S2, i1) #0 + +; Function Attrs: nounwind +declare %dx.types.LinAlgMatrixC2M4N5U1S1 @dx.op.linAlgCopyConvertMatrix.mC2M4N5U1S1.mC2M5N4U1S2(i32, %dx.types.LinAlgMatrixC2M5N4U1S2, i1) #0 + +; Function Attrs: nounwind +declare %dx.types.LinAlgMatrixC2M4N5U1S0 @dx.op.linAlgFillMatrix.mC2M4N5U1S0.i32(i32, i32) #0 + +; Function Attrs: nounwind +declare %dx.types.LinAlgMatrixC2M4N5U1S0 @dx.op.linAlgCopyConvertMatrix.mC2M4N5U1S0.mC2M4N5U1S0(i32, %dx.types.LinAlgMatrixC2M4N5U1S0, i1) #0 + +attributes #0 = { nounwind } + +!dx.targetTypes = !{!0, !1, !2, !3, !4, !5} +!llvm.ident = !{!6} +!dx.version = !{!7} +!dx.valver = !{!7} +!dx.shaderModel = !{!8} +!dx.entryPoints = !{!9} + +!0 = !{%dx.types.LinAlgMatrixC2M5N4U1S2 undef, i32 2, i32 5, i32 4, i32 1, i32 2} +!1 = !{%dx.types.LinAlgMatrixC4M8N4U1S2 undef, i32 4, i32 8, i32 4, i32 1, i32 2} +!2 = !{%dx.types.LinAlgMatrixC4M5N8U1S2 undef, i32 4, i32 5, i32 8, i32 1, i32 2} +!3 = !{%dx.types.LinAlgMatrixC4M5N4U1S2 undef, i32 4, i32 5, i32 4, i32 1, i32 2} +!4 = !{%dx.types.LinAlgMatrixC2M4N5U1S1 undef, i32 2, i32 4, i32 5, i32 1, i32 1} +!5 = !{%dx.types.LinAlgMatrixC2M4N5U1S0 undef, i32 2, i32 4, i32 5, i32 1, i32 0} +!6 = !{!"dxc(private) 1.9.0.5389 (linalg-validation-component-type, b8b639b7d-dirty)"} +!7 = !{i32 1, i32 10} +!8 = !{!"cs", i32 6, i32 10} +!9 = !{void ()* @main, !"main", null, null, !10} +!10 = !{i32 4, !11} +!11 = !{i32 1, i32 1, i32 1} diff --git a/utils/hct/hctdb.py b/utils/hct/hctdb.py index ba05825a69..62c4191efb 100644 --- a/utils/hct/hctdb.py +++ b/utils/hct/hctdb.py @@ -8644,7 +8644,18 @@ def build_valrules(self): "Instr.LinAlgIllegalComponentType", "Matrix Component Type '%0' not allowed in LinAlg Matrix.", ) - + self.add_valrule( + "Instr.LinAlgMatrixScopeNotAllowed", + "Matrix Scope '%0' not allowed in %1 operation.", + ) + self.add_valrule( + "Instr.LinAlgMatrixScopeMismatch", + "Matrix Scope '%0' does not match expected scope %1.", + ) + self.add_valrule( + "Instr.LinAlgMatrixDimMismatch", + "Matrix Dimension '%0x%1' does not match expected dimension %2x%3.", + ) # Some legacy rules: # - space is only supported for shader targets 5.1 and higher # - multiple rules regarding derivatives, which isn't a supported feature for DXIL From 977f447922580905ead2fb5ea95dc9159929d9ea Mon Sep 17 00:00:00 2001 From: Ashley Coleman Date: Fri, 10 Jul 2026 09:37:35 -0600 Subject: [PATCH 2/2] Apply suggestion from @alsepkow Co-authored-by: Alex Sepkowski --- lib/DxilValidation/DxilValidation.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/DxilValidation/DxilValidation.cpp b/lib/DxilValidation/DxilValidation.cpp index f6934435be..7e87940e2b 100644 --- a/lib/DxilValidation/DxilValidation.cpp +++ b/lib/DxilValidation/DxilValidation.cpp @@ -2287,7 +2287,7 @@ static void ValidateDxilOperationCallInProfile(CallInst *CI, Type *DstMatTy = CI->getType(); Type *SrcMatTy = CI->getArgOperand(1)->getType(); assert(dxilutil::IsHLSLLinAlgMatrixType(DstMatTy) && - dxilutil::IsHLSLLinAlgMatrixType(DstMatTy) && + dxilutil::IsHLSLLinAlgMatrixType(SrcMatTy) && "Must be LinAlg types"); Value *TransposeOp = CI->getArgOperand(2);