Skip to content

Commit d8ebd34

Browse files
committed
[SER] HitObject_MakeNop|Miss DXIL opcodes and verification tests
Specification: https://github.com/microsoft/hlsl-specs/blob/main/proposals/0027-shader-execution-reordering.md DXC SER implementation tracker: #7214
1 parent b646ad3 commit d8ebd34

File tree

7 files changed

+230
-22
lines changed

7 files changed

+230
-22
lines changed

include/dxc/DXIL/DxilConstants.h

+9-3
Original file line numberDiff line numberDiff line change
@@ -520,9 +520,7 @@ enum class OpCode : unsigned {
520520
ReservedB27 = 289, // reserved
521521
ReservedB28 = 290, // reserved
522522
ReservedB29 = 291, // reserved
523-
ReservedB3 = 265, // reserved
524523
ReservedB30 = 292, // reserved
525-
ReservedB4 = 266, // reserved
526524
ReservedB5 = 267, // reserved
527525
ReservedB6 = 268, // reserved
528526
ReservedB7 = 269, // reserved
@@ -909,6 +907,10 @@ enum class OpCode : unsigned {
909907
WriteSamplerFeedbackLevel = 176, // updates a feedback texture for a sampling
910908
// operation with a mipmap-level offset
911909

910+
// Shader Execution Reordering
911+
HitObject_MakeMiss = 265, // Creates a new HitObject representing a miss
912+
HitObject_MakeNop = 266, // Creates an empty nop HitObject
913+
912914
// Synchronization
913915
AtomicBinOp = 78, // performs an atomic operation on two operands
914916
AtomicCompareExchange = 79, // atomic compare and exchange to memory
@@ -1281,6 +1283,10 @@ enum class OpCodeClass : unsigned {
12811283
WriteSamplerFeedbackGrad,
12821284
WriteSamplerFeedbackLevel,
12831285

1286+
// Shader Execution Reordering
1287+
HitObject_MakeMiss,
1288+
HitObject_MakeNop,
1289+
12841290
// Synchronization
12851291
AtomicBinOp,
12861292
AtomicCompareExchange,
@@ -1345,7 +1351,7 @@ enum class OpCodeClass : unsigned {
13451351
NumOpClasses_Dxil_1_7 = 153,
13461352
NumOpClasses_Dxil_1_8 = 174,
13471353

1348-
NumOpClasses = 175 // exclusive last value of enumeration
1354+
NumOpClasses = 177 // exclusive last value of enumeration
13491355
};
13501356
// OPCODECLASS-ENUM:END
13511357

include/dxc/DXIL/DxilInstructions.h

+74
Original file line numberDiff line numberDiff line change
@@ -8813,5 +8813,79 @@ struct DxilInst_AllocateRayQuery2 {
88138813
llvm::APInt(32, (uint64_t)val)));
88148814
}
88158815
};
8816+
8817+
/// This instruction Creates a new HitObject representing a miss
8818+
struct DxilInst_HitObject_MakeMiss {
8819+
llvm::Instruction *Instr;
8820+
// Construction and identification
8821+
DxilInst_HitObject_MakeMiss(llvm::Instruction *pInstr) : Instr(pInstr) {}
8822+
operator bool() const {
8823+
return hlsl::OP::IsDxilOpFuncCallInst(Instr,
8824+
hlsl::OP::OpCode::HitObject_MakeMiss);
8825+
}
8826+
// Validation support
8827+
bool isAllowed() const { return true; }
8828+
bool isArgumentListValid() const {
8829+
if (11 != llvm::dyn_cast<llvm::CallInst>(Instr)->getNumArgOperands())
8830+
return false;
8831+
return true;
8832+
}
8833+
// Metadata
8834+
bool requiresUniformInputs() const { return false; }
8835+
// Operand indexes
8836+
enum OperandIdx {
8837+
arg_RayFlags = 1,
8838+
arg_MissShaderIndex = 2,
8839+
arg_Origin_X = 3,
8840+
arg_Origin_Y = 4,
8841+
arg_Origin_Z = 5,
8842+
arg_TMin = 6,
8843+
arg_Direction_X = 7,
8844+
arg_Direction_Y = 8,
8845+
arg_Direction_Z = 9,
8846+
arg_TMax = 10,
8847+
};
8848+
// Accessors
8849+
llvm::Value *get_RayFlags() const { return Instr->getOperand(1); }
8850+
void set_RayFlags(llvm::Value *val) { Instr->setOperand(1, val); }
8851+
llvm::Value *get_MissShaderIndex() const { return Instr->getOperand(2); }
8852+
void set_MissShaderIndex(llvm::Value *val) { Instr->setOperand(2, val); }
8853+
llvm::Value *get_Origin_X() const { return Instr->getOperand(3); }
8854+
void set_Origin_X(llvm::Value *val) { Instr->setOperand(3, val); }
8855+
llvm::Value *get_Origin_Y() const { return Instr->getOperand(4); }
8856+
void set_Origin_Y(llvm::Value *val) { Instr->setOperand(4, val); }
8857+
llvm::Value *get_Origin_Z() const { return Instr->getOperand(5); }
8858+
void set_Origin_Z(llvm::Value *val) { Instr->setOperand(5, val); }
8859+
llvm::Value *get_TMin() const { return Instr->getOperand(6); }
8860+
void set_TMin(llvm::Value *val) { Instr->setOperand(6, val); }
8861+
llvm::Value *get_Direction_X() const { return Instr->getOperand(7); }
8862+
void set_Direction_X(llvm::Value *val) { Instr->setOperand(7, val); }
8863+
llvm::Value *get_Direction_Y() const { return Instr->getOperand(8); }
8864+
void set_Direction_Y(llvm::Value *val) { Instr->setOperand(8, val); }
8865+
llvm::Value *get_Direction_Z() const { return Instr->getOperand(9); }
8866+
void set_Direction_Z(llvm::Value *val) { Instr->setOperand(9, val); }
8867+
llvm::Value *get_TMax() const { return Instr->getOperand(10); }
8868+
void set_TMax(llvm::Value *val) { Instr->setOperand(10, val); }
8869+
};
8870+
8871+
/// This instruction Creates an empty nop HitObject
8872+
struct DxilInst_HitObject_MakeNop {
8873+
llvm::Instruction *Instr;
8874+
// Construction and identification
8875+
DxilInst_HitObject_MakeNop(llvm::Instruction *pInstr) : Instr(pInstr) {}
8876+
operator bool() const {
8877+
return hlsl::OP::IsDxilOpFuncCallInst(Instr,
8878+
hlsl::OP::OpCode::HitObject_MakeNop);
8879+
}
8880+
// Validation support
8881+
bool isAllowed() const { return true; }
8882+
bool isArgumentListValid() const {
8883+
if (1 != llvm::dyn_cast<llvm::CallInst>(Instr)->getNumArgOperands())
8884+
return false;
8885+
return true;
8886+
}
8887+
// Metadata
8888+
bool requiresUniformInputs() const { return false; }
8889+
};
88168890
// INSTR-HELPER:END
88178891
} // namespace hlsl

