diff --git a/include/dxc/DXIL/DxilConstants.h b/include/dxc/DXIL/DxilConstants.h index e002779d09..8c73328fbd 100644 --- a/include/dxc/DXIL/DxilConstants.h +++ b/include/dxc/DXIL/DxilConstants.h @@ -505,7 +505,6 @@ enum class OpCode : unsigned { ReservedB28 = 290, // reserved ReservedB29 = 291, // reserved ReservedB30 = 292, // reserved - ReservedB6 = 268, // reserved ReservedC0 = 293, // reserved ReservedC1 = 294, // reserved ReservedC2 = 295, // reserved @@ -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 @@ -1319,6 +1319,7 @@ enum class OpCodeClass : unsigned { HitObject_StateScalar, HitObject_StateVector, HitObject_TraceRay, + MaybeReorderThread, // Synchronization AtomicBinOp, @@ -1384,7 +1385,7 @@ enum class OpCodeClass : unsigned { NumOpClasses_Dxil_1_7 = 153, NumOpClasses_Dxil_1_8 = 174, - NumOpClasses = 189 // exclusive last value of enumeration + NumOpClasses = 190 // exclusive last value of enumeration }; // OPCODECLASS-ENUM:END diff --git a/include/dxc/DXIL/DxilInstructions.h b/include/dxc/DXIL/DxilInstructions.h index e39f754c68..a99c5360d4 100644 --- a/include/dxc/DXIL/DxilInstructions.h +++ b/include/dxc/DXIL/DxilInstructions.h @@ -9104,6 +9104,43 @@ struct DxilInst_HitObject_Invoke { void set_payload(llvm::Value *val) { Instr->setOperand(2, val); } }; +/// This instruction Reorders the current thread +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); + } +}; + /// This instruction Returns `true` if the HitObject represents a miss struct DxilInst_HitObject_IsMiss { llvm::Instruction *Instr; diff --git a/lib/DXIL/DxilOperations.cpp b/lib/DXIL/DxilOperations.cpp index b837d6e65d..f614ba9d14 100644 --- a/lib/DXIL/DxilOperations.cpp +++ b/lib/DXIL/DxilOperations.cpp @@ -2353,17 +2353,14 @@ const OP::OpCodeProperty OP::m_OpCodeProps[(unsigned)OP::OpCode::NumOpCodes] = { 1, {{0x100}}, {{0x0}}}, // Overloads: u - - {OC::ReservedB6, - "ReservedB6", - OCC::Reserved, - "reserved", + {OC::MaybeReorderThread, + "MaybeReorderThread", + OCC::MaybeReorderThread, + "maybeReorderThread", Attribute::None, 0, {}, {}}, // Overloads: v - - // Shader Execution Reordering {OC::HitObject_IsMiss, "HitObject_IsMiss", OCC::HitObject_StateScalar, @@ -3449,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, @@ -5690,14 +5694,13 @@ Function *OP::GetOpFunc(OpCode opCode, Type *pOverloadType) { A(pHit); A(udt); break; - - // - case OpCode::ReservedB6: + case OpCode::MaybeReorderThread: A(pV); A(pI32); + A(pHit); + A(pI32); + A(pI32); break; - - // Shader Execution Reordering case OpCode::HitObject_IsMiss: A(pI1); A(pI32); @@ -6158,7 +6161,7 @@ llvm::Type *OP::GetOverloadType(OpCode opCode, llvm::Function *F) { case OpCode::HitObject_FromRayQuery: case OpCode::HitObject_MakeMiss: case OpCode::HitObject_MakeNop: - case OpCode::ReservedB6: + case OpCode::MaybeReorderThread: case OpCode::HitObject_SetShaderTableIndex: case OpCode::HitObject_LoadLocalRootTableConstant: case OpCode::ReservedB28: diff --git a/lib/DxilValidation/DxilValidation.cpp b/lib/DxilValidation/DxilValidation.cpp index 5ec72e0267..00a6b9ae14 100644 --- a/lib/DxilValidation/DxilValidation.cpp +++ b/lib/DxilValidation/DxilValidation.cpp @@ -1886,6 +1886,30 @@ static void ValidateDxilOperationCallInProfile(CallInst *CI, {"CreateHandleForLib", "Library"}); } break; + + // Shader Execution Reordering + case DXIL::OpCode::MaybeReorderThread: { + Value *HitObject = CI->getArgOperand(1); + Value *CoherenceHintBits = CI->getArgOperand(2); + Value *NumCoherenceHintBits = CI->getArgOperand(3); + + 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: case DXIL::OpCode::AtomicCompareExchange: { Type *pOverloadType = OP::GetOverloadType(Opcode, CI->getCalledFunction()); diff --git a/tools/clang/test/LitDXILValidation/ser_maybereorder_failing.ll b/tools/clang/test/LitDXILValidation/ser_maybereorder_failing.ll new file mode 100644 index 0000000000..4502b9241d --- /dev/null +++ b/tools/clang/test/LitDXILValidation/ser_maybereorder_failing.ll @@ -0,0 +1,60 @@ +; 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" +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 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 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) + 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/tools/clang/test/LitDXILValidation/ser_maybereorder_passing.ll b/tools/clang/test/LitDXILValidation/ser_maybereorder_passing.ll new file mode 100644 index 0000000000..8ee7677bd4 --- /dev/null +++ b/tools/clang/test/LitDXILValidation/ser_maybereorder_passing.ll @@ -0,0 +1,46 @@ +; REQUIRES: dxil-1-9 +; 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) + + ; 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 +} + +; 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 595bad7c1b..9b2f33727a 100644 --- a/utils/hct/hctdb.py +++ b/utils/hct/hctdb.py @@ -866,6 +866,13 @@ def populate_categories_and_models(self): "closesthit", "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", + ) def populate_llvm_instructions(self): # Add instructions that map to LLVM instructions. @@ -5904,7 +5911,26 @@ def UFI(name, **mappings): ) next_op_idx += 1 - next_op_idx = self.reserve_dxil_op_range("ReservedB", next_op_idx, 1, 6) + self.add_dxil_op( + "MaybeReorderThread", + next_op_idx, + "MaybeReorderThread", + "Reorders the current thread", + "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 self.add_dxil_op( "HitObject_IsMiss", @@ -8267,6 +8293,16 @@ def build_valrules(self): "Invalid use of completed record handle.", ) + # 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.", + ) + # 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