From 6237780b825dd9e88632fd4b3d2790683b478354 Mon Sep 17 00:00:00 2001 From: Simon Moll Date: Mon, 17 Mar 2025 17:31:06 +0100 Subject: [PATCH 1/5] [SER] MaybeReorderThread DXIL opcode and validation - DXIL opcodes for MaybeReorderThread - Validator rules - DXV validation test (passing & expected failures) Specification: https://github.com/microsoft/hlsl-specs/blob/main/proposals/0027-shader-execution-reordering.md DXC SER implementation tracker: #7214 --- include/dxc/DXIL/DxilConstants.h | 112 +++++++++--------- include/dxc/DXIL/DxilInstructions.h | 38 ++++++ lib/DXIL/DxilOperations.cpp | 20 +++- lib/DxilValidation/DxilValidation.cpp | 13 ++ .../ser_maybereorder_failing.ll | 50 ++++++++ .../ser_maybereorder_passing.ll | 43 +++++++ utils/hct/hctdb.py | 35 +++++- 7 files changed, 249 insertions(+), 62 deletions(-) create mode 100644 tools/clang/test/DXILValidation/ser_maybereorder_failing.ll create mode 100644 tools/clang/test/DXILValidation/ser_maybereorder_passing.ll diff --git a/include/dxc/DXIL/DxilConstants.h b/include/dxc/DXIL/DxilConstants.h index 0a9c6a4ffd..437202afdf 100644 --- a/include/dxc/DXIL/DxilConstants.h +++ b/include/dxc/DXIL/DxilConstants.h @@ -482,60 +482,61 @@ inline bool IsFeedbackTexture(DXIL::ResourceKind ResourceKind) { // Enumeration for operations specified by DXIL enum class OpCode : unsigned { // - Reserved0 = 226, // Reserved - Reserved1 = 227, // Reserved - Reserved10 = 236, // Reserved - Reserved11 = 237, // Reserved - Reserved2 = 228, // Reserved - Reserved3 = 229, // Reserved - Reserved4 = 230, // Reserved - Reserved5 = 231, // Reserved - Reserved6 = 232, // Reserved - Reserved7 = 233, // Reserved - Reserved8 = 234, // Reserved - Reserved9 = 235, // Reserved - ReservedA0 = 259, // reserved - ReservedA1 = 260, // reserved - ReservedA2 = 261, // reserved - ReservedB0 = 262, // reserved - ReservedB1 = 263, // reserved - ReservedB10 = 272, // reserved - ReservedB11 = 273, // reserved - ReservedB12 = 274, // reserved - ReservedB13 = 275, // reserved - ReservedB14 = 276, // reserved - ReservedB15 = 277, // reserved - ReservedB16 = 278, // reserved - ReservedB17 = 279, // reserved - ReservedB18 = 280, // reserved - ReservedB19 = 281, // reserved - ReservedB2 = 264, // reserved - ReservedB20 = 282, // reserved - ReservedB21 = 283, // reserved - ReservedB22 = 284, // reserved - ReservedB23 = 285, // reserved - ReservedB24 = 286, // reserved - ReservedB25 = 287, // reserved - ReservedB26 = 288, // reserved - ReservedB27 = 289, // reserved - ReservedB28 = 290, // reserved - ReservedB29 = 291, // reserved - ReservedB30 = 292, // reserved - ReservedB5 = 267, // reserved - ReservedB6 = 268, // reserved - ReservedB7 = 269, // reserved - ReservedB8 = 270, // reserved - ReservedB9 = 271, // reserved - ReservedC0 = 293, // reserved - ReservedC1 = 294, // reserved - ReservedC2 = 295, // reserved - ReservedC3 = 296, // reserved - ReservedC4 = 297, // reserved - ReservedC5 = 298, // reserved - ReservedC6 = 299, // reserved - ReservedC7 = 300, // reserved - ReservedC8 = 301, // reserved - ReservedC9 = 302, // reserved + MaybeReorderThread = 268, // Reorders the current thread. Optionally accepts a + // HitObject arg, or undef + Reserved0 = 226, // Reserved + Reserved1 = 227, // Reserved + Reserved10 = 236, // Reserved + Reserved11 = 237, // Reserved + Reserved2 = 228, // Reserved + Reserved3 = 229, // Reserved + Reserved4 = 230, // Reserved + Reserved5 = 231, // Reserved + Reserved6 = 232, // Reserved + Reserved7 = 233, // Reserved + Reserved8 = 234, // Reserved + Reserved9 = 235, // Reserved + ReservedA0 = 259, // reserved + ReservedA1 = 260, // reserved + ReservedA2 = 261, // reserved + ReservedB0 = 262, // reserved + ReservedB1 = 263, // reserved + ReservedB10 = 272, // reserved + ReservedB11 = 273, // reserved + ReservedB12 = 274, // reserved + ReservedB13 = 275, // reserved + ReservedB14 = 276, // reserved + ReservedB15 = 277, // reserved + ReservedB16 = 278, // reserved + ReservedB17 = 279, // reserved + ReservedB18 = 280, // reserved + ReservedB19 = 281, // reserved + ReservedB2 = 264, // reserved + ReservedB20 = 282, // reserved + ReservedB21 = 283, // reserved + ReservedB22 = 284, // reserved + ReservedB23 = 285, // reserved + ReservedB24 = 286, // reserved + ReservedB25 = 287, // reserved + ReservedB26 = 288, // reserved + ReservedB27 = 289, // reserved + ReservedB28 = 290, // reserved + ReservedB29 = 291, // reserved + ReservedB30 = 292, // reserved + ReservedB5 = 267, // reserved + ReservedB7 = 269, // reserved + ReservedB8 = 270, // reserved + ReservedB9 = 271, // reserved + ReservedC0 = 293, // reserved + ReservedC1 = 294, // reserved + ReservedC2 = 295, // reserved + ReservedC3 = 296, // reserved + ReservedC4 = 297, // reserved + ReservedC5 = 298, // reserved + ReservedC6 = 299, // reserved + ReservedC7 = 300, // reserved + ReservedC8 = 301, // reserved + ReservedC9 = 302, // reserved // Amplification shader instructions DispatchMesh = 173, // Amplification shader intrinsic DispatchMesh @@ -1051,6 +1052,7 @@ enum class OpCode : unsigned { // Groups for DXIL operations with equivalent function templates enum class OpCodeClass : unsigned { // + MaybeReorderThread, Reserved, // Amplification shader instructions @@ -1351,7 +1353,7 @@ enum class OpCodeClass : unsigned { NumOpClasses_Dxil_1_7 = 153, NumOpClasses_Dxil_1_8 = 174, - NumOpClasses = 177 // exclusive last value of enumeration + NumOpClasses = 178 // exclusive last value of enumeration }; // OPCODECLASS-ENUM:END diff --git a/include/dxc/DXIL/DxilInstructions.h b/include/dxc/DXIL/DxilInstructions.h index 6a28a2a806..4a037ab7ac 100644 --- a/include/dxc/DXIL/DxilInstructions.h +++ b/include/dxc/DXIL/DxilInstructions.h @@ -8887,5 +8887,43 @@ struct DxilInst_HitObject_MakeNop { // Metadata bool requiresUniformInputs() const { return false; } }; + +/// This instruction Reorders the current thread. Optionally accepts a HitObject +/// arg, or undef +struct DxilInst_MaybeReorderThread { + llvm::Instruction *Instr; + // Construction and identification + DxilInst_MaybeReorderThread(llvm::Instruction *pInstr) : Instr(pInstr) {} + operator bool() const { + return hlsl::OP::IsDxilOpFuncCallInst(Instr, + hlsl::OP::OpCode::MaybeReorderThread); + } + // Validation support + bool isAllowed() const { return true; } + bool isArgumentListValid() const { + if (4 != llvm::dyn_cast(Instr)->getNumArgOperands()) + return false; + return true; + } + // Metadata + bool requiresUniformInputs() const { return false; } + // Operand indexes + enum OperandIdx { + arg_hitObject = 1, + arg_coherenceHint = 2, + arg_numCoherenceHintBitsFromLSB = 3, + }; + // Accessors + llvm::Value *get_hitObject() const { return Instr->getOperand(1); } + void set_hitObject(llvm::Value *val) { Instr->setOperand(1, val); } + llvm::Value *get_coherenceHint() const { return Instr->getOperand(2); } + void set_coherenceHint(llvm::Value *val) { Instr->setOperand(2, val); } + llvm::Value *get_numCoherenceHintBitsFromLSB() const { + return Instr->getOperand(3); + } + void set_numCoherenceHintBitsFromLSB(llvm::Value *val) { + Instr->setOperand(3, val); + } +}; // INSTR-HELPER:END } // namespace hlsl diff --git a/lib/DXIL/DxilOperations.cpp b/lib/DXIL/DxilOperations.cpp index 86049fee9c..702568e0ac 100644 --- a/lib/DXIL/DxilOperations.cpp +++ b/lib/DXIL/DxilOperations.cpp @@ -2703,10 +2703,10 @@ const OP::OpCodeProperty OP::m_OpCodeProps[(unsigned)OP::OpCode::NumOpCodes] = { Attribute::None, }, { - OC::ReservedB6, - "ReservedB6", - OCC::Reserved, - "reserved", + OC::MaybeReorderThread, + "MaybeReorderThread", + OCC::MaybeReorderThread, + "maybeReorderThread", {true, false, false, false, false, false, false, false, false, false, false}, Attribute::None, @@ -3486,6 +3486,11 @@ void OP::GetMinShaderModelAndMask(OpCode C, bool bWithTranslation, SFLAG(Amplification) | SFLAG(Mesh) | SFLAG(Node); return; } + // Instructions: MaybeReorderThread=268 + if (op == 268) { + mask = SFLAG(Library) | SFLAG(RayGeneration); + return; + } // Instructions: RenderTargetGetSamplePosition=76, // RenderTargetGetSampleCount=77, Discard=82, EvalSnapped=87, // EvalSampleIndex=88, EvalCentroid=89, SampleIndex=90, Coverage=91, @@ -5913,9 +5918,12 @@ Function *OP::GetOpFunc(OpCode opCode, Type *pOverloadType) { A(pV); A(pI32); break; - case OpCode::ReservedB6: + case OpCode::MaybeReorderThread: A(pV); A(pI32); + A(pHit); + A(pI32); + A(pI32); break; case OpCode::ReservedB7: A(pV); @@ -6321,7 +6329,7 @@ llvm::Type *OP::GetOverloadType(OpCode opCode, llvm::Function *F) { case OpCode::HitObject_MakeMiss: case OpCode::HitObject_MakeNop: case OpCode::ReservedB5: - case OpCode::ReservedB6: + case OpCode::MaybeReorderThread: case OpCode::ReservedB7: case OpCode::ReservedB8: case OpCode::ReservedB9: diff --git a/lib/DxilValidation/DxilValidation.cpp b/lib/DxilValidation/DxilValidation.cpp index 0a2001a745..d4b6bb379f 100644 --- a/lib/DxilValidation/DxilValidation.cpp +++ b/lib/DxilValidation/DxilValidation.cpp @@ -1862,6 +1862,19 @@ static void ValidateDxilOperationCallInProfile(CallInst *CI, {"CreateHandleForLib", "Library"}); } break; + + // Shader Execution Reordering + case DXIL::OpCode::MaybeReorderThread: { + Value *CoherenceHintBits = CI->getArgOperand(2); + Value *NumCoherenceHintBits = CI->getArgOperand(3); + + if (isa(CoherenceHintBits) || + isa(NumCoherenceHintBits)) { + ValCtx.EmitInstrError( + CI, ValidationRule::InstrMayReorderThreadUndefCoherenceHintParam); + } + } break; + case DXIL::OpCode::AtomicBinOp: case DXIL::OpCode::AtomicCompareExchange: { Type *pOverloadType = OP::GetOverloadType(opcode, CI->getCalledFunction()); diff --git a/tools/clang/test/DXILValidation/ser_maybereorder_failing.ll b/tools/clang/test/DXILValidation/ser_maybereorder_failing.ll new file mode 100644 index 0000000000..b5e9e2c3fb --- /dev/null +++ b/tools/clang/test/DXILValidation/ser_maybereorder_failing.ll @@ -0,0 +1,50 @@ +; 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.HitObject = type { i8* } + +; Function Attrs: nounwind +define void @"\01?main@@YAXXZ"() #0 { + %nop = call %dx.types.HitObject @dx.op.hitObject_MakeNop(i32 266) ; HitObject_MakeNop() + +; Validate that coherence hint is not undef. + call void @dx.op.maybeReorderThread(i32 268, %dx.types.HitObject %nop, i32 undef, i32 0) ; MaybeReorderThread(hitObject,coherenceHint,numCoherenceHintBitsFromLSB) +; CHECK: Function: ?main@@YAXXZ: error: Use of undef coherence hint or num coherence hint bits in MaybeReorderThread. +; CHECK-NEXT: note: at 'call void @dx.op.maybeReorderThread(i32 268, %dx.types.HitObject %nop, i32 undef, i32 0)' + +; Validate that num coherence hint bits from LSB is not undef. + call void @dx.op.maybeReorderThread(i32 268, %dx.types.HitObject %nop, i32 1, i32 undef) ; MaybeReorderThread(hitObject,coherenceHint,numCoherenceHintBitsFromLSB) +; CHECK-NEXT: Function: ?main@@YAXXZ: error: Use of undef coherence hint or num coherence hint bits in MaybeReorderThread. +; CHECK-NEXT: note: at 'call void @dx.op.maybeReorderThread(i32 268, %dx.types.HitObject %nop, i32 1, i32 undef)' + ret void +} +; CHECK-NEXT: Validation failed. + +; Function Attrs: nounwind readnone +declare %dx.types.HitObject @dx.op.hitObject_MakeNop(i32) #1 + +; Function Attrs: nounwind +declare void @dx.op.maybeReorderThread(i32, %dx.types.HitObject, i32, i32) #0 + +attributes #0 = { nounwind } +attributes #1 = { nounwind readnone } + +!dx.version = !{!0} +!dx.valver = !{!0} +!dx.shaderModel = !{!1} +!dx.typeAnnotations = !{!2} +!dx.entryPoints = !{!6, !8} + +!0 = !{i32 1, i32 9} +!1 = !{!"lib", i32 6, i32 9} +!2 = !{i32 1, void ()* @"\01?main@@YAXXZ", !3} +!3 = !{!4} +!4 = !{i32 1, !5, !5} +!5 = !{} +!6 = !{null, !"", null, null, !7} +!7 = !{i32 0, i64 0} +!8 = !{void ()* @"\01?main@@YAXXZ", !"\01?main@@YAXXZ", null, null, !9} +!9 = !{i32 8, i32 7, i32 5, !10} +!10 = !{i32 0} diff --git a/tools/clang/test/DXILValidation/ser_maybereorder_passing.ll b/tools/clang/test/DXILValidation/ser_maybereorder_passing.ll new file mode 100644 index 0000000000..3d66015a05 --- /dev/null +++ b/tools/clang/test/DXILValidation/ser_maybereorder_passing.ll @@ -0,0 +1,43 @@ +; RUN: %dxv %s | FileCheck %s + +; CHECK: Validation succeeded. + +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.HitObject = type { i8* } + +; Function Attrs: nounwind +define void @"\01?main@@YAXXZ"() #0 { + %nop = call %dx.types.HitObject @dx.op.hitObject_MakeNop(i32 266) ; HitObject_MakeNop() + call void @dx.op.maybeReorderThread(i32 268, %dx.types.HitObject %nop, i32 241, i32 3) ; MaybeReorderThread(hitObject,coherenceHint,numCoherenceHintBitsFromLSB) + call void @dx.op.maybeReorderThread(i32 268, %dx.types.HitObject undef, i32 242, i32 7) ; MaybeReorderThread(hitObject,coherenceHint,numCoherenceHintBitsFromLSB) + ret void +} + +; Function Attrs: nounwind readnone +declare %dx.types.HitObject @dx.op.hitObject_MakeNop(i32) #1 + +; Function Attrs: nounwind +declare void @dx.op.maybeReorderThread(i32, %dx.types.HitObject, i32, i32) #0 + +attributes #0 = { nounwind } +attributes #1 = { nounwind readnone } + +!dx.version = !{!0} +!dx.valver = !{!0} +!dx.shaderModel = !{!1} +!dx.typeAnnotations = !{!2} +!dx.entryPoints = !{!6, !8} + +!0 = !{i32 1, i32 9} +!1 = !{!"lib", i32 6, i32 9} +!2 = !{i32 1, void ()* @"\01?main@@YAXXZ", !3} +!3 = !{!4} +!4 = !{i32 1, !5, !5} +!5 = !{} +!6 = !{null, !"", null, null, !7} +!7 = !{i32 0, i64 0} +!8 = !{void ()* @"\01?main@@YAXXZ", !"\01?main@@YAXXZ", null, null, !9} +!9 = !{i32 8, i32 7, i32 5, !10} +!10 = !{i32 0} diff --git a/utils/hct/hctdb.py b/utils/hct/hctdb.py index fc4c427580..625fb7d2a4 100644 --- a/utils/hct/hctdb.py +++ b/utils/hct/hctdb.py @@ -708,6 +708,11 @@ def populate_categories_and_models(self): "closesthit", "miss", ) + for i in ("MaybeReorderThread").split(","): + self.name_idx[i].shader_stages = ( + "library", + "raygeneration", + ) def populate_llvm_instructions(self): # Add instructions that map to LLVM instructions. @@ -5595,7 +5600,29 @@ def UFI(name, **mappings): ) next_op_idx += 1 - next_op_idx = self.reserve_dxil_op_range("ReservedB", next_op_idx, 26, 5) + next_op_idx = self.reserve_dxil_op_range("ReservedB", next_op_idx, 1, 5) + + self.add_dxil_op( + "MaybeReorderThread", + next_op_idx, + "MaybeReorderThread", + "Reorders the current thread. Optionally accepts a HitObject arg, or undef", + "v", + "", + [ + retvoid_param, + db_dxil_param(2, "hit_object", "hitObject", "hit"), + db_dxil_param(3, "i32", "coherenceHint", "Coherence hint"), + db_dxil_param( + 4, + "i32", + "numCoherenceHintBitsFromLSB", + "Num coherence hint bits from LSB", + ), + ], + ) + next_op_idx += 1 + next_op_idx = self.reserve_dxil_op_range("ReservedB", next_op_idx, 24, 7) # Reserved block C next_op_idx = self.reserve_dxil_op_range("ReservedC", next_op_idx, 10) @@ -7541,6 +7568,12 @@ def build_valrules(self): "Invalid use of completed record handle.", ) + # Shader Execution Reordering + self.add_valrule( + "Instr.MayReorderThreadUndefCoherenceHintParam", + "Use of undef coherence hint or num coherence hint bits in MaybeReorderThread.", + ) + # 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 0f4ef28e854aa44b0893ee93e4ce4d7d46ec70e6 Mon Sep 17 00:00:00 2001 From: Simon Moll Date: Fri, 11 Apr 2025 15:54:30 +0200 Subject: [PATCH 2/5] Validate HitObject/NumCoherenceBits is not undef / Validate CoherenceBits when NumBits != 0 / move tests to LitDXILValidation and update them --- lib/DxilValidation/DxilValidation.cpp | 17 +++++++++--- .../ser_maybereorder_failing.ll | 26 +++++++++++++------ .../ser_maybereorder_passing.ll | 5 +++- utils/hct/hctdb.py | 4 +++ 4 files changed, 40 insertions(+), 12 deletions(-) rename tools/clang/test/{DXILValidation => LitDXILValidation}/ser_maybereorder_failing.ll (66%) rename tools/clang/test/{DXILValidation => LitDXILValidation}/ser_maybereorder_passing.ll (87%) diff --git a/lib/DxilValidation/DxilValidation.cpp b/lib/DxilValidation/DxilValidation.cpp index fac5eeee30..63ad2d0cef 100644 --- a/lib/DxilValidation/DxilValidation.cpp +++ b/lib/DxilValidation/DxilValidation.cpp @@ -1874,14 +1874,25 @@ static void ValidateDxilOperationCallInProfile(CallInst *CI, // Shader Execution Reordering case DXIL::OpCode::MaybeReorderThread: { + Value *HitObject = CI->getArgOperand(1); Value *CoherenceHintBits = CI->getArgOperand(2); Value *NumCoherenceHintBits = CI->getArgOperand(3); - if (isa(CoherenceHintBits) || - isa(NumCoherenceHintBits)) { + if (isa(HitObject)) + ValCtx.EmitInstrError(CI, ValidationRule::InstrUndefHitObject); + + if (isa(NumCoherenceHintBits)) + ValCtx.EmitInstrError( + CI, ValidationRule::InstrMayReorderThreadUndefCoherenceHintParam); + + ConstantInt *NumCoherenceHintBitsConst = + dyn_cast(NumCoherenceHintBits); + const bool HasCoherenceHint = + NumCoherenceHintBitsConst && + NumCoherenceHintBitsConst->getLimitedValue() != 0; + if (HasCoherenceHint && isa(CoherenceHintBits)) ValCtx.EmitInstrError( CI, ValidationRule::InstrMayReorderThreadUndefCoherenceHintParam); - } } break; case DXIL::OpCode::AtomicBinOp: diff --git a/tools/clang/test/DXILValidation/ser_maybereorder_failing.ll b/tools/clang/test/LitDXILValidation/ser_maybereorder_failing.ll similarity index 66% rename from tools/clang/test/DXILValidation/ser_maybereorder_failing.ll rename to tools/clang/test/LitDXILValidation/ser_maybereorder_failing.ll index b5e9e2c3fb..4502b9241d 100644 --- a/tools/clang/test/DXILValidation/ser_maybereorder_failing.ll +++ b/tools/clang/test/LitDXILValidation/ser_maybereorder_failing.ll @@ -1,3 +1,4 @@ +; REQUIRES: dxil-1-9 ; 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" @@ -5,22 +6,31 @@ target triple = "dxil-ms-dx" %dx.types.HitObject = type { i8* } +; CHECK: Function: ?main@@YAXXZ: error: Use of undef coherence hint or num coherence hint bits in MaybeReorderThread. +; CHECK-NEXT: note: at 'call void @dx.op.maybeReorderThread(i32 268, %dx.types.HitObject %nop, i32 1, i32 undef)' + +; CHECK: Function: ?main@@YAXXZ: error: Use of undef coherence hint or num coherence hint bits in MaybeReorderThread. +; CHECK-NEXT: note: at 'call void @dx.op.maybeReorderThread(i32 268, %dx.types.HitObject %nop, i32 undef, i32 1)' + +; CHECK: Function: ?main@@YAXXZ: error: HitObject is undef. +; CHECK-NEXT: note: at 'call void @dx.op.maybeReorderThread(i32 268, %dx.types.HitObject undef, i32 11, i32 0)' + +; CHECK: Validation failed. + ; Function Attrs: nounwind define void @"\01?main@@YAXXZ"() #0 { %nop = call %dx.types.HitObject @dx.op.hitObject_MakeNop(i32 266) ; HitObject_MakeNop() -; Validate that coherence hint is not undef. - call void @dx.op.maybeReorderThread(i32 268, %dx.types.HitObject %nop, i32 undef, i32 0) ; MaybeReorderThread(hitObject,coherenceHint,numCoherenceHintBitsFromLSB) -; CHECK: Function: ?main@@YAXXZ: error: Use of undef coherence hint or num coherence hint bits in MaybeReorderThread. -; CHECK-NEXT: note: at 'call void @dx.op.maybeReorderThread(i32 268, %dx.types.HitObject %nop, i32 undef, i32 0)' + ; Validate that hit object is not undef. + call void @dx.op.maybeReorderThread(i32 268, %dx.types.HitObject undef, i32 11, i32 0) ; MaybeReorderThread(hitObject,coherenceHint,numCoherenceHintBitsFromLSB) -; Validate that num coherence hint bits from LSB is not undef. + ; Validate that coherence hint is not undef while numCoherenceHintBitsFromLSB is not 0. + call void @dx.op.maybeReorderThread(i32 268, %dx.types.HitObject %nop, i32 undef, i32 1) ; MaybeReorderThread(hitObject,coherenceHint,numCoherenceHintBitsFromLSB) + + ; Validate that num coherence hint bits from LSB is not undef. call void @dx.op.maybeReorderThread(i32 268, %dx.types.HitObject %nop, i32 1, i32 undef) ; MaybeReorderThread(hitObject,coherenceHint,numCoherenceHintBitsFromLSB) -; CHECK-NEXT: Function: ?main@@YAXXZ: error: Use of undef coherence hint or num coherence hint bits in MaybeReorderThread. -; CHECK-NEXT: note: at 'call void @dx.op.maybeReorderThread(i32 268, %dx.types.HitObject %nop, i32 1, i32 undef)' ret void } -; CHECK-NEXT: Validation failed. ; Function Attrs: nounwind readnone declare %dx.types.HitObject @dx.op.hitObject_MakeNop(i32) #1 diff --git a/tools/clang/test/DXILValidation/ser_maybereorder_passing.ll b/tools/clang/test/LitDXILValidation/ser_maybereorder_passing.ll similarity index 87% rename from tools/clang/test/DXILValidation/ser_maybereorder_passing.ll rename to tools/clang/test/LitDXILValidation/ser_maybereorder_passing.ll index 3d66015a05..8ee7677bd4 100644 --- a/tools/clang/test/DXILValidation/ser_maybereorder_passing.ll +++ b/tools/clang/test/LitDXILValidation/ser_maybereorder_passing.ll @@ -1,3 +1,4 @@ +; REQUIRES: dxil-1-9 ; RUN: %dxv %s | FileCheck %s ; CHECK: Validation succeeded. @@ -11,7 +12,9 @@ target triple = "dxil-ms-dx" define void @"\01?main@@YAXXZ"() #0 { %nop = call %dx.types.HitObject @dx.op.hitObject_MakeNop(i32 266) ; HitObject_MakeNop() call void @dx.op.maybeReorderThread(i32 268, %dx.types.HitObject %nop, i32 241, i32 3) ; MaybeReorderThread(hitObject,coherenceHint,numCoherenceHintBitsFromLSB) - call void @dx.op.maybeReorderThread(i32 268, %dx.types.HitObject undef, i32 242, i32 7) ; MaybeReorderThread(hitObject,coherenceHint,numCoherenceHintBitsFromLSB) + + ; Coherence hint disabled, accept 'undef' coherence hint bits. + call void @dx.op.maybeReorderThread(i32 268, %dx.types.HitObject %nop, i32 undef, i32 0) ; MaybeReorderThread(hitObject,coherenceHint,numCoherenceHintBitsFromLSB) ret void } diff --git a/utils/hct/hctdb.py b/utils/hct/hctdb.py index 03068b30d2..75e360de49 100644 --- a/utils/hct/hctdb.py +++ b/utils/hct/hctdb.py @@ -7831,6 +7831,10 @@ def build_valrules(self): ) # Shader Execution Reordering + self.add_valrule( + "Instr.UndefHitObject", + "HitObject is undef.", + ) self.add_valrule( "Instr.MayReorderThreadUndefCoherenceHintParam", "Use of undef coherence hint or num coherence hint bits in MaybeReorderThread.", From abd03a8797b5a4c2071f2243e4f56d60bfaa1715 Mon Sep 17 00:00:00 2001 From: Simon Moll Date: Mon, 14 Apr 2025 06:55:25 +0200 Subject: [PATCH 3/5] [nfc] Update MaybeReorderThread description (must not be 'undef' as said before) --- include/dxc/DXIL/DxilConstants.h | 3 +-- include/dxc/DXIL/DxilInstructions.h | 3 +-- utils/hct/hctdb.py | 2 +- 3 files changed, 3 insertions(+), 5 deletions(-) diff --git a/include/dxc/DXIL/DxilConstants.h b/include/dxc/DXIL/DxilConstants.h index 658bd9d79f..8c6803d410 100644 --- a/include/dxc/DXIL/DxilConstants.h +++ b/include/dxc/DXIL/DxilConstants.h @@ -487,8 +487,7 @@ inline bool IsFeedbackTexture(DXIL::ResourceKind ResourceKind) { // Enumeration for operations specified by DXIL enum class OpCode : unsigned { // - MaybeReorderThread = 268, // Reorders the current thread. Optionally accepts a - // HitObject arg, or undef + MaybeReorderThread = 268, // Reorders the current thread Reserved0 = 226, // Reserved Reserved1 = 227, // Reserved Reserved10 = 236, // Reserved diff --git a/include/dxc/DXIL/DxilInstructions.h b/include/dxc/DXIL/DxilInstructions.h index b116ff0514..09690c41b8 100644 --- a/include/dxc/DXIL/DxilInstructions.h +++ b/include/dxc/DXIL/DxilInstructions.h @@ -8987,8 +8987,7 @@ struct DxilInst_HitObject_MakeNop { bool requiresUniformInputs() const { return false; } }; -/// This instruction Reorders the current thread. Optionally accepts a HitObject -/// arg, or undef +/// This instruction Reorders the current thread struct DxilInst_MaybeReorderThread { llvm::Instruction *Instr; // Construction and identification diff --git a/utils/hct/hctdb.py b/utils/hct/hctdb.py index 7540cb5015..0cc6b7e047 100644 --- a/utils/hct/hctdb.py +++ b/utils/hct/hctdb.py @@ -5833,7 +5833,7 @@ def UFI(name, **mappings): "MaybeReorderThread", next_op_idx, "MaybeReorderThread", - "Reorders the current thread. Optionally accepts a HitObject arg, or undef", + "Reorders the current thread", "v", "", [ From 9328d0c851d03a322f092f26a268c7d157000024 Mon Sep 17 00:00:00 2001 From: Simon Moll Date: Mon, 14 Apr 2025 07:08:47 +0200 Subject: [PATCH 4/5] nfc: autformat hctdb.py --- utils/hct/hctdb.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/utils/hct/hctdb.py b/utils/hct/hctdb.py index 0cc6b7e047..19eae9b4bf 100644 --- a/utils/hct/hctdb.py +++ b/utils/hct/hctdb.py @@ -5845,7 +5845,9 @@ def UFI(name, **mappings): "i32", "numCoherenceHintBitsFromLSB", "Num coherence hint bits from LSB", - ),]) + ), + ], + ) next_op_idx += 1 self.add_dxil_op( From 6fa67b4e9959dd0c61205041a62baa4c86315855 Mon Sep 17 00:00:00 2001 From: Tex Riddell Date: Mon, 14 Apr 2025 10:42:13 -0700 Subject: [PATCH 5/5] Add category and shader model to MaybeReorderThread --- include/dxc/DXIL/DxilConstants.h | 60 ++++++++++++++++---------------- lib/DXIL/DxilOperations.cpp | 20 ++++------- utils/hct/hctdb.py | 2 ++ 3 files changed, 39 insertions(+), 43 deletions(-) diff --git a/include/dxc/DXIL/DxilConstants.h b/include/dxc/DXIL/DxilConstants.h index e91e79e016..8c73328fbd 100644 --- a/include/dxc/DXIL/DxilConstants.h +++ b/include/dxc/DXIL/DxilConstants.h @@ -487,35 +487,34 @@ inline bool IsFeedbackTexture(DXIL::ResourceKind ResourceKind) { // Enumeration for operations specified by DXIL enum class OpCode : unsigned { // - MaybeReorderThread = 268, // Reorders the current thread - Reserved0 = 226, // Reserved - Reserved1 = 227, // Reserved - Reserved10 = 236, // Reserved - Reserved11 = 237, // Reserved - Reserved2 = 228, // Reserved - Reserved3 = 229, // Reserved - Reserved4 = 230, // Reserved - Reserved5 = 231, // Reserved - Reserved6 = 232, // Reserved - Reserved7 = 233, // Reserved - Reserved8 = 234, // Reserved - Reserved9 = 235, // Reserved - ReservedA0 = 259, // reserved - ReservedA1 = 260, // reserved - ReservedA2 = 261, // reserved - ReservedB28 = 290, // reserved - ReservedB29 = 291, // reserved - ReservedB30 = 292, // reserved - ReservedC0 = 293, // reserved - ReservedC1 = 294, // reserved - ReservedC2 = 295, // reserved - ReservedC3 = 296, // reserved - ReservedC4 = 297, // reserved - ReservedC5 = 298, // reserved - ReservedC6 = 299, // reserved - ReservedC7 = 300, // reserved - ReservedC8 = 301, // reserved - ReservedC9 = 302, // reserved + Reserved0 = 226, // Reserved + Reserved1 = 227, // Reserved + Reserved10 = 236, // Reserved + Reserved11 = 237, // Reserved + Reserved2 = 228, // Reserved + Reserved3 = 229, // Reserved + Reserved4 = 230, // Reserved + Reserved5 = 231, // Reserved + Reserved6 = 232, // Reserved + Reserved7 = 233, // Reserved + Reserved8 = 234, // Reserved + Reserved9 = 235, // Reserved + ReservedA0 = 259, // reserved + ReservedA1 = 260, // reserved + ReservedA2 = 261, // reserved + ReservedB28 = 290, // reserved + ReservedB29 = 291, // reserved + ReservedB30 = 292, // reserved + ReservedC0 = 293, // reserved + ReservedC1 = 294, // reserved + ReservedC2 = 295, // reserved + ReservedC3 = 296, // reserved + ReservedC4 = 297, // reserved + ReservedC5 = 298, // reserved + ReservedC6 = 299, // reserved + ReservedC7 = 300, // reserved + ReservedC8 = 301, // reserved + ReservedC9 = 302, // reserved // Amplification shader instructions DispatchMesh = 173, // Amplification shader intrinsic DispatchMesh @@ -931,6 +930,7 @@ enum class OpCode : unsigned { HitObject_WorldRayOrigin = 275, // Returns the ray origin in world space HitObject_WorldToObject3x4 = 280, // Returns the world to object space // transformation matrix in 3x4 form + MaybeReorderThread = 268, // Reorders the current thread // Synchronization AtomicBinOp = 78, // performs an atomic operation on two operands @@ -1072,7 +1072,6 @@ enum class OpCode : unsigned { // Groups for DXIL operations with equivalent function templates enum class OpCodeClass : unsigned { // - MaybeReorderThread, Reserved, // Amplification shader instructions @@ -1320,6 +1319,7 @@ enum class OpCodeClass : unsigned { HitObject_StateScalar, HitObject_StateVector, HitObject_TraceRay, + MaybeReorderThread, // Synchronization AtomicBinOp, diff --git a/lib/DXIL/DxilOperations.cpp b/lib/DXIL/DxilOperations.cpp index a081109933..f614ba9d14 100644 --- a/lib/DXIL/DxilOperations.cpp +++ b/lib/DXIL/DxilOperations.cpp @@ -2353,8 +2353,6 @@ const OP::OpCodeProperty OP::m_OpCodeProps[(unsigned)OP::OpCode::NumOpCodes] = { 1, {{0x100}}, {{0x0}}}, // Overloads: u - - // {OC::MaybeReorderThread, "MaybeReorderThread", OCC::MaybeReorderThread, @@ -2363,8 +2361,6 @@ const OP::OpCodeProperty OP::m_OpCodeProps[(unsigned)OP::OpCode::NumOpCodes] = { 0, {}, {}}, // Overloads: v - - // Shader Execution Reordering {OC::HitObject_IsMiss, "HitObject_IsMiss", OCC::HitObject_StateScalar, @@ -3180,11 +3176,6 @@ void OP::GetMinShaderModelAndMask(OpCode C, bool bWithTranslation, SFLAG(Amplification) | SFLAG(Mesh) | SFLAG(Node); return; } - // Instructions: MaybeReorderThread=268 - if (op == 268) { - mask = SFLAG(Library) | SFLAG(RayGeneration); - return; - } // Instructions: RenderTargetGetSamplePosition=76, // RenderTargetGetSampleCount=77, Discard=82, EvalSnapped=87, // EvalSampleIndex=88, EvalCentroid=89, SampleIndex=90, Coverage=91, @@ -3455,6 +3446,13 @@ void OP::GetMinShaderModelAndMask(OpCode C, bool bWithTranslation, minor = 9; return; } + // Instructions: MaybeReorderThread=268 + if (op == 268) { + major = 6; + minor = 9; + mask = SFLAG(Library) | SFLAG(RayGeneration); + return; + } // Instructions: HitObject_TraceRay=262, HitObject_FromRayQuery=263, // HitObject_FromRayQueryWithAttrs=264, HitObject_MakeMiss=265, // HitObject_MakeNop=266, HitObject_Invoke=267, HitObject_IsMiss=269, @@ -5696,8 +5694,6 @@ Function *OP::GetOpFunc(OpCode opCode, Type *pOverloadType) { A(pHit); A(udt); break; - - // case OpCode::MaybeReorderThread: A(pV); A(pI32); @@ -5705,8 +5701,6 @@ Function *OP::GetOpFunc(OpCode opCode, Type *pOverloadType) { A(pI32); A(pI32); break; - - // Shader Execution Reordering case OpCode::HitObject_IsMiss: A(pI1); A(pI32); diff --git a/utils/hct/hctdb.py b/utils/hct/hctdb.py index bc7ff84f26..9b2f33727a 100644 --- a/utils/hct/hctdb.py +++ b/utils/hct/hctdb.py @@ -867,6 +867,8 @@ def populate_categories_and_models(self): "miss", ) for i in ("MaybeReorderThread").split(","): + self.name_idx[i].category = "Shader Execution Reordering" + self.name_idx[i].shader_model = 6, 9 self.name_idx[i].shader_stages = ( "library", "raygeneration",