Skip to content

[SER] MaybeReorderThread DXIL opcode and validation #7256

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 8 commits into from
Apr 14, 2025
5 changes: 3 additions & 2 deletions include/dxc/DXIL/DxilConstants.h
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -1319,6 +1319,7 @@ enum class OpCodeClass : unsigned {
HitObject_StateScalar,
HitObject_StateVector,
HitObject_TraceRay,
MaybeReorderThread,

// Synchronization
AtomicBinOp,
Expand Down Expand Up @@ -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

Expand Down
37 changes: 37 additions & 0 deletions include/dxc/DXIL/DxilInstructions.h
Original file line number Diff line number Diff line change
Expand Up @@ -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<llvm::CallInst>(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;
Expand Down
29 changes: 16 additions & 13 deletions lib/DXIL/DxilOperations.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down Expand Up @@ -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,
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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:
Expand Down
24 changes: 24 additions & 0 deletions lib/DxilValidation/DxilValidation.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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<UndefValue>(HitObject))
ValCtx.EmitInstrError(CI, ValidationRule::InstrUndefHitObject);

if (isa<UndefValue>(NumCoherenceHintBits))
ValCtx.EmitInstrError(
CI, ValidationRule::InstrMayReorderThreadUndefCoherenceHintParam);

ConstantInt *NumCoherenceHintBitsConst =
dyn_cast<ConstantInt>(NumCoherenceHintBits);
const bool HasCoherenceHint =
NumCoherenceHintBitsConst &&
NumCoherenceHintBitsConst->getLimitedValue() != 0;
if (HasCoherenceHint && isa<UndefValue>(CoherenceHintBits))
ValCtx.EmitInstrError(
CI, ValidationRule::InstrMayReorderThreadUndefCoherenceHintParam);
} break;

case DXIL::OpCode::AtomicBinOp:
case DXIL::OpCode::AtomicCompareExchange: {
Type *pOverloadType = OP::GetOverloadType(Opcode, CI->getCalledFunction());
Expand Down
60 changes: 60 additions & 0 deletions tools/clang/test/LitDXILValidation/ser_maybereorder_failing.ll
Original file line number Diff line number Diff line change
@@ -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}
46 changes: 46 additions & 0 deletions tools/clang/test/LitDXILValidation/ser_maybereorder_passing.ll
Original file line number Diff line number Diff line change
@@ -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}
38 changes: 37 additions & 1 deletion utils/hct/hctdb.py
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down Expand Up @@ -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",
Expand Down Expand Up @@ -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
Expand Down