Skip to content

Commit b5a9cd5

Browse files
authored
[SER] MaybeReorderThread DXIL opcode and validation (#7256)
- 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
1 parent 8280d0f commit b5a9cd5

File tree

7 files changed

+223
-16
lines changed

7 files changed

+223
-16
lines changed

include/dxc/DXIL/DxilConstants.h

+3-2
Original file line numberDiff line numberDiff line change
@@ -505,7 +505,6 @@ enum class OpCode : unsigned {
505505
ReservedB28 = 290, // reserved
506506
ReservedB29 = 291, // reserved
507507
ReservedB30 = 292, // reserved
508-
ReservedB6 = 268, // reserved
509508
ReservedC0 = 293, // reserved
510509
ReservedC1 = 294, // reserved
511510
ReservedC2 = 295, // reserved
@@ -931,6 +930,7 @@ enum class OpCode : unsigned {
931930
HitObject_WorldRayOrigin = 275, // Returns the ray origin in world space
932931
HitObject_WorldToObject3x4 = 280, // Returns the world to object space
933932
// transformation matrix in 3x4 form
933+
MaybeReorderThread = 268, // Reorders the current thread
934934

935935
// Synchronization
936936
AtomicBinOp = 78, // performs an atomic operation on two operands
@@ -1319,6 +1319,7 @@ enum class OpCodeClass : unsigned {
13191319
HitObject_StateScalar,
13201320
HitObject_StateVector,
13211321
HitObject_TraceRay,
1322+
MaybeReorderThread,
13221323

13231324
// Synchronization
13241325
AtomicBinOp,
@@ -1384,7 +1385,7 @@ enum class OpCodeClass : unsigned {
13841385
NumOpClasses_Dxil_1_7 = 153,
13851386
NumOpClasses_Dxil_1_8 = 174,
13861387

1387-
NumOpClasses = 189 // exclusive last value of enumeration
1388+
NumOpClasses = 190 // exclusive last value of enumeration
13881389
};
13891390
// OPCODECLASS-ENUM:END
13901391

include/dxc/DXIL/DxilInstructions.h

+37
Original file line numberDiff line numberDiff line change
@@ -9104,6 +9104,43 @@ struct DxilInst_HitObject_Invoke {
91049104
void set_payload(llvm::Value *val) { Instr->setOperand(2, val); }
91059105
};
91069106

9107+
/// This instruction Reorders the current thread
9108+
struct DxilInst_MaybeReorderThread {
9109+
llvm::Instruction *Instr;
9110+
// Construction and identification
9111+
DxilInst_MaybeReorderThread(llvm::Instruction *pInstr) : Instr(pInstr) {}
9112+
operator bool() const {
9113+
return hlsl::OP::IsDxilOpFuncCallInst(Instr,
9114+
hlsl::OP::OpCode::MaybeReorderThread);
9115+
}
9116+
// Validation support
9117+
bool isAllowed() const { return true; }
9118+
bool isArgumentListValid() const {
9119+
if (4 != llvm::dyn_cast<llvm::CallInst>(Instr)->getNumArgOperands())
9120+
return false;
9121+
return true;
9122+
}
9123+
// Metadata
9124+
bool requiresUniformInputs() const { return false; }
9125+
// Operand indexes
9126+
enum OperandIdx {
9127+
arg_hitObject = 1,
9128+
arg_coherenceHint = 2,
9129+
arg_numCoherenceHintBitsFromLSB = 3,
9130+
};
9131+
// Accessors
9132+
llvm::Value *get_hitObject() const { return Instr->getOperand(1); }
9133+
void set_hitObject(llvm::Value *val) { Instr->setOperand(1, val); }
9134+
llvm::Value *get_coherenceHint() const { return Instr->getOperand(2); }
9135+
void set_coherenceHint(llvm::Value *val) { Instr->setOperand(2, val); }
9136+
llvm::Value *get_numCoherenceHintBitsFromLSB() const {
9137+
return Instr->getOperand(3);
9138+
}
9139+
void set_numCoherenceHintBitsFromLSB(llvm::Value *val) {
9140+
Instr->setOperand(3, val);
9141+
}
9142+
};
9143+
91079144
/// This instruction Returns `true` if the HitObject represents a miss
91089145
struct DxilInst_HitObject_IsMiss {
91099146
llvm::Instruction *Instr;

lib/DXIL/DxilOperations.cpp

+16-13
Original file line numberDiff line numberDiff line change
@@ -2353,17 +2353,14 @@ const OP::OpCodeProperty OP::m_OpCodeProps[(unsigned)OP::OpCode::NumOpCodes] = {
23532353
1,
23542354
{{0x100}},
23552355
{{0x0}}}, // Overloads: u
2356-
2357-
{OC::ReservedB6,
2358-
"ReservedB6",
2359-
OCC::Reserved,
2360-
"reserved",
2356+
{OC::MaybeReorderThread,
2357+
"MaybeReorderThread",
2358+
OCC::MaybeReorderThread,
2359+
"maybeReorderThread",
23612360
Attribute::None,
23622361
0,
23632362
{},
23642363
{}}, // Overloads: v
2365-
2366-
// Shader Execution Reordering
23672364
{OC::HitObject_IsMiss,
23682365
"HitObject_IsMiss",
23692366
OCC::HitObject_StateScalar,
@@ -3449,6 +3446,13 @@ void OP::GetMinShaderModelAndMask(OpCode C, bool bWithTranslation,
34493446
minor = 9;
34503447
return;
34513448
}
3449+
// Instructions: MaybeReorderThread=268
3450+
if (op == 268) {
3451+
major = 6;
3452+
minor = 9;
3453+
mask = SFLAG(Library) | SFLAG(RayGeneration);
3454+
return;
3455+
}
34523456
// Instructions: HitObject_TraceRay=262, HitObject_FromRayQuery=263,
34533457
// HitObject_FromRayQueryWithAttrs=264, HitObject_MakeMiss=265,
34543458
// HitObject_MakeNop=266, HitObject_Invoke=267, HitObject_IsMiss=269,
@@ -5690,14 +5694,13 @@ Function *OP::GetOpFunc(OpCode opCode, Type *pOverloadType) {
56905694
A(pHit);
56915695
A(udt);
56925696
break;
5693-
5694-
//
5695-
case OpCode::ReservedB6:
5697+
case OpCode::MaybeReorderThread:
56965698
A(pV);
56975699
A(pI32);
5700+
A(pHit);
5701+
A(pI32);
5702+
A(pI32);
56985703
break;
5699-
5700-
// Shader Execution Reordering
57015704
case OpCode::HitObject_IsMiss:
57025705
A(pI1);
57035706
A(pI32);
@@ -6158,7 +6161,7 @@ llvm::Type *OP::GetOverloadType(OpCode opCode, llvm::Function *F) {
61586161
case OpCode::HitObject_FromRayQuery:
61596162
case OpCode::HitObject_MakeMiss:
61606163
case OpCode::HitObject_MakeNop:
6161-
case OpCode::ReservedB6:
6164+
case OpCode::MaybeReorderThread:
61626165
case OpCode::HitObject_SetShaderTableIndex:
61636166
case OpCode::HitObject_LoadLocalRootTableConstant:
61646167
case OpCode::ReservedB28:

lib/DxilValidation/DxilValidation.cpp

+24
Original file line numberDiff line numberDiff line change
@@ -1886,6 +1886,30 @@ static void ValidateDxilOperationCallInProfile(CallInst *CI,
18861886
{"CreateHandleForLib", "Library"});
18871887
}
18881888
break;
1889+
1890+
// Shader Execution Reordering
1891+
case DXIL::OpCode::MaybeReorderThread: {
1892+
Value *HitObject = CI->getArgOperand(1);
1893+
Value *CoherenceHintBits = CI->getArgOperand(2);
1894+
Value *NumCoherenceHintBits = CI->getArgOperand(3);
1895+
1896+
if (isa<UndefValue>(HitObject))
1897+
ValCtx.EmitInstrError(CI, ValidationRule::InstrUndefHitObject);
1898+
1899+
if (isa<UndefValue>(NumCoherenceHintBits))
1900+
ValCtx.EmitInstrError(
1901+
CI, ValidationRule::InstrMayReorderThreadUndefCoherenceHintParam);
1902+
1903+
ConstantInt *NumCoherenceHintBitsConst =
1904+
dyn_cast<ConstantInt>(NumCoherenceHintBits);
1905+
const bool HasCoherenceHint =
1906+
NumCoherenceHintBitsConst &&
1907+
NumCoherenceHintBitsConst->getLimitedValue() != 0;
1908+
if (HasCoherenceHint && isa<UndefValue>(CoherenceHintBits))
1909+
ValCtx.EmitInstrError(
1910+
CI, ValidationRule::InstrMayReorderThreadUndefCoherenceHintParam);
1911+
} break;
1912+
18891913
case DXIL::OpCode::AtomicBinOp:
18901914
case DXIL::OpCode::AtomicCompareExchange: {
18911915
Type *pOverloadType = OP::GetOverloadType(Opcode, CI->getCalledFunction());
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
; REQUIRES: dxil-1-9
2+
; RUN: not %dxv %s 2>&1 | FileCheck %s
3+
4+
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+
target triple = "dxil-ms-dx"
6+
7+
%dx.types.HitObject = type { i8* }
8+
9+
; CHECK: Function: ?main@@YAXXZ: error: Use of undef coherence hint or num coherence hint bits in MaybeReorderThread.
10+
; CHECK-NEXT: note: at 'call void @dx.op.maybeReorderThread(i32 268, %dx.types.HitObject %nop, i32 1, i32 undef)'
11+
12+
; CHECK: Function: ?main@@YAXXZ: error: Use of undef coherence hint or num coherence hint bits in MaybeReorderThread.
13+
; CHECK-NEXT: note: at 'call void @dx.op.maybeReorderThread(i32 268, %dx.types.HitObject %nop, i32 undef, i32 1)'
14+
15+
; CHECK: Function: ?main@@YAXXZ: error: HitObject is undef.
16+
; CHECK-NEXT: note: at 'call void @dx.op.maybeReorderThread(i32 268, %dx.types.HitObject undef, i32 11, i32 0)'
17+
18+
; CHECK: Validation failed.
19+
20+
; Function Attrs: nounwind
21+
define void @"\01?main@@YAXXZ"() #0 {
22+
%nop = call %dx.types.HitObject @dx.op.hitObject_MakeNop(i32 266) ; HitObject_MakeNop()
23+
24+
; Validate that hit object is not undef.
25+
call void @dx.op.maybeReorderThread(i32 268, %dx.types.HitObject undef, i32 11, i32 0) ; MaybeReorderThread(hitObject,coherenceHint,numCoherenceHintBitsFromLSB)
26+
27+
; Validate that coherence hint is not undef while numCoherenceHintBitsFromLSB is not 0.
28+
call void @dx.op.maybeReorderThread(i32 268, %dx.types.HitObject %nop, i32 undef, i32 1) ; MaybeReorderThread(hitObject,coherenceHint,numCoherenceHintBitsFromLSB)
29+
30+
; Validate that num coherence hint bits from LSB is not undef.
31+
call void @dx.op.maybeReorderThread(i32 268, %dx.types.HitObject %nop, i32 1, i32 undef) ; MaybeReorderThread(hitObject,coherenceHint,numCoherenceHintBitsFromLSB)
32+
ret void
33+
}
34+
35+
; Function Attrs: nounwind readnone
36+
declare %dx.types.HitObject @dx.op.hitObject_MakeNop(i32) #1
37+
38+
; Function Attrs: nounwind
39+
declare void @dx.op.maybeReorderThread(i32, %dx.types.HitObject, i32, i32) #0
40+
41+
attributes #0 = { nounwind }
42+
attributes #1 = { nounwind readnone }
43+
44+
!dx.version = !{!0}
45+
!dx.valver = !{!0}
46+
!dx.shaderModel = !{!1}
47+
!dx.typeAnnotations = !{!2}
48+
!dx.entryPoints = !{!6, !8}
49+
50+
!0 = !{i32 1, i32 9}
51+
!1 = !{!"lib", i32 6, i32 9}
52+
!2 = !{i32 1, void ()* @"\01?main@@YAXXZ", !3}
53+
!3 = !{!4}
54+
!4 = !{i32 1, !5, !5}
55+
!5 = !{}
56+
!6 = !{null, !"", null, null, !7}
57+
!7 = !{i32 0, i64 0}
58+
!8 = !{void ()* @"\01?main@@YAXXZ", !"\01?main@@YAXXZ", null, null, !9}
59+
!9 = !{i32 8, i32 7, i32 5, !10}
60+
!10 = !{i32 0}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
; REQUIRES: dxil-1-9
2+
; RUN: %dxv %s | FileCheck %s
3+
4+
; CHECK: Validation succeeded.
5+
6+
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"
7+
target triple = "dxil-ms-dx"
8+
9+
%dx.types.HitObject = type { i8* }
10+
11+
; Function Attrs: nounwind
12+
define void @"\01?main@@YAXXZ"() #0 {
13+
%nop = call %dx.types.HitObject @dx.op.hitObject_MakeNop(i32 266) ; HitObject_MakeNop()
14+
call void @dx.op.maybeReorderThread(i32 268, %dx.types.HitObject %nop, i32 241, i32 3) ; MaybeReorderThread(hitObject,coherenceHint,numCoherenceHintBitsFromLSB)
15+
16+
; Coherence hint disabled, accept 'undef' coherence hint bits.
17+
call void @dx.op.maybeReorderThread(i32 268, %dx.types.HitObject %nop, i32 undef, i32 0) ; MaybeReorderThread(hitObject,coherenceHint,numCoherenceHintBitsFromLSB)
18+
ret void
19+
}
20+
21+
; Function Attrs: nounwind readnone
22+
declare %dx.types.HitObject @dx.op.hitObject_MakeNop(i32) #1
23+
24+
; Function Attrs: nounwind
25+
declare void @dx.op.maybeReorderThread(i32, %dx.types.HitObject, i32, i32) #0
26+
27+
attributes #0 = { nounwind }
28+
attributes #1 = { nounwind readnone }
29+
30+
!dx.version = !{!0}
31+
!dx.valver = !{!0}
32+
!dx.shaderModel = !{!1}
33+
!dx.typeAnnotations = !{!2}
34+
!dx.entryPoints = !{!6, !8}
35+
36+
!0 = !{i32 1, i32 9}
37+
!1 = !{!"lib", i32 6, i32 9}
38+
!2 = !{i32 1, void ()* @"\01?main@@YAXXZ", !3}
39+
!3 = !{!4}
40+
!4 = !{i32 1, !5, !5}
41+
!5 = !{}
42+
!6 = !{null, !"", null, null, !7}
43+
!7 = !{i32 0, i64 0}
44+
!8 = !{void ()* @"\01?main@@YAXXZ", !"\01?main@@YAXXZ", null, null, !9}
45+
!9 = !{i32 8, i32 7, i32 5, !10}
46+
!10 = !{i32 0}

utils/hct/hctdb.py

+37-1
Original file line numberDiff line numberDiff line change
@@ -866,6 +866,13 @@ def populate_categories_and_models(self):
866866
"closesthit",
867867
"miss",
868868
)
869+
for i in ("MaybeReorderThread").split(","):
870+
self.name_idx[i].category = "Shader Execution Reordering"
871+
self.name_idx[i].shader_model = 6, 9
872+
self.name_idx[i].shader_stages = (
873+
"library",
874+
"raygeneration",
875+
)
869876

870877
def populate_llvm_instructions(self):
871878
# Add instructions that map to LLVM instructions.
@@ -5904,7 +5911,26 @@ def UFI(name, **mappings):
59045911
)
59055912
next_op_idx += 1
59065913

5907-
next_op_idx = self.reserve_dxil_op_range("ReservedB", next_op_idx, 1, 6)
5914+
self.add_dxil_op(
5915+
"MaybeReorderThread",
5916+
next_op_idx,
5917+
"MaybeReorderThread",
5918+
"Reorders the current thread",
5919+
"v",
5920+
"",
5921+
[
5922+
retvoid_param,
5923+
db_dxil_param(2, "hit_object", "hitObject", "hit"),
5924+
db_dxil_param(3, "i32", "coherenceHint", "Coherence hint"),
5925+
db_dxil_param(
5926+
4,
5927+
"i32",
5928+
"numCoherenceHintBitsFromLSB",
5929+
"Num coherence hint bits from LSB",
5930+
),
5931+
],
5932+
)
5933+
next_op_idx += 1
59085934

59095935
self.add_dxil_op(
59105936
"HitObject_IsMiss",
@@ -8267,6 +8293,16 @@ def build_valrules(self):
82678293
"Invalid use of completed record handle.",
82688294
)
82698295

8296+
# Shader Execution Reordering
8297+
self.add_valrule(
8298+
"Instr.UndefHitObject",
8299+
"HitObject is undef.",
8300+
)
8301+
self.add_valrule(
8302+
"Instr.MayReorderThreadUndefCoherenceHintParam",
8303+
"Use of undef coherence hint or num coherence hint bits in MaybeReorderThread.",
8304+
)
8305+
82708306
# Some legacy rules:
82718307
# - space is only supported for shader targets 5.1 and higher
82728308
# - multiple rules regarding derivatives, which isn't a supported feature for DXIL

0 commit comments

Comments
 (0)