include/dxc/DXIL/DxilOperations.h

+2
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,7 @@ class OP {
6464
void RemoveFunction(llvm::Function *F);
6565
llvm::LLVMContext &GetCtx() { return m_Ctx; }
6666
llvm::Type *GetHandleType() const;
67+
llvm::Type *GetHitObjectType() const;
6768
llvm::Type *GetNodeHandleType() const;
6869
llvm::Type *GetNodeRecordHandleType() const;
6970
llvm::Type *GetResourcePropertiesType() const;
@@ -146,6 +147,7 @@ class OP {
146147
llvm::Module *m_pModule;
147148

148149
llvm::Type *m_pHandleType;
150+
llvm::Type *m_pHitObjectType;
149151
llvm::Type *m_pNodeHandleType;
150152
llvm::Type *m_pNodeRecordHandleType;
151153
llvm::Type *m_pResourcePropertiesType;

lib/DXIL/DxilOperations.cpp

+48-16
Original file line numberDiff line numberDiff line change
@@ -2670,24 +2670,29 @@ const OP::OpCodeProperty OP::m_OpCodeProps[(unsigned)OP::OpCode::NumOpCodes] = {
26702670
false},
26712671
Attribute::None,
26722672
},
2673+
2674+
// Shader Execution Reordering void, h, f, d, i1, i8, i16,
2675+
// i32, i64, udt, obj , function attribute
26732676
{
2674-
OC::ReservedB3,
2675-
"ReservedB3",
2676-
OCC::Reserved,
2677-
"reserved",
2677+
OC::HitObject_MakeMiss,
2678+
"HitObject_MakeMiss",
2679+
OCC::HitObject_MakeMiss,
2680+
"hitObject_MakeMiss",
26782681
{true, false, false, false, false, false, false, false, false, false,
26792682
false},
2680-
Attribute::None,
2683+
Attribute::ReadNone,
26812684
},
26822685
{
2683-
OC::ReservedB4,
2684-
"ReservedB4",
2685-
OCC::Reserved,
2686-
"reserved",
2686+
OC::HitObject_MakeNop,
2687+
"HitObject_MakeNop",
2688+
OCC::HitObject_MakeNop,
2689+
"hitObject_MakeNop",
26872690
{true, false, false, false, false, false, false, false, false, false,
26882691
false},
2689-
Attribute::None,
2692+
Attribute::ReadNone,
26902693
},
2694+
2695+
// void, h, f, d, i1, i8, i16, i32, i64, udt, obj , function attribute
26912696
{
26922697
OC::ReservedB5,
26932698
"ReservedB5",
@@ -3750,6 +3755,14 @@ void OP::GetMinShaderModelAndMask(OpCode C, bool bWithTranslation,
37503755
minor = 9;
37513756
return;
37523757
}
3758+
// Instructions: HitObject_MakeMiss=265, HitObject_MakeNop=266
3759+
if ((265 <= op && op <= 266)) {
3760+
major = 6;
3761+
minor = 9;
3762+
mask =
3763+
SFLAG(Library) | SFLAG(RayGeneration) | SFLAG(ClosestHit) | SFLAG(Miss);
3764+
return;
3765+
}
37533766
// OPCODE-SMMASK:END
37543767
}
37553768

@@ -3851,6 +3864,8 @@ OP::OP(LLVMContext &Ctx, Module *pModule)
38513864

38523865
m_pHandleType = GetOrCreateStructType(m_Ctx, Type::getInt8PtrTy(m_Ctx),
38533866
"dx.types.Handle", pModule);
3867+
m_pHitObjectType = GetOrCreateStructType(m_Ctx, Type::getInt8PtrTy(m_Ctx),
3868+
"dx.types.HitObject", pModule);
38543869
m_pNodeHandleType = GetOrCreateStructType(m_Ctx, Type::getInt8PtrTy(m_Ctx),
38553870
"dx.types.NodeHandle", pModule);
38563871
m_pNodeRecordHandleType = GetOrCreateStructType(
@@ -3993,6 +4008,7 @@ Function *OP::GetOpFunc(OpCode opCode, Type *pOverloadType) {
39934008
Type *pF64 = Type::getDoubleTy(m_Ctx);
39944009
Type *pSDT = GetSplitDoubleType(); // Split double type.
39954010
Type *p4I32 = GetFourI32Type(); // 4 i32s in a struct.
4011+
Type *pHit = GetHitObjectType();
39964012

39974013
Type *udt = pOverloadType;
39984014
Type *obj = pOverloadType;
@@ -5871,14 +5887,28 @@ Function *OP::GetOpFunc(OpCode opCode, Type *pOverloadType) {
58715887
A(pV);
58725888
A(pI32);
58735889
break;
5874-
case OpCode::ReservedB3:
5875-
A(pV);
5890+
5891+
// Shader Execution Reordering
5892+
case OpCode::HitObject_MakeMiss:
5893+
A(pHit);
5894+
A(pI32);
5895+
A(pI32);
58765896
A(pI32);
5897+
A(pF32);
5898+
A(pF32);
5899+
A(pF32);
5900+
A(pF32);
5901+
A(pF32);
5902+
A(pF32);
5903+
A(pF32);
5904+
A(pF32);
58775905
break;
5878-
case OpCode::ReservedB4:
5879-
A(pV);
5906+
case OpCode::HitObject_MakeNop:
5907+
A(pHit);
58805908
A(pI32);
58815909
break;
5910+
5911+
//
58825912
case OpCode::ReservedB5:
58835913
A(pV);
58845914
A(pI32);
@@ -6288,8 +6318,8 @@ llvm::Type *OP::GetOverloadType(OpCode opCode, llvm::Function *F) {
62886318
case OpCode::ReservedB0:
62896319
case OpCode::ReservedB1:
62906320
case OpCode::ReservedB2:
6291-
case OpCode::ReservedB3:
6292-
case OpCode::ReservedB4:
6321+
case OpCode::HitObject_MakeMiss:
6322+
case OpCode::HitObject_MakeNop:
62936323
case OpCode::ReservedB5:
62946324
case OpCode::ReservedB6:
62956325
case OpCode::ReservedB7:
@@ -6431,6 +6461,8 @@ Type *OP::GetHandleType() const { return m_pHandleType; }
64316461

64326462
Type *OP::GetNodeHandleType() const { return m_pNodeHandleType; }
64336463

6464+
Type *OP::GetHitObjectType() const { return m_pHitObjectType; }
6465+
64346466
Type *OP::GetNodeRecordHandleType() const { return m_pNodeRecordHandleType; }
64356467

64366468
Type *OP::GetResourcePropertiesType() const {
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
; RUN: %dxv %s | FileCheck %s
2+
3+
; CHECK: Validation succeeded.
4+
5+
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"
6+
target triple = "dxil-ms-dx"
7+
8+
%dx.types.HitObject = type { i8* }
9+
10+
; Function Attrs: nounwind
11+
define void @"\01?main@@YAXXZ"() #0 {
12+
; Test HitObject_MakeMiss (opcode 265)
13+
%r265 = call %dx.types.HitObject @dx.op.hitObject_MakeMiss(i32 265, i32 4, i32 0, float 0.000000e+00, float 0.000000e+00, float 0.000000e+00, float 0.000000e+00, float 1.000000e+00, float 0.000000e+00, float 0.000000e+00, float 9.999000e+03) ; HitObject_MakeMiss(RayFlags,MissShaderIndex,Origin_X,Origin_Y,Origin_Z,TMin,Direction_X,Direction_Y,Direction_Z,TMax)
14+
15+
; Test HitObject_MakeNop (opcode 266)
16+
%r266 = call %dx.types.HitObject @dx.op.hitObject_MakeNop(i32 266) ; HitObject_MakeNop()
17+
18+
ret void
19+
}
20+
21+
; Function Attrs: nounwind readnone
22+
declare %dx.types.HitObject @dx.op.hitObject_MakeMiss(i32, i32, i32, float, float, float, float, float, float, float, float) #1
23+
24+
; Function Attrs: nounwind readnone
25+
declare %dx.types.HitObject @dx.op.hitObject_MakeNop(i32) #1
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 = !{!9, !11}
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+
!9 = !{null, !"", null, null, !10}
43+
!10 = !{i32 0, i64 0}
44+
!11 = !{void ()* @"\01?main@@YAXXZ", !"\01?main@@YAXXZ", null, null, !12}
45+
!12 = !{i32 8, i32 7, i32 5, !13}
46+
!13 = !{i32 0}

utils/hct/hctdb.py

+50-3
Original file line numberDiff line numberDiff line change
@@ -699,6 +699,15 @@ def populate_categories_and_models(self):
699699
self.name_idx[i].category = "Extended Command Information"
700700
self.name_idx[i].shader_stages = ("vertex",)
701701
self.name_idx[i].shader_model = 6, 8
702+
for i in ("HitObject_MakeMiss,HitObject_MakeNop").split(","):
703+
self.name_idx[i].category = "Shader Execution Reordering"
704+
self.name_idx[i].shader_model = 6, 9
705+
self.name_idx[i].shader_stages = (
706+
"library",
707+
"raygeneration",
708+
"closesthit",
709+
"miss",
710+
)
702711

703712
def populate_llvm_instructions(self):
704713
# Add instructions that map to LLVM instructions.
@@ -5550,7 +5559,43 @@ def UFI(name, **mappings):
55505559
next_op_idx = self.reserve_dxil_op_range("ReservedA", next_op_idx, 3)
55515560

55525561
# Shader Execution Reordering
5553-
next_op_idx = self.reserve_dxil_op_range("ReservedB", next_op_idx, 31)
5562+
next_op_idx = self.reserve_dxil_op_range("ReservedB", next_op_idx, 3)
5563+
5564+
self.add_dxil_op(
5565+
"HitObject_MakeMiss",
5566+
next_op_idx,
5567+
"HitObject_MakeMiss",
5568+
"Creates a new HitObject representing a miss",
5569+
"v",
5570+
"rn",
5571+
[
5572+
db_dxil_param(0, "hit_object", "", "HitObject with a committed miss"),
5573+
db_dxil_param(2, "i32", "RayFlags", "ray flags"),
5574+
db_dxil_param(3, "i32", "MissShaderIndex", "Miss shader index"),
5575+
db_dxil_param(4, "f", "Origin_X", "Origin x of the ray"),
5576+
db_dxil_param(5, "f", "Origin_Y", "Origin y of the ray"),
5577+
db_dxil_param(6, "f", "Origin_Z", "Origin z of the ray"),
5578+
db_dxil_param(7, "f", "TMin", "Tmin of the ray"),
5579+
db_dxil_param(8, "f", "Direction_X", "Direction x of the ray"),
5580+
db_dxil_param(9, "f", "Direction_Y", "Direction y of the ray"),
5581+
db_dxil_param(10, "f", "Direction_Z", "Direction z of the ray"),
5582+
db_dxil_param(11, "f", "TMax", "Tmax of the ray"),
5583+
],
5584+
)
5585+
next_op_idx += 1
5586+
5587+
self.add_dxil_op(
5588+
"HitObject_MakeNop",
5589+
next_op_idx,
5590+
"HitObject_MakeNop",
5591+
"Creates an empty nop HitObject",
5592+
"v",
5593+
"rn",
5594+
[db_dxil_param(0, "hit_object", "", "Empty nop HitObject")],
5595+
)
5596+
next_op_idx += 1
5597+
5598+
next_op_idx = self.reserve_dxil_op_range("ReservedB", next_op_idx, 26, 5)
55545599

55555600
# Reserved block C
55565601
next_op_idx = self.reserve_dxil_op_range("ReservedC", next_op_idx, 10)
@@ -8145,10 +8190,12 @@ def add_dxil_op_reserved(self, name, code_id):
81458190
)
81468191
self.instr.append(i)
81478192

8148-
def reserve_dxil_op_range(self, group_name, start_id, count):
8193+
def reserve_dxil_op_range(self, group_name, start_id, count, start_reserved_id=0):
81498194
"Reserve a range of dxil opcodes for future use; returns next id"
81508195
for i in range(0, count):
8151-
self.add_dxil_op_reserved("{0}{1}".format(group_name, i), start_id + i)
8196+
self.add_dxil_op_reserved(
8197+
"{0}{1}".format(group_name, start_reserved_id + i), start_id + i
8198+
)
81528199
return start_id + count
81538200

81548201
def get_instr_by_llvm_name(self, llvm_name):

utils/hct/hctdb_instrhelp.py

+1
Original file line numberDiff line numberDiff line change
@@ -620,6 +620,7 @@ def print_opfunc_table(self):
620620
"noderecordhandle": "A(pNodeRecordHandle);",
621621
"nodeproperty": "A(nodeProperty);",
622622
"noderecordproperty": "A(nodeRecordProperty);",
623+
"hit_object": "A(pHit);",
623624
}
624625
last_category = None
625626
for i in self.instrs:

0 commit comments

Comments
 (0)