Skip to content

Commit 98bc4c2

Browse files
authored
Implement DebugBreak and IsDebuggerPresent (#8106)
## Add `DebugBreak()` and `dx::IsDebuggerPresent()` intrinsics for shader debugging ### Description This PR adds two new intrinsics for shader debugging in experimental Shader Model 6.10: - **`DebugBreak()`** - Triggers a breakpoint if a debugger is attached - **`dx::IsDebuggerPresent()`** - Returns `true` if a debugger is attached ### Changes **HLSL Intrinsic Definitions:** - Added `DebugBreak()` to the base `Intrinsics` namespace in `gen_intrin_main.txt` - Added `IsDebuggerPresent()` to the `DxIntrinsics` namespace - Both require minimum shader model 6.10 **DXIL Operations:** - Added `DebugBreak` and `IsDebuggerPresent` DXIL opcodes in `hctdb.py` - `DebugBreak`: void return, no overload - `IsDebuggerPresent`: i1 (bool) return, no overload **Code Generation:** - Added HLSL to DXIL lowering in `HLOperationLower.cpp` - Added `LICOMPTYPE_BOOL` handling in `SemaHLSL.cpp` for `dx::` namespace intrinsic type resolution **SPIR-V Support:** - `DebugBreak()` emits `NonSemantic.DebugBreak` extended instruction - Added `SPV_KHR_non_semantic_info` extension enablement in `CapabilityVisitor.cpp` - `dx::IsDebuggerPresent()` produces an error (no Vulkan equivalent) **Tests:** - `debugbreak.hlsl` - DXIL codegen test - `debugbreak_sm69_error.hlsl` - Shader model version error test - `isdebugerpresent.hlsl` - DXIL codegen test - `intrinsics.debugbreak.hlsl` - SPIR-V codegen test - `intrinsics.isdebugerpresent.error.hlsl` - SPIR-V unsupported error test ### Related https://github.com/microsoft/hlsl-specs/blob/main/proposals/0039-debugbreak.md
1 parent ba54caa commit 98bc4c2

21 files changed

Lines changed: 385 additions & 8 deletions

docs/DXIL.rst

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3098,6 +3098,8 @@ ID Name Description
30983098
2147483678 LinAlgMatrixReserved0 reserved
30993099
2147483679 LinAlgMatrixReserved1 reserved
31003100
2147483680 LinAlgMatrixReserved2 reserved
3101+
2147483681 DebugBreak triggers a breakpoint if a debugger is attached
3102+
2147483682 IsDebuggerPresent returns true if a debugger is attached
31013103
========== ======================================== ===================================================================================================================
31023104

31033105

docs/ReleaseNotes.md

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,10 @@ line upon naming the release. Refer to previous for appropriate section names.
3131
- GetGroupWaveCount: New intrinsic for Compute, Mesh, Amplification and Node
3232
shaders which returns the total number of waves executing within the thread
3333
group.
34+
- Added `DebugBreak()` and `dx::IsDebuggerPresent()` intrinsics for shader debugging (experimental Shader Model 6.10).
35+
- `DebugBreak()` triggers a breakpoint if a debugger is attached.
36+
- `dx::IsDebuggerPresent()` returns true if a debugger is attached.
37+
- SPIR-V: `DebugBreak()` emits `NonSemantic.DebugBreak` extended instruction; `IsDebuggerPresent()` is not supported.
3438

3539
### Version 1.9.2602
3640

@@ -85,7 +89,6 @@ line upon naming the release. Refer to previous for appropriate section names.
8589
- Several small bug fixes.
8690

8791
#### Other Changes
88-
8992
- Fixed regression: [#7510](https://github.com/microsoft/DirectXShaderCompiler/issues/7510) crash when calling `sizeof` on templated type.
9093
- Fixed regression: [#7508](https://github.com/microsoft/DirectXShaderCompiler/issues/7508) crash when calling `Load` with `status`.
9194
- Header file `dxcpix.h` was added to the release package.

include/dxc/DXIL/DxilConstants.h

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -516,6 +516,10 @@ enum class OpCode : unsigned {
516516
LinAlgMatrixReserved1 = 31, // reserved
517517
LinAlgMatrixReserved2 = 32, // reserved
518518

519+
// Debugging
520+
DebugBreak = 33, // triggers a breakpoint if a debugger is attached
521+
IsDebuggerPresent = 34, // returns true if a debugger is attached
522+
519523
// Group Wave Ops
520524
GetGroupWaveCount = 2, // returns the number of waves in the thread group
521525
GetGroupWaveIndex = 1, // returns the index of the wave in the thread group
@@ -580,7 +584,7 @@ enum class OpCode : unsigned {
580584
HitObject_TriangleObjectPosition =
581585
10, // returns triangle vertices in object space as <9 x float>
582586

583-
NumOpCodes = 33, // exclusive last value of enumeration
587+
NumOpCodes = 35, // exclusive last value of enumeration
584588
};
585589
} // namespace ExperimentalOps
586590
static const unsigned NumOpCodeTables = 2;
@@ -1324,6 +1328,12 @@ enum class OpCode : unsigned {
13241328
EXP_OPCODE(ExperimentalOps, LinAlgMatrixReserved1), // reserved
13251329
// LinAlgMatrixReserved2 = 0x80000020, 2147483680U, -2147483616
13261330
EXP_OPCODE(ExperimentalOps, LinAlgMatrixReserved2), // reserved
1331+
// DebugBreak = 0x80000021, 2147483681U, -2147483615
1332+
EXP_OPCODE(ExperimentalOps,
1333+
DebugBreak), // triggers a breakpoint if a debugger is attached
1334+
// IsDebuggerPresent = 0x80000022, 2147483682U, -2147483614
1335+
EXP_OPCODE(ExperimentalOps,
1336+
IsDebuggerPresent), // returns true if a debugger is attached
13271337
};
13281338
// OPCODE-ENUM:END
13291339
#undef EXP_OPCODE
@@ -1386,6 +1396,10 @@ enum class OpCodeClass : unsigned {
13861396
IndexNodeHandle,
13871397
createNodeOutputHandle,
13881398

1399+
// Debugging
1400+
DebugBreak,
1401+
IsDebuggerPresent,
1402+
13891403
// Derivatives
13901404
CalculateLOD,
13911405
Unary,
@@ -1688,7 +1702,7 @@ enum class OpCodeClass : unsigned {
16881702
NodeOutputIsValid,
16891703
OutputComplete,
16901704

1691-
NumOpClasses = 223, // exclusive last value of enumeration
1705+
NumOpClasses = 225, // exclusive last value of enumeration
16921706
};
16931707
// OPCODECLASS-ENUM:END
16941708

include/dxc/DXIL/DxilInstructions.h

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11137,5 +11137,44 @@ struct DxilInst_MatrixOuterProduct {
1113711137
llvm::Value *get_vectorB() const { return Instr->getOperand(3); }
1113811138
void set_vectorB(llvm::Value *val) { Instr->setOperand(3, val); }
1113911139
};
11140+
11141+
/// This instruction triggers a breakpoint if a debugger is attached
11142+
struct DxilInst_DebugBreak {
11143+
llvm::Instruction *Instr;
11144+
// Construction and identification
11145+
DxilInst_DebugBreak(llvm::Instruction *pInstr) : Instr(pInstr) {}
11146+
operator bool() const {
11147+
return hlsl::OP::IsDxilOpFuncCallInst(Instr, hlsl::OP::OpCode::DebugBreak);
11148+
}
11149+
// Validation support
11150+
bool isAllowed() const { return true; }
11151+
bool isArgumentListValid() const {
11152+
if (1 != llvm::dyn_cast<llvm::CallInst>(Instr)->getNumArgOperands())
11153+
return false;
11154+
return true;
11155+
}
11156+
// Metadata
11157+
bool requiresUniformInputs() const { return false; }
11158+
};
11159+
11160+
/// This instruction returns true if a debugger is attached
11161+
struct DxilInst_IsDebuggerPresent {
11162+
llvm::Instruction *Instr;
11163+
// Construction and identification
11164+
DxilInst_IsDebuggerPresent(llvm::Instruction *pInstr) : Instr(pInstr) {}
11165+
operator bool() const {
11166+
return hlsl::OP::IsDxilOpFuncCallInst(Instr,
11167+
hlsl::OP::OpCode::IsDebuggerPresent);
11168+
}
11169+
// Validation support
11170+
bool isAllowed() const { return true; }
11171+
bool isArgumentListValid() const {
11172+
if (1 != llvm::dyn_cast<llvm::CallInst>(Instr)->getNumArgOperands())
11173+
return false;
11174+
return true;
11175+
}
11176+
// Metadata
11177+
bool requiresUniformInputs() const { return false; }
11178+
};
1114011179
// INSTR-HELPER:END
1114111180
} // namespace hlsl

include/dxc/HlslIntrinsicOp.h

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ enum class IntrinsicOp {
1616
IOP_ClusterID = 397,
1717
IOP_CreateResourceFromHeap = 8,
1818
IOP_D3DCOLORtoUBYTE4 = 9,
19+
IOP_DebugBreak = 425,
1920
IOP_DeviceMemoryBarrier = 10,
2021
IOP_DeviceMemoryBarrierWithGroupSync = 11,
2122
IOP_DispatchMesh = 12,
@@ -399,6 +400,7 @@ enum class IntrinsicOp {
399400
MOP_DxHitObject_SetShaderTableIndex = 388,
400401
MOP_DxHitObject_TraceRay = 389,
401402
MOP_DxHitObject_TriangleObjectPositions = 404,
403+
IOP_DxIsDebuggerPresent = 426,
402404
IOP_DxMaybeReorderThread = 359,
403405
MOP_Count = 328,
404406
MOP_FinishedCrossGroupSharing = 329,
@@ -431,7 +433,7 @@ enum class IntrinsicOp {
431433
IOP_usign = 355,
432434
MOP_InterlockedUMax = 356,
433435
MOP_InterlockedUMin = 357,
434-
Num_Intrinsics = 425,
436+
Num_Intrinsics = 427,
435437
};
436438
inline bool HasUnsignedIntrinsicOpcode(IntrinsicOp opcode) {
437439
switch (opcode) {

lib/DXIL/DxilOperations.cpp

Lines changed: 34 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3001,6 +3001,24 @@ static const OP::OpCodeProperty ExperimentalOps_OpCodeProps[] = {
30013001
0,
30023002
{},
30033003
{}}, // Overloads: v
3004+
3005+
// Debugging
3006+
{OC::DebugBreak,
3007+
"DebugBreak",
3008+
OCC::DebugBreak,
3009+
"debugBreak",
3010+
Attribute::NoDuplicate,
3011+
0,
3012+
{},
3013+
{}}, // Overloads: v
3014+
{OC::IsDebuggerPresent,
3015+
"IsDebuggerPresent",
3016+
OCC::IsDebuggerPresent,
3017+
"isDebuggerPresent",
3018+
Attribute::ReadOnly,
3019+
0,
3020+
{},
3021+
{}}, // Overloads: v
30043022
};
30053023
static_assert(_countof(ExperimentalOps_OpCodeProps) ==
30063024
(size_t)DXIL::ExperimentalOps::OpCode::NumOpCodes,
@@ -3919,12 +3937,14 @@ void OP::GetMinShaderModelAndMask(OpCode C, bool bWithTranslation,
39193937
// CreateMatrix=2147483659, MatrixLoadFromDescriptor=2147483662,
39203938
// MatrixQueryAccumulatorLayout=2147483670, MatrixVecMul=2147483673,
39213939
// MatrixVecMulAdd=2147483674, MatrixAccumulateToDescriptor=2147483675,
3922-
// MatrixOuterProduct=2147483677
3940+
// MatrixOuterProduct=2147483677, DebugBreak=2147483681,
3941+
// IsDebuggerPresent=2147483682
39233942
if ((305 <= op && op <= 308) || op == 2147483648 ||
39243943
(2147483652 <= op && op <= 2147483653) ||
39253944
(2147483656 <= op && op <= 2147483657) || op == 2147483659 ||
39263945
op == 2147483662 || op == 2147483670 ||
3927-
(2147483673 <= op && op <= 2147483675) || op == 2147483677) {
3946+
(2147483673 <= op && op <= 2147483675) || op == 2147483677 ||
3947+
(2147483681 <= op && op <= 2147483682)) {
39283948
major = 6;
39293949
minor = 10;
39303950
return;
@@ -6683,6 +6703,16 @@ Function *OP::GetOpFunc(OpCode opCode, Type *pOverloadType) {
66836703
A(pV);
66846704
A(pI32);
66856705
break;
6706+
6707+
// Debugging
6708+
case OpCode::DebugBreak:
6709+
A(pV);
6710+
A(pI32);
6711+
break;
6712+
case OpCode::IsDebuggerPresent:
6713+
A(pI1);
6714+
A(pI32);
6715+
break;
66866716
// OPCODE-OLOAD-FUNCS:END
66876717
default:
66886718
DXASSERT(false, "otherwise unhandled case");
@@ -6998,6 +7028,8 @@ llvm::Type *OP::GetOverloadType(OpCode opCode, llvm::Function *F) {
69987028
case OpCode::LinAlgMatrixReserved0:
69997029
case OpCode::LinAlgMatrixReserved1:
70007030
case OpCode::LinAlgMatrixReserved2:
7031+
case OpCode::DebugBreak:
7032+
case OpCode::IsDebuggerPresent:
70017033
return Type::getVoidTy(Ctx);
70027034
case OpCode::QuadVote:
70037035
return IntegerType::get(Ctx, 1);

lib/HLSL/HLOperationLower.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7697,6 +7697,10 @@ constexpr IntrinsicLower gLowerTable[] = {
76977697
DXIL::OpCode::MatrixVecMul},
76987698
{IntrinsicOp::IOP___builtin_LinAlg_MatrixVectorMultiplyAdd, EmptyLower,
76997699
DXIL::OpCode::MatrixVecMulAdd},
7700+
{IntrinsicOp::IOP_DebugBreak, TrivialNoArgOperation,
7701+
DXIL::OpCode::DebugBreak},
7702+
{IntrinsicOp::IOP_DxIsDebuggerPresent, TranslateWaveToVal,
7703+
DXIL::OpCode::IsDebuggerPresent},
77007704
};
77017705
constexpr size_t NumLowerTableEntries =
77027706
sizeof(gLowerTable) / sizeof(gLowerTable[0]);

tools/clang/include/clang/SPIRV/SpirvBuilder.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
#include "clang/SPIRV/SpirvInstruction.h"
1717
#include "clang/SPIRV/SpirvModule.h"
1818

19+
#include "spirv/unified1/NonSemanticDebugBreak.h"
1920
#include "spirv/unified1/NonSemanticDebugPrintf.h"
2021

2122
namespace clang {
@@ -434,6 +435,10 @@ class SpirvBuilder {
434435
QualType resultType, NonSemanticDebugPrintfInstructions instId,
435436
llvm::ArrayRef<SpirvInstruction *> operands, SourceLocation);
436437

438+
/// \brief Creates an OpExtInst instruction for the NonSemantic.DebugBreak
439+
/// extension set. Returns the resulting instruction pointer.
440+
SpirvInstruction *createNonSemanticDebugBreakExtInst(SourceLocation);
441+
437442
SpirvInstruction *createIsNodePayloadValid(SpirvInstruction *payloadArray,
438443
SpirvInstruction *nodeIndex,
439444
SourceLocation);

tools/clang/lib/SPIRV/CapabilityVisitor.cpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -794,6 +794,9 @@ bool CapabilityVisitor::visit(SpirvExtInstImport *instr) {
794794
"NonSemantic.Shader.DebugInfo.100") {
795795
addExtension(Extension::KHR_non_semantic_info, "Shader.DebugInfo.100",
796796
/*SourceLocation*/ {});
797+
} else if (instr->getExtendedInstSetName() == "NonSemantic.DebugBreak") {
798+
addExtension(Extension::KHR_non_semantic_info, "DebugBreak",
799+
/*SourceLocation*/ {});
797800
}
798801
return true;
799802
}

tools/clang/lib/SPIRV/SpirvBuilder.cpp

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -894,6 +894,16 @@ SpirvInstruction *SpirvBuilder::createNonSemanticDebugPrintfExtInst(
894894
return extInst;
895895
}
896896

897+
SpirvInstruction *
898+
SpirvBuilder::createNonSemanticDebugBreakExtInst(SourceLocation loc) {
899+
assert(insertPoint && "null insert point");
900+
auto *extInst = new (context) SpirvExtInst(
901+
astContext.VoidTy, loc, getExtInstSet("NonSemantic.DebugBreak"),
902+
NonSemanticDebugBreakDebugBreak, {});
903+
insertPoint->addInstruction(extInst);
904+
return extInst;
905+
}
906+
897907
SpirvInstruction *
898908
SpirvBuilder::createIsNodePayloadValid(SpirvInstruction *payloadArray,
899909
SpirvInstruction *nodeIndex,

0 commit comments

Comments
 (0)