From 8717ac5140375b823c036c9a74200e53e8348b9c Mon Sep 17 00:00:00 2001 From: Jack Elliott Date: Wed, 28 Jan 2026 11:47:58 +1300 Subject: [PATCH 01/11] Implement DebugBreak and IsDebuggerPresent --- docs/DXIL.rst | 2 + docs/ReleaseNotes.md | 4 ++ include/dxc/DXIL/DxilConstants.h | 16 +++++++- include/dxc/DXIL/DxilInstructions.h | 39 +++++++++++++++++++ include/dxc/HlslIntrinsicOp.h | 4 +- lib/DXIL/DxilOperations.cpp | 36 ++++++++++++++++- lib/HLSL/HLOperationLower.cpp | 4 ++ .../clang/include/clang/SPIRV/SpirvBuilder.h | 5 +++ tools/clang/lib/SPIRV/CapabilityVisitor.cpp | 3 ++ tools/clang/lib/SPIRV/SpirvBuilder.cpp | 10 +++++ tools/clang/lib/SPIRV/SpirvEmitter.cpp | 4 ++ tools/clang/lib/Sema/SemaHLSL.cpp | 3 ++ .../CodeGenSPIRV/intrinsics.debugbreak.hlsl | 12 ++++++ .../intrinsics.isdebugerpresent.error.hlsl | 12 ++++++ .../hlsl/intrinsics/basic/debugbreak.hlsl | 12 ++++++ .../intrinsics/basic/isdebugerpresent.hlsl | 16 ++++++++ utils/hct/gen_intrin_main.txt | 2 + utils/hct/hctdb.py | 28 +++++++++++++ utils/hct/hlsl_intrinsic_opcodes.json | 6 ++- 19 files changed, 211 insertions(+), 7 deletions(-) create mode 100644 tools/clang/test/CodeGenSPIRV/intrinsics.debugbreak.hlsl create mode 100644 tools/clang/test/CodeGenSPIRV/intrinsics.isdebugerpresent.error.hlsl create mode 100644 tools/clang/test/HLSLFileCheckLit/hlsl/intrinsics/basic/debugbreak.hlsl create mode 100644 tools/clang/test/HLSLFileCheckLit/hlsl/intrinsics/basic/isdebugerpresent.hlsl diff --git a/docs/DXIL.rst b/docs/DXIL.rst index a5f0536c4e..c8adc0e32a 100644 --- a/docs/DXIL.rst +++ b/docs/DXIL.rst @@ -3098,6 +3098,8 @@ ID Name Description 2147483678 LinAlgMatrixReserved0 reserved 2147483679 LinAlgMatrixReserved1 reserved 2147483680 LinAlgMatrixReserved2 reserved +2147483681 DebugBreak triggers a breakpoint if debugger is attached +2147483682 IsDebuggerPresent returns true if debugger is attached ========== ======================================== =================================================================================================================== diff --git a/docs/ReleaseNotes.md b/docs/ReleaseNotes.md index 05f07b4cac..76231b55d2 100644 --- a/docs/ReleaseNotes.md +++ b/docs/ReleaseNotes.md @@ -19,6 +19,10 @@ The included licenses apply to the following files: ### Upcoming Release +- Added `DebugBreak()` and `dx::IsDebuggerPresent()` intrinsics for shader debugging (experimental Shader Model 6.10). + - `DebugBreak()` triggers a breakpoint if a debugger is attached. + - `dx::IsDebuggerPresent()` returns true if a debugger is attached. + - SPIR-V: `DebugBreak()` emits `NonSemantic.DebugBreak` extended instruction; `IsDebuggerPresent()` is not supported. - Fixed regression: [#7510](https://github.com/microsoft/DirectXShaderCompiler/issues/7510) crash when calling `sizeof` on templated type. - Fixed regression: [#7508](https://github.com/microsoft/DirectXShaderCompiler/issues/7508) crash when calling `Load` with `status`. - Header file `dxcpix.h` was added to the release package. diff --git a/include/dxc/DXIL/DxilConstants.h b/include/dxc/DXIL/DxilConstants.h index 2c00080ada..3b7b2edb96 100644 --- a/include/dxc/DXIL/DxilConstants.h +++ b/include/dxc/DXIL/DxilConstants.h @@ -516,6 +516,10 @@ enum class OpCode : unsigned { LinAlgMatrixReserved1 = 31, // reserved LinAlgMatrixReserved2 = 32, // reserved + // Debugging + DebugBreak = 33, // triggers a breakpoint if debugger is attached + IsDebuggerPresent = 34, // returns true if debugger is attached + // Group Wave Ops GetGroupWaveCount = 2, // returns the number of waves in the thread group GetGroupWaveIndex = 1, // returns the index of the wave in the thread group @@ -580,7 +584,7 @@ enum class OpCode : unsigned { HitObject_TriangleObjectPosition = 10, // returns triangle vertices in object space as <9 x float> - NumOpCodes = 33, // exclusive last value of enumeration + NumOpCodes = 35, // exclusive last value of enumeration }; } // namespace ExperimentalOps static const unsigned NumOpCodeTables = 2; @@ -1289,6 +1293,10 @@ enum class OpCode : unsigned { EXP_OPCODE(ExperimentalOps, LinAlgMatrixReserved0), // reserved EXP_OPCODE(ExperimentalOps, LinAlgMatrixReserved1), // reserved EXP_OPCODE(ExperimentalOps, LinAlgMatrixReserved2), // reserved + EXP_OPCODE(ExperimentalOps, + DebugBreak), // triggers a breakpoint if debugger is attached + EXP_OPCODE(ExperimentalOps, + IsDebuggerPresent), // returns true if debugger is attached }; // OPCODE-ENUM:END #undef EXP_OPCODE @@ -1351,6 +1359,10 @@ enum class OpCodeClass : unsigned { IndexNodeHandle, createNodeOutputHandle, + // Debugging + DebugBreak, + IsDebuggerPresent, + // Derivatives CalculateLOD, Unary, @@ -1653,7 +1665,7 @@ enum class OpCodeClass : unsigned { NodeOutputIsValid, OutputComplete, - NumOpClasses = 223, // exclusive last value of enumeration + NumOpClasses = 225, // exclusive last value of enumeration }; // OPCODECLASS-ENUM:END diff --git a/include/dxc/DXIL/DxilInstructions.h b/include/dxc/DXIL/DxilInstructions.h index d78912a217..fdf99db26b 100644 --- a/include/dxc/DXIL/DxilInstructions.h +++ b/include/dxc/DXIL/DxilInstructions.h @@ -11137,5 +11137,44 @@ struct DxilInst_MatrixOuterProduct { llvm::Value *get_vectorB() const { return Instr->getOperand(3); } void set_vectorB(llvm::Value *val) { Instr->setOperand(3, val); } }; + +/// This instruction triggers a breakpoint if debugger is attached +struct DxilInst_DebugBreak { + llvm::Instruction *Instr; + // Construction and identification + DxilInst_DebugBreak(llvm::Instruction *pInstr) : Instr(pInstr) {} + operator bool() const { + return hlsl::OP::IsDxilOpFuncCallInst(Instr, hlsl::OP::OpCode::DebugBreak); + } + // Validation support + bool isAllowed() const { return true; } + bool isArgumentListValid() const { + if (1 != llvm::dyn_cast(Instr)->getNumArgOperands()) + return false; + return true; + } + // Metadata + bool requiresUniformInputs() const { return false; } +}; + +/// This instruction returns true if debugger is attached +struct DxilInst_IsDebuggerPresent { + llvm::Instruction *Instr; + // Construction and identification + DxilInst_IsDebuggerPresent(llvm::Instruction *pInstr) : Instr(pInstr) {} + operator bool() const { + return hlsl::OP::IsDxilOpFuncCallInst(Instr, + hlsl::OP::OpCode::IsDebuggerPresent); + } + // Validation support + bool isAllowed() const { return true; } + bool isArgumentListValid() const { + if (1 != llvm::dyn_cast(Instr)->getNumArgOperands()) + return false; + return true; + } + // Metadata + bool requiresUniformInputs() const { return false; } +}; // INSTR-HELPER:END } // namespace hlsl diff --git a/include/dxc/HlslIntrinsicOp.h b/include/dxc/HlslIntrinsicOp.h index 24e35b3719..1c7f2dd7b3 100644 --- a/include/dxc/HlslIntrinsicOp.h +++ b/include/dxc/HlslIntrinsicOp.h @@ -16,6 +16,7 @@ enum class IntrinsicOp { IOP_ClusterID = 397, IOP_CreateResourceFromHeap = 8, IOP_D3DCOLORtoUBYTE4 = 9, + IOP_DebugBreak = 425, IOP_DeviceMemoryBarrier = 10, IOP_DeviceMemoryBarrierWithGroupSync = 11, IOP_DispatchMesh = 12, @@ -399,6 +400,7 @@ enum class IntrinsicOp { MOP_DxHitObject_SetShaderTableIndex = 388, MOP_DxHitObject_TraceRay = 389, MOP_DxHitObject_TriangleObjectPosition = 404, + IOP_DxIsDebuggerPresent = 426, IOP_DxMaybeReorderThread = 359, MOP_Count = 328, MOP_FinishedCrossGroupSharing = 329, @@ -431,7 +433,7 @@ enum class IntrinsicOp { IOP_usign = 355, MOP_InterlockedUMax = 356, MOP_InterlockedUMin = 357, - Num_Intrinsics = 425, + Num_Intrinsics = 427, }; inline bool HasUnsignedIntrinsicOpcode(IntrinsicOp opcode) { switch (opcode) { diff --git a/lib/DXIL/DxilOperations.cpp b/lib/DXIL/DxilOperations.cpp index 183d656a2e..f4eca2f4bc 100644 --- a/lib/DXIL/DxilOperations.cpp +++ b/lib/DXIL/DxilOperations.cpp @@ -3001,6 +3001,24 @@ static const OP::OpCodeProperty ExperimentalOps_OpCodeProps[] = { 0, {}, {}}, // Overloads: v + + // Debugging + {OC::DebugBreak, + "DebugBreak", + OCC::DebugBreak, + "debugBreak", + Attribute::NoDuplicate, + 0, + {}, + {}}, // Overloads: v + {OC::IsDebuggerPresent, + "IsDebuggerPresent", + OCC::IsDebuggerPresent, + "isDebuggerPresent", + Attribute::ReadOnly, + 0, + {}, + {}}, // Overloads: v }; static_assert(_countof(ExperimentalOps_OpCodeProps) == (size_t)DXIL::ExperimentalOps::OpCode::NumOpCodes, @@ -3925,11 +3943,13 @@ void OP::GetMinShaderModelAndMask(OpCode C, bool bWithTranslation, // MatrixMulOp=2147483671, MatrixAccumulate=2147483672, // MatrixVecMul=2147483673, MatrixVecMulAdd=2147483674, // MatrixAccumulateToDescriptor=2147483675, - // MatrixAccumulateToMemory=2147483676, MatrixOuterProduct=2147483677 + // MatrixAccumulateToMemory=2147483676, MatrixOuterProduct=2147483677, + // DebugBreak=2147483681, IsDebuggerPresent=2147483682 if ((305 <= op && op <= 308) || op == 2147483648 || (2147483652 <= op && op <= 2147483653) || (2147483656 <= op && op <= 2147483657) || - (2147483659 <= op && op <= 2147483677)) { + (2147483659 <= op && op <= 2147483677) || + (2147483681 <= op && op <= 2147483682)) { major = 6; minor = 10; return; @@ -6677,6 +6697,16 @@ Function *OP::GetOpFunc(OpCode opCode, Type *pOverloadType) { A(pV); A(pI32); break; + + // Debugging + case OpCode::DebugBreak: + A(pV); + A(pI32); + break; + case OpCode::IsDebuggerPresent: + A(pI1); + A(pI32); + break; // OPCODE-OLOAD-FUNCS:END default: DXASSERT(false, "otherwise unhandled case"); @@ -6992,6 +7022,8 @@ llvm::Type *OP::GetOverloadType(OpCode opCode, llvm::Function *F) { case OpCode::LinAlgMatrixReserved0: case OpCode::LinAlgMatrixReserved1: case OpCode::LinAlgMatrixReserved2: + case OpCode::DebugBreak: + case OpCode::IsDebuggerPresent: return Type::getVoidTy(Ctx); case OpCode::QuadVote: return IntegerType::get(Ctx, 1); diff --git a/lib/HLSL/HLOperationLower.cpp b/lib/HLSL/HLOperationLower.cpp index 69ce941178..b65fd317da 100644 --- a/lib/HLSL/HLOperationLower.cpp +++ b/lib/HLSL/HLOperationLower.cpp @@ -7577,6 +7577,10 @@ constexpr IntrinsicLower gLowerTable[] = { DXIL::OpCode::MatrixVecMul}, {IntrinsicOp::IOP___builtin_LinAlg_MatrixVectorMultiplyAdd, EmptyLower, DXIL::OpCode::MatrixVecMulAdd}, + {IntrinsicOp::IOP_DebugBreak, TrivialNoArgOperation, + DXIL::OpCode::DebugBreak}, + {IntrinsicOp::IOP_DxIsDebuggerPresent, TranslateWaveToVal, + DXIL::OpCode::IsDebuggerPresent}, }; constexpr size_t NumLowerTableEntries = sizeof(gLowerTable) / sizeof(gLowerTable[0]); diff --git a/tools/clang/include/clang/SPIRV/SpirvBuilder.h b/tools/clang/include/clang/SPIRV/SpirvBuilder.h index 1d012568d6..122f461a5f 100644 --- a/tools/clang/include/clang/SPIRV/SpirvBuilder.h +++ b/tools/clang/include/clang/SPIRV/SpirvBuilder.h @@ -16,6 +16,7 @@ #include "clang/SPIRV/SpirvInstruction.h" #include "clang/SPIRV/SpirvModule.h" +#include "spirv/unified1/NonSemanticDebugBreak.h" #include "spirv/unified1/NonSemanticDebugPrintf.h" namespace clang { @@ -434,6 +435,10 @@ class SpirvBuilder { QualType resultType, NonSemanticDebugPrintfInstructions instId, llvm::ArrayRef operands, SourceLocation); + /// \brief Creates an OpExtInst instruction for the NonSemantic.DebugBreak + /// extension set. Returns the resulting instruction pointer. + SpirvInstruction *createNonSemanticDebugBreakExtInst(SourceLocation); + SpirvInstruction *createIsNodePayloadValid(SpirvInstruction *payloadArray, SpirvInstruction *nodeIndex, SourceLocation); diff --git a/tools/clang/lib/SPIRV/CapabilityVisitor.cpp b/tools/clang/lib/SPIRV/CapabilityVisitor.cpp index 389dc6eed4..20e9b2b45e 100644 --- a/tools/clang/lib/SPIRV/CapabilityVisitor.cpp +++ b/tools/clang/lib/SPIRV/CapabilityVisitor.cpp @@ -794,6 +794,9 @@ bool CapabilityVisitor::visit(SpirvExtInstImport *instr) { "NonSemantic.Shader.DebugInfo.100") { addExtension(Extension::KHR_non_semantic_info, "Shader.DebugInfo.100", /*SourceLocation*/ {}); + } else if (instr->getExtendedInstSetName() == "NonSemantic.DebugBreak") { + addExtension(Extension::KHR_non_semantic_info, "DebugBreak", + /*SourceLocation*/ {}); } return true; } diff --git a/tools/clang/lib/SPIRV/SpirvBuilder.cpp b/tools/clang/lib/SPIRV/SpirvBuilder.cpp index 86701f48fd..3d6a4d4756 100644 --- a/tools/clang/lib/SPIRV/SpirvBuilder.cpp +++ b/tools/clang/lib/SPIRV/SpirvBuilder.cpp @@ -894,6 +894,16 @@ SpirvInstruction *SpirvBuilder::createNonSemanticDebugPrintfExtInst( return extInst; } +SpirvInstruction * +SpirvBuilder::createNonSemanticDebugBreakExtInst(SourceLocation loc) { + assert(insertPoint && "null insert point"); + auto *extInst = new (context) + SpirvExtInst(astContext.VoidTy, loc, getExtInstSet("NonSemantic.DebugBreak"), + NonSemanticDebugBreakDebugBreak, {}); + insertPoint->addInstruction(extInst); + return extInst; +} + SpirvInstruction * SpirvBuilder::createIsNodePayloadValid(SpirvInstruction *payloadArray, SpirvInstruction *nodeIndex, diff --git a/tools/clang/lib/SPIRV/SpirvEmitter.cpp b/tools/clang/lib/SPIRV/SpirvEmitter.cpp index e9fec851ba..64303ec47d 100644 --- a/tools/clang/lib/SPIRV/SpirvEmitter.cpp +++ b/tools/clang/lib/SPIRV/SpirvEmitter.cpp @@ -9323,6 +9323,9 @@ SpirvEmitter::processIntrinsicCallExpr(const CallExpr *callExpr) { /*groupSync*/ true, /*isAllBarrier*/ true); break; + case hlsl::IntrinsicOp::IOP_DebugBreak: + retVal = spvBuilder.createNonSemanticDebugBreakExtInst(srcLoc); + break; case hlsl::IntrinsicOp::IOP_GetRemainingRecursionLevels: retVal = processIntrinsicGetRemainingRecursionLevels(callExpr); break; @@ -9543,6 +9546,7 @@ SpirvEmitter::processIntrinsicCallExpr(const CallExpr *callExpr) { retVal = processWaveQuadAnyAll(callExpr, hlslOpcode); break; case hlsl::IntrinsicOp::IOP_abort: + case hlsl::IntrinsicOp::IOP_DxIsDebuggerPresent: case hlsl::IntrinsicOp::IOP_GetRenderTargetSampleCount: case hlsl::IntrinsicOp::IOP_GetRenderTargetSamplePosition: { emitError("no equivalent for %0 intrinsic function in Vulkan", srcLoc) diff --git a/tools/clang/lib/Sema/SemaHLSL.cpp b/tools/clang/lib/Sema/SemaHLSL.cpp index e9c8c90a2d..2828b467ca 100644 --- a/tools/clang/lib/Sema/SemaHLSL.cpp +++ b/tools/clang/lib/Sema/SemaHLSL.cpp @@ -3599,6 +3599,9 @@ class HLSLExternalSource : public ExternalSemaSource { case LICOMPTYPE_UINT: paramTypes.push_back(context.UnsignedIntTy); break; + case LICOMPTYPE_BOOL: + paramTypes.push_back(context.BoolTy); + break; case LICOMPTYPE_VOID: paramTypes.push_back(context.VoidTy); break; diff --git a/tools/clang/test/CodeGenSPIRV/intrinsics.debugbreak.hlsl b/tools/clang/test/CodeGenSPIRV/intrinsics.debugbreak.hlsl new file mode 100644 index 0000000000..b9b60aebb0 --- /dev/null +++ b/tools/clang/test/CodeGenSPIRV/intrinsics.debugbreak.hlsl @@ -0,0 +1,12 @@ +// RUN: %dxc -T cs_6_10 -spirv %s | FileCheck %s + +// CHECK: OpExtension "SPV_KHR_non_semantic_info" +// CHECK: OpExtInstImport "NonSemantic.DebugBreak" +// CHECK: OpExtInst %void {{%[0-9]+}} 1 + +[numthreads(8, 8, 1)] +void main(uint3 threadId : SV_DispatchThreadID) { + if (threadId.x == 0) { + DebugBreak(); + } +} diff --git a/tools/clang/test/CodeGenSPIRV/intrinsics.isdebugerpresent.error.hlsl b/tools/clang/test/CodeGenSPIRV/intrinsics.isdebugerpresent.error.hlsl new file mode 100644 index 0000000000..9e0aae003d --- /dev/null +++ b/tools/clang/test/CodeGenSPIRV/intrinsics.isdebugerpresent.error.hlsl @@ -0,0 +1,12 @@ +// RUN: not %dxc -T cs_6_10 -spirv %s 2>&1 | FileCheck %s + +// CHECK: error: no equivalent for IsDebuggerPresent intrinsic function in Vulkan + +RWStructuredBuffer Output : register(u0); + +[numthreads(8, 8, 1)] +void main(uint3 threadId : SV_DispatchThreadID) { + if (dx::IsDebuggerPresent()) { + Output[threadId.x] = 1; + } +} diff --git a/tools/clang/test/HLSLFileCheckLit/hlsl/intrinsics/basic/debugbreak.hlsl b/tools/clang/test/HLSLFileCheckLit/hlsl/intrinsics/basic/debugbreak.hlsl new file mode 100644 index 0000000000..dae72aed6d --- /dev/null +++ b/tools/clang/test/HLSLFileCheckLit/hlsl/intrinsics/basic/debugbreak.hlsl @@ -0,0 +1,12 @@ +// REQUIRES: dxil-1-10 + +// RUN: %dxc -T cs_6_10 %s | FileCheck %s + +// CHECK: call void @dx.op.debugBreak(i32 + +[numthreads(8, 8, 1)] +void main(uint3 threadId : SV_DispatchThreadID) { + if (threadId.x == 0) { + DebugBreak(); + } +} diff --git a/tools/clang/test/HLSLFileCheckLit/hlsl/intrinsics/basic/isdebugerpresent.hlsl b/tools/clang/test/HLSLFileCheckLit/hlsl/intrinsics/basic/isdebugerpresent.hlsl new file mode 100644 index 0000000000..e88f31e7ee --- /dev/null +++ b/tools/clang/test/HLSLFileCheckLit/hlsl/intrinsics/basic/isdebugerpresent.hlsl @@ -0,0 +1,16 @@ +// REQUIRES: dxil-1-10 + +// RUN: %dxc -T cs_6_10 %s | FileCheck %s + +// CHECK: call i1 @dx.op.isDebuggerPresent(i32 + +RWStructuredBuffer Output : register(u0); + +[numthreads(8, 8, 1)] +void main(uint3 threadId : SV_DispatchThreadID) { + if (dx::IsDebuggerPresent()) { + Output[threadId.x] = 1; + } else { + Output[threadId.x] = 0; + } +} diff --git a/utils/hct/gen_intrin_main.txt b/utils/hct/gen_intrin_main.txt index 3b20c13ccb..33c798baa1 100644 --- a/utils/hct/gen_intrin_main.txt +++ b/utils/hct/gen_intrin_main.txt @@ -119,6 +119,7 @@ $type1 [[rn]] ddx_fine(in float_like<> x); $type1 [[rn]] ddy(in float_like<> x); $type1 [[rn]] ddy_coarse(in float_like<> x); $type1 [[rn]] ddy_fine(in float_like<> x); +void [[min_sm=6.10]] DebugBreak(); $type1 [[rn]] degrees(in float_like<> x); $match<0, 1> float_like [[rn]] determinant(in float_like x); void [[]] DeviceMemoryBarrier() : syncdevicememory_ug; @@ -1183,6 +1184,7 @@ namespace DxHitObjectMethods { } namespace namespace DxIntrinsics { +bool [[ro,min_sm=6.10]] IsDebuggerPresent(); void [[min_sm=6.9]] MaybeReorderThread(in DxHitObject HitObject); void [[min_sm=6.9]] MaybeReorderThread(in uint CoherenceHint, in uint NumCoherenceHintBitsFromLSB); void [[min_sm=6.9]] MaybeReorderThread(in DxHitObject HitObject, in uint CoherenceHint, in uint NumCoherenceHintBitsFromLSB); diff --git a/utils/hct/hctdb.py b/utils/hct/hctdb.py index 3f85b0f98c..99b4be525d 100644 --- a/utils/hct/hctdb.py +++ b/utils/hct/hctdb.py @@ -1163,6 +1163,10 @@ def populate_categories_and_models_ExperimentalOps(self): ): i.category = "Linear Algebra Operations" i.shader_model = experimental_sm + + for i in insts("DebugBreak", "IsDebuggerPresent"): + i.category = "Debugging" + i.shader_model = experimental_sm def populate_llvm_instructions(self): # Add instructions that map to LLVM instructions. @@ -6195,6 +6199,8 @@ def populate_ExperimentalOps(self): ) add_dxil_op = op_table.add_dxil_op + retvoid_param = db_dxil_param(0, "v", "", "no return value") + # Add Nop to test experimental table infrastructure. add_dxil_op( "ExperimentalNop", @@ -6638,6 +6644,28 @@ def populate_ExperimentalOps(self): op_table.reserve_dxil_op_range("LinAlgMatrixReserved", 3) + # Debugging intrinsics + add_dxil_op( + "DebugBreak", + "DebugBreak", + "triggers a breakpoint if debugger is attached", + "v", + "nd", + [ + retvoid_param, + ], + ) + add_dxil_op( + "IsDebuggerPresent", + "IsDebuggerPresent", + "returns true if debugger is attached", + "v", + "ro", + [ + db_dxil_param(0, "i1", "", "true if debugger is attached"), + ], + ) + def finalize_dxil_operations(self): "Finalize DXIL operations by setting properties and verifying consistency." diff --git a/utils/hct/hlsl_intrinsic_opcodes.json b/utils/hct/hlsl_intrinsic_opcodes.json index e09e31cbfe..017f5610e6 100644 --- a/utils/hct/hlsl_intrinsic_opcodes.json +++ b/utils/hct/hlsl_intrinsic_opcodes.json @@ -1,6 +1,6 @@ { "IntrinsicOpCodes": { - "Num_Intrinsics": 425, + "Num_Intrinsics": 427, "IOP_AcceptHitAndEndSearch": 0, "IOP_AddUint64": 1, "IOP_AllMemoryBarrier": 2, @@ -425,6 +425,8 @@ "IOP___builtin_LinAlg_MatrixAccumulateToMemory": 421, "IOP___builtin_LinAlg_MatrixOuterProduct": 422, "IOP___builtin_LinAlg_MatrixVectorMultiply": 423, - "IOP___builtin_LinAlg_MatrixVectorMultiplyAdd": 424 + "IOP___builtin_LinAlg_MatrixVectorMultiplyAdd": 424, + "IOP_DebugBreak": 425, + "IOP_DxIsDebuggerPresent": 426 } } From 25b97974477f4cd712d3ae2794d61b1a63240cc3 Mon Sep 17 00:00:00 2001 From: Jack Elliott Date: Wed, 28 Jan 2026 11:49:18 +1300 Subject: [PATCH 02/11] formatting --- tools/clang/lib/SPIRV/SpirvBuilder.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/tools/clang/lib/SPIRV/SpirvBuilder.cpp b/tools/clang/lib/SPIRV/SpirvBuilder.cpp index 3d6a4d4756..7d08500dad 100644 --- a/tools/clang/lib/SPIRV/SpirvBuilder.cpp +++ b/tools/clang/lib/SPIRV/SpirvBuilder.cpp @@ -897,9 +897,9 @@ SpirvInstruction *SpirvBuilder::createNonSemanticDebugPrintfExtInst( SpirvInstruction * SpirvBuilder::createNonSemanticDebugBreakExtInst(SourceLocation loc) { assert(insertPoint && "null insert point"); - auto *extInst = new (context) - SpirvExtInst(astContext.VoidTy, loc, getExtInstSet("NonSemantic.DebugBreak"), - NonSemanticDebugBreakDebugBreak, {}); + auto *extInst = new (context) SpirvExtInst( + astContext.VoidTy, loc, getExtInstSet("NonSemantic.DebugBreak"), + NonSemanticDebugBreakDebugBreak, {}); insertPoint->addInstruction(extInst); return extInst; } From c89129305bb4a0411d90a798b53883d4dff33482 Mon Sep 17 00:00:00 2001 From: Jack Elliott Date: Wed, 28 Jan 2026 12:14:15 +1300 Subject: [PATCH 03/11] remove whitespace --- utils/hct/hctdb.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/utils/hct/hctdb.py b/utils/hct/hctdb.py index 99b4be525d..883654b451 100644 --- a/utils/hct/hctdb.py +++ b/utils/hct/hctdb.py @@ -1163,7 +1163,7 @@ def populate_categories_and_models_ExperimentalOps(self): ): i.category = "Linear Algebra Operations" i.shader_model = experimental_sm - + for i in insts("DebugBreak", "IsDebuggerPresent"): i.category = "Debugging" i.shader_model = experimental_sm From a7ba920b9986d68f6326f0470b1f070ed38b922e Mon Sep 17 00:00:00 2001 From: Jack Elliott Date: Wed, 28 Jan 2026 13:48:29 +1300 Subject: [PATCH 04/11] Missed generated file --- include/dxc/DXIL/DxilConstants.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/include/dxc/DXIL/DxilConstants.h b/include/dxc/DXIL/DxilConstants.h index 5c314376c5..ed0c09fc47 100644 --- a/include/dxc/DXIL/DxilConstants.h +++ b/include/dxc/DXIL/DxilConstants.h @@ -1328,8 +1328,10 @@ enum class OpCode : unsigned { EXP_OPCODE(ExperimentalOps, LinAlgMatrixReserved1), // reserved // LinAlgMatrixReserved2 = 0x80000020, 2147483680U, -2147483616 EXP_OPCODE(ExperimentalOps, LinAlgMatrixReserved2), // reserved + // DebugBreak = 0x80000021, 2147483681U, -2147483615 EXP_OPCODE(ExperimentalOps, DebugBreak), // triggers a breakpoint if debugger is attached + // IsDebuggerPresent = 0x80000022, 2147483682U, -2147483614 EXP_OPCODE(ExperimentalOps, IsDebuggerPresent), // returns true if debugger is attached }; From a5afec59afa40a6b1cf11da329c52471c26f6287 Mon Sep 17 00:00:00 2001 From: Jack Elliott Date: Fri, 30 Jan 2026 06:19:50 +1300 Subject: [PATCH 05/11] Move release notes section --- docs/ReleaseNotes.md | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/docs/ReleaseNotes.md b/docs/ReleaseNotes.md index e6aeffe91a..056e37312f 100644 --- a/docs/ReleaseNotes.md +++ b/docs/ReleaseNotes.md @@ -35,6 +35,10 @@ The included licenses apply to the following files: - GetGroupWaveCount: New intrinsic for Compute, Mesh, Amplification and Node shaders which returns the total number of waves executing within the thread group. +- Added `DebugBreak()` and `dx::IsDebuggerPresent()` intrinsics for shader debugging (experimental Shader Model 6.10). + - `DebugBreak()` triggers a breakpoint if a debugger is attached. + - `dx::IsDebuggerPresent()` returns true if a debugger is attached. + - SPIR-V: `DebugBreak()` emits `NonSemantic.DebugBreak` extended instruction; `IsDebuggerPresent()` is not supported. #### Noteble SPIR-V updates @@ -80,11 +84,6 @@ The included licenses apply to the following files: - Several small bug fixes. #### Other Changes - -- Added `DebugBreak()` and `dx::IsDebuggerPresent()` intrinsics for shader debugging (experimental Shader Model 6.10). - - `DebugBreak()` triggers a breakpoint if a debugger is attached. - - `dx::IsDebuggerPresent()` returns true if a debugger is attached. - - SPIR-V: `DebugBreak()` emits `NonSemantic.DebugBreak` extended instruction; `IsDebuggerPresent()` is not supported. - Fixed regression: [#7510](https://github.com/microsoft/DirectXShaderCompiler/issues/7510) crash when calling `sizeof` on templated type. - Fixed regression: [#7508](https://github.com/microsoft/DirectXShaderCompiler/issues/7508) crash when calling `Load` with `status`. - Header file `dxcpix.h` was added to the release package. From d38a57623590a36fe423ef6eaa306f4eeb83a011 Mon Sep 17 00:00:00 2001 From: Jack Elliott Date: Tue, 3 Feb 2026 07:34:30 +1300 Subject: [PATCH 06/11] fix build after merge --- include/dxc/HlslIntrinsicOp.h | 1 - lib/DXIL/DxilOperations.cpp | 6 ++++-- utils/hct/hctdb.py | 8 ++++---- 3 files changed, 8 insertions(+), 7 deletions(-) diff --git a/include/dxc/HlslIntrinsicOp.h b/include/dxc/HlslIntrinsicOp.h index bbe8c66e7d..1ebb2df35b 100644 --- a/include/dxc/HlslIntrinsicOp.h +++ b/include/dxc/HlslIntrinsicOp.h @@ -399,7 +399,6 @@ enum class IntrinsicOp { MOP_DxHitObject_MakeNop = 358, MOP_DxHitObject_SetShaderTableIndex = 388, MOP_DxHitObject_TraceRay = 389, - MOP_DxHitObject_TriangleObjectPosition = 404, MOP_DxHitObject_TriangleObjectPositions = 404, IOP_DxIsDebuggerPresent = 426, IOP_DxMaybeReorderThread = 359, diff --git a/lib/DXIL/DxilOperations.cpp b/lib/DXIL/DxilOperations.cpp index fc87385605..eb5b2a2ceb 100644 --- a/lib/DXIL/DxilOperations.cpp +++ b/lib/DXIL/DxilOperations.cpp @@ -3937,12 +3937,14 @@ void OP::GetMinShaderModelAndMask(OpCode C, bool bWithTranslation, // CreateMatrix=2147483659, MatrixLoadFromDescriptor=2147483662, // MatrixQueryAccumulatorLayout=2147483670, MatrixVecMul=2147483673, // MatrixVecMulAdd=2147483674, MatrixAccumulateToDescriptor=2147483675, - // MatrixOuterProduct=2147483677 + // MatrixOuterProduct=2147483677, DebugBreak=2147483681, + // IsDebuggerPresent=2147483682 if ((305 <= op && op <= 308) || op == 2147483648 || (2147483652 <= op && op <= 2147483653) || (2147483656 <= op && op <= 2147483657) || op == 2147483659 || op == 2147483662 || op == 2147483670 || - (2147483673 <= op && op <= 2147483675) || op == 2147483677) { + (2147483673 <= op && op <= 2147483675) || op == 2147483677 || + (2147483681 <= op && op <= 2147483682)) { major = 6; minor = 10; return; diff --git a/utils/hct/hctdb.py b/utils/hct/hctdb.py index 02d3bba742..3f7e2d57f1 100644 --- a/utils/hct/hctdb.py +++ b/utils/hct/hctdb.py @@ -1168,10 +1168,6 @@ def populate_categories_and_models_ExperimentalOps(self): i.category = "Linear Algebra Operations" i.shader_model = experimental_sm - for i in insts("DebugBreak", "IsDebuggerPresent"): - i.category = "Debugging" - i.shader_model = experimental_sm - # Wave/ThreadGroup scope operations for i in insts( "FillMatrix,CopyConvertMatrix," @@ -1187,6 +1183,10 @@ def populate_categories_and_models_ExperimentalOps(self): "mesh", "amplification", ) + + for i in insts("DebugBreak", "IsDebuggerPresent"): + i.category = "Debugging" + i.shader_model = experimental_sm def populate_llvm_instructions(self): # Add instructions that map to LLVM instructions. From bebc171d8a9e1a8b51fbc2ac830cbc3a57e102a6 Mon Sep 17 00:00:00 2001 From: Jack Elliott Date: Tue, 3 Feb 2026 07:48:34 +1300 Subject: [PATCH 07/11] Fix bad grammar --- docs/DXIL.rst | 4 ++-- include/dxc/DXIL/DxilConstants.h | 8 ++++---- include/dxc/DXIL/DxilInstructions.h | 4 ++-- utils/hct/hctdb.py | 6 +++--- 4 files changed, 11 insertions(+), 11 deletions(-) diff --git a/docs/DXIL.rst b/docs/DXIL.rst index c8adc0e32a..8871d3d8c9 100644 --- a/docs/DXIL.rst +++ b/docs/DXIL.rst @@ -3098,8 +3098,8 @@ ID Name Description 2147483678 LinAlgMatrixReserved0 reserved 2147483679 LinAlgMatrixReserved1 reserved 2147483680 LinAlgMatrixReserved2 reserved -2147483681 DebugBreak triggers a breakpoint if debugger is attached -2147483682 IsDebuggerPresent returns true if debugger is attached +2147483681 DebugBreak triggers a breakpoint if a debugger is attached +2147483682 IsDebuggerPresent returns true if a debugger is attached ========== ======================================== =================================================================================================================== diff --git a/include/dxc/DXIL/DxilConstants.h b/include/dxc/DXIL/DxilConstants.h index b5809d04ea..eb5f6ac1dd 100644 --- a/include/dxc/DXIL/DxilConstants.h +++ b/include/dxc/DXIL/DxilConstants.h @@ -517,8 +517,8 @@ enum class OpCode : unsigned { LinAlgMatrixReserved2 = 32, // reserved // Debugging - DebugBreak = 33, // triggers a breakpoint if debugger is attached - IsDebuggerPresent = 34, // returns true if debugger is attached + DebugBreak = 33, // triggers a breakpoint if a debugger is attached + IsDebuggerPresent = 34, // returns true if a debugger is attached // Group Wave Ops GetGroupWaveCount = 2, // returns the number of waves in the thread group @@ -1330,10 +1330,10 @@ enum class OpCode : unsigned { EXP_OPCODE(ExperimentalOps, LinAlgMatrixReserved2), // reserved // DebugBreak = 0x80000021, 2147483681U, -2147483615 EXP_OPCODE(ExperimentalOps, - DebugBreak), // triggers a breakpoint if debugger is attached + DebugBreak), // triggers a breakpoint if a debugger is attached // IsDebuggerPresent = 0x80000022, 2147483682U, -2147483614 EXP_OPCODE(ExperimentalOps, - IsDebuggerPresent), // returns true if debugger is attached + IsDebuggerPresent), // returns true if a debugger is attached }; // OPCODE-ENUM:END #undef EXP_OPCODE diff --git a/include/dxc/DXIL/DxilInstructions.h b/include/dxc/DXIL/DxilInstructions.h index 7c841b8790..a4dab455bf 100644 --- a/include/dxc/DXIL/DxilInstructions.h +++ b/include/dxc/DXIL/DxilInstructions.h @@ -11138,7 +11138,7 @@ struct DxilInst_MatrixOuterProduct { void set_vectorB(llvm::Value *val) { Instr->setOperand(3, val); } }; -/// This instruction triggers a breakpoint if debugger is attached +/// This instruction triggers a breakpoint if a debugger is attached struct DxilInst_DebugBreak { llvm::Instruction *Instr; // Construction and identification @@ -11157,7 +11157,7 @@ struct DxilInst_DebugBreak { bool requiresUniformInputs() const { return false; } }; -/// This instruction returns true if debugger is attached +/// This instruction returns true if a debugger is attached struct DxilInst_IsDebuggerPresent { llvm::Instruction *Instr; // Construction and identification diff --git a/utils/hct/hctdb.py b/utils/hct/hctdb.py index 3f7e2d57f1..dd03d00450 100644 --- a/utils/hct/hctdb.py +++ b/utils/hct/hctdb.py @@ -6712,7 +6712,7 @@ def populate_ExperimentalOps(self): add_dxil_op( "DebugBreak", "DebugBreak", - "triggers a breakpoint if debugger is attached", + "triggers a breakpoint if a debugger is attached", "v", "nd", [ @@ -6722,11 +6722,11 @@ def populate_ExperimentalOps(self): add_dxil_op( "IsDebuggerPresent", "IsDebuggerPresent", - "returns true if debugger is attached", + "returns true if a debugger is attached", "v", "ro", [ - db_dxil_param(0, "i1", "", "true if debugger is attached"), + db_dxil_param(0, "i1", "", "true if a debugger is attached"), ], ) From 0d6b95801f74a340196fd1182bead827392eec58 Mon Sep 17 00:00:00 2001 From: Jack Elliott Date: Tue, 3 Feb 2026 07:57:45 +1300 Subject: [PATCH 08/11] Add the opcode to the file check --- .../test/HLSLFileCheckLit/hlsl/intrinsics/basic/debugbreak.hlsl | 2 +- .../hlsl/intrinsics/basic/isdebugerpresent.hlsl | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/tools/clang/test/HLSLFileCheckLit/hlsl/intrinsics/basic/debugbreak.hlsl b/tools/clang/test/HLSLFileCheckLit/hlsl/intrinsics/basic/debugbreak.hlsl index dae72aed6d..867a03667a 100644 --- a/tools/clang/test/HLSLFileCheckLit/hlsl/intrinsics/basic/debugbreak.hlsl +++ b/tools/clang/test/HLSLFileCheckLit/hlsl/intrinsics/basic/debugbreak.hlsl @@ -2,7 +2,7 @@ // RUN: %dxc -T cs_6_10 %s | FileCheck %s -// CHECK: call void @dx.op.debugBreak(i32 +// CHECK: call void @dx.op.debugBreak(i32 -2147483615) ; DebugBreak() [numthreads(8, 8, 1)] void main(uint3 threadId : SV_DispatchThreadID) { diff --git a/tools/clang/test/HLSLFileCheckLit/hlsl/intrinsics/basic/isdebugerpresent.hlsl b/tools/clang/test/HLSLFileCheckLit/hlsl/intrinsics/basic/isdebugerpresent.hlsl index e88f31e7ee..2583b59728 100644 --- a/tools/clang/test/HLSLFileCheckLit/hlsl/intrinsics/basic/isdebugerpresent.hlsl +++ b/tools/clang/test/HLSLFileCheckLit/hlsl/intrinsics/basic/isdebugerpresent.hlsl @@ -2,7 +2,7 @@ // RUN: %dxc -T cs_6_10 %s | FileCheck %s -// CHECK: call i1 @dx.op.isDebuggerPresent(i32 +// CHECK: call i1 @dx.op.isDebuggerPresent(i32 -2147483614) ; IsDebuggerPresent() RWStructuredBuffer Output : register(u0); From 173024c7c854e9b01f2150e2088adfb666cc9542 Mon Sep 17 00:00:00 2001 From: Jack Elliott Date: Tue, 3 Feb 2026 09:48:11 +1300 Subject: [PATCH 09/11] Add AST and FCGL checks --- .../hlsl/intrinsics/basic/debugbreak.hlsl | 8 ++++++++ .../{isdebugerpresent.hlsl => isdebuggerpresent.hlsl} | 8 ++++++++ 2 files changed, 16 insertions(+) rename tools/clang/test/HLSLFileCheckLit/hlsl/intrinsics/basic/{isdebugerpresent.hlsl => isdebuggerpresent.hlsl} (51%) diff --git a/tools/clang/test/HLSLFileCheckLit/hlsl/intrinsics/basic/debugbreak.hlsl b/tools/clang/test/HLSLFileCheckLit/hlsl/intrinsics/basic/debugbreak.hlsl index 867a03667a..7147490437 100644 --- a/tools/clang/test/HLSLFileCheckLit/hlsl/intrinsics/basic/debugbreak.hlsl +++ b/tools/clang/test/HLSLFileCheckLit/hlsl/intrinsics/basic/debugbreak.hlsl @@ -1,8 +1,16 @@ // REQUIRES: dxil-1-10 // RUN: %dxc -T cs_6_10 %s | FileCheck %s +// RUN: %dxc -T cs_6_10 -fcgl %s | FileCheck %s --check-prefix=FCGL +// RUN: %dxc -T cs_6_10 -ast-dump %s | FileCheck %s --check-prefix=AST // CHECK: call void @dx.op.debugBreak(i32 -2147483615) ; DebugBreak() +// FCGL: call void @"dx.hl.op..void (i32)"(i32 425) + +// AST: CallExpr {{.*}} 'void' +// AST-NEXT: `-ImplicitCastExpr {{.*}} 'void (*)()' +// AST-NEXT: `-DeclRefExpr {{.*}} 'DebugBreak' 'void ()' + [numthreads(8, 8, 1)] void main(uint3 threadId : SV_DispatchThreadID) { diff --git a/tools/clang/test/HLSLFileCheckLit/hlsl/intrinsics/basic/isdebugerpresent.hlsl b/tools/clang/test/HLSLFileCheckLit/hlsl/intrinsics/basic/isdebuggerpresent.hlsl similarity index 51% rename from tools/clang/test/HLSLFileCheckLit/hlsl/intrinsics/basic/isdebugerpresent.hlsl rename to tools/clang/test/HLSLFileCheckLit/hlsl/intrinsics/basic/isdebuggerpresent.hlsl index 2583b59728..ad58d814b7 100644 --- a/tools/clang/test/HLSLFileCheckLit/hlsl/intrinsics/basic/isdebugerpresent.hlsl +++ b/tools/clang/test/HLSLFileCheckLit/hlsl/intrinsics/basic/isdebuggerpresent.hlsl @@ -1,9 +1,17 @@ // REQUIRES: dxil-1-10 // RUN: %dxc -T cs_6_10 %s | FileCheck %s +// RUN: %dxc -T cs_6_10 -fcgl %s | FileCheck %s --check-prefix=FCGL +// RUN: %dxc -T cs_6_10 -ast-dump %s | FileCheck %s --check-prefix=AST // CHECK: call i1 @dx.op.isDebuggerPresent(i32 -2147483614) ; IsDebuggerPresent() +// FCGL: call i1 @"dx.hl.op.ro.i1 (i32)"(i32 426) + +// AST: CallExpr {{.*}} 'bool' +// AST-NEXT: `-ImplicitCastExpr {{.*}} 'bool (*)()' +// AST-NEXT: `-DeclRefExpr {{.*}} 'IsDebuggerPresent' 'bool ()' + RWStructuredBuffer Output : register(u0); [numthreads(8, 8, 1)] From bf2a1f607ff06d6ca4361414a89602c1ef86dc31 Mon Sep 17 00:00:00 2001 From: Jack Elliott Date: Tue, 3 Feb 2026 10:16:39 +1300 Subject: [PATCH 10/11] Add DxilGen tests --- .../test/DXC/Passes/DxilGen/debugbreak.ll | 59 +++++++++++ .../DXC/Passes/DxilGen/isdebuggerpresent.ll | 97 +++++++++++++++++++ 2 files changed, 156 insertions(+) create mode 100644 tools/clang/test/DXC/Passes/DxilGen/debugbreak.ll create mode 100644 tools/clang/test/DXC/Passes/DxilGen/isdebuggerpresent.ll diff --git a/tools/clang/test/DXC/Passes/DxilGen/debugbreak.ll b/tools/clang/test/DXC/Passes/DxilGen/debugbreak.ll new file mode 100644 index 0000000000..a3b53dbf19 --- /dev/null +++ b/tools/clang/test/DXC/Passes/DxilGen/debugbreak.ll @@ -0,0 +1,59 @@ +; REQUIRES: dxil-1-10 +; RUN: %dxopt %s -hlsl-passes-resume -dxilgen -S | FileCheck %s + +; CHECK: call void @dx.op.debugBreak(i32 -2147483615) + +; Generated from: +; dxc -T cs_6_10 -fcgl tools/clang/test/HLSLFileCheckLit/hlsl/intrinsics/basic/debugbreak.hlsl +; Debug info manually stripped. + +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" + +; Function Attrs: nounwind +define void @main(<3 x i32> %threadId) #0 { +entry: + %0 = extractelement <3 x i32> %threadId, i32 0 + %cmp = icmp eq i32 %0, 0 + br i1 %cmp, label %if.then, label %if.end + +if.then: + call void @"dx.hl.op..void (i32)"(i32 425) + br label %if.end + +if.end: + ret void +} + +; Function Attrs: nounwind +declare void @"dx.hl.op..void (i32)"(i32) #0 + +attributes #0 = { nounwind } + +!pauseresume = !{!0} +!llvm.ident = !{!1} +!dx.version = !{!2} +!dx.valver = !{!2} +!dx.shaderModel = !{!3} +!dx.typeAnnotations = !{!4} +!dx.entryPoints = !{!10} +!dx.fnprops = !{!14} +!dx.options = !{!15, !16} + +!0 = !{!"hlsl-hlemit", !"hlsl-hlensure"} +!1 = !{!"dxc(private) 1.9.0.5167 (Debug-Break, c89129305)"} +!2 = !{i32 1, i32 10} +!3 = !{!"cs", i32 6, i32 10} +!4 = !{i32 1, void (<3 x i32>)* @main, !5} +!5 = !{!6, !8} +!6 = !{i32 1, !7, !7} +!7 = !{} +!8 = !{i32 0, !9, !7} +!9 = !{i32 4, !"SV_DispatchThreadID", i32 7, i32 5, i32 13, i32 3} +!10 = !{void (<3 x i32>)* @main, !"main", null, !11, null} +!11 = !{null, null, null, null} +!12 = !{} +!13 = !{i32 0} +!14 = !{void (<3 x i32>)* @main, i32 5, i32 8, i32 8, i32 1} +!15 = !{i32 -2147483584} +!16 = !{i32 -1} diff --git a/tools/clang/test/DXC/Passes/DxilGen/isdebuggerpresent.ll b/tools/clang/test/DXC/Passes/DxilGen/isdebuggerpresent.ll new file mode 100644 index 0000000000..fa77e8f3c8 --- /dev/null +++ b/tools/clang/test/DXC/Passes/DxilGen/isdebuggerpresent.ll @@ -0,0 +1,97 @@ +; REQUIRES: dxil-1-10 +; RUN: %dxopt %s -hlsl-passes-resume -dxilgen -S | FileCheck %s + +; CHECK: call i1 @dx.op.isDebuggerPresent(i32 -2147483614) + +; Generated from: +; dxc -T cs_6_10 -fcgl tools/clang/test/HLSLFileCheckLit/hlsl/intrinsics/basic/isdebuggerpresent.hlsl +; Debug info manually stripped. + +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" + +%"class.RWStructuredBuffer" = type { i32 } +%dx.types.Handle = type { i8* } +%dx.types.ResourceProperties = type { i32, i32 } + +@"\01?Output@@3V?$RWStructuredBuffer@I@@A" = external global %"class.RWStructuredBuffer", align 4 + +; Function Attrs: nounwind +define void @main(<3 x i32> %threadId) #0 { +entry: + %0 = call i1 @"dx.hl.op.ro.i1 (i32)"(i32 426) + br i1 %0, label %if.then, label %if.else + +if.then: + %1 = extractelement <3 x i32> %threadId, i32 0 + %2 = load %"class.RWStructuredBuffer", %"class.RWStructuredBuffer"* @"\01?Output@@3V?$RWStructuredBuffer@I@@A" + %3 = call %dx.types.Handle @"dx.hl.createhandle..%dx.types.Handle (i32, %\22class.RWStructuredBuffer\22)"(i32 0, %"class.RWStructuredBuffer" %2) + %4 = call %dx.types.Handle @"dx.hl.annotatehandle..%dx.types.Handle (i32, %dx.types.Handle, %dx.types.ResourceProperties, %\22class.RWStructuredBuffer\22)"(i32 14, %dx.types.Handle %3, %dx.types.ResourceProperties { i32 4108, i32 4 }, %"class.RWStructuredBuffer" undef) + %5 = call i32* @"dx.hl.subscript.[].rn.i32* (i32, %dx.types.Handle, i32)"(i32 0, %dx.types.Handle %4, i32 %1) + store i32 1, i32* %5 + br label %if.end + +if.else: + %6 = extractelement <3 x i32> %threadId, i32 0 + %7 = load %"class.RWStructuredBuffer", %"class.RWStructuredBuffer"* @"\01?Output@@3V?$RWStructuredBuffer@I@@A" + %8 = call %dx.types.Handle @"dx.hl.createhandle..%dx.types.Handle (i32, %\22class.RWStructuredBuffer\22)"(i32 0, %"class.RWStructuredBuffer" %7) + %9 = call %dx.types.Handle @"dx.hl.annotatehandle..%dx.types.Handle (i32, %dx.types.Handle, %dx.types.ResourceProperties, %\22class.RWStructuredBuffer\22)"(i32 14, %dx.types.Handle %8, %dx.types.ResourceProperties { i32 4108, i32 4 }, %"class.RWStructuredBuffer" undef) + %10 = call i32* @"dx.hl.subscript.[].rn.i32* (i32, %dx.types.Handle, i32)"(i32 0, %dx.types.Handle %9, i32 %6) + store i32 0, i32* %10 + br label %if.end + +if.end: + ret void +} + +; Function Attrs: nounwind readonly +declare i1 @"dx.hl.op.ro.i1 (i32)"(i32) #1 + +; Function Attrs: nounwind readnone +declare i32* @"dx.hl.subscript.[].rn.i32* (i32, %dx.types.Handle, i32)"(i32, %dx.types.Handle, i32) #2 + +; Function Attrs: nounwind readnone +declare %dx.types.Handle @"dx.hl.createhandle..%dx.types.Handle (i32, %\22class.RWStructuredBuffer\22)"(i32, %"class.RWStructuredBuffer") #2 + +; Function Attrs: nounwind readnone +declare %dx.types.Handle @"dx.hl.annotatehandle..%dx.types.Handle (i32, %dx.types.Handle, %dx.types.ResourceProperties, %\22class.RWStructuredBuffer\22)"(i32, %dx.types.Handle, %dx.types.ResourceProperties, %"class.RWStructuredBuffer") #2 + +attributes #0 = { nounwind } +attributes #1 = { nounwind readonly } +attributes #2 = { nounwind readnone } + +!pauseresume = !{!0} +!llvm.ident = !{!1} +!dx.version = !{!2} +!dx.valver = !{!2} +!dx.shaderModel = !{!3} +!dx.typeAnnotations = !{!4, !10} +!dx.entryPoints = !{!16} +!dx.fnprops = !{!22} +!dx.options = !{!23, !24} + +!0 = !{!"hlsl-hlemit", !"hlsl-hlensure"} +!1 = !{!"dxc(private) 1.9.0.5167 (Debug-Break, c89129305)"} +!2 = !{i32 1, i32 10} +!3 = !{!"cs", i32 6, i32 10} +!4 = !{i32 0, %"class.RWStructuredBuffer" undef, !5} +!5 = !{i32 4, !6, !7} +!6 = !{i32 6, !"h", i32 3, i32 0, i32 7, i32 5} +!7 = !{i32 0, !8} +!8 = !{!9} +!9 = !{i32 0, i32 undef} +!10 = !{i32 1, void (<3 x i32>)* @main, !11} +!11 = !{!12, !14} +!12 = !{i32 1, !13, !13} +!13 = !{} +!14 = !{i32 0, !15, !13} +!15 = !{i32 4, !"SV_DispatchThreadID", i32 7, i32 5, i32 13, i32 3} +!16 = !{void (<3 x i32>)* @main, !"main", null, !17, null} +!17 = !{null, !18, null, null} +!18 = !{!19} +!19 = !{i32 0, %"class.RWStructuredBuffer"* @"\01?Output@@3V?$RWStructuredBuffer@I@@A", !"Output", i32 0, i32 0, i32 1, i32 12, i1 false, i1 false, i1 false, !20} +!20 = !{i32 1, i32 4} +!21 = !{i32 0} +!22 = !{void (<3 x i32>)* @main, i32 5, i32 8, i32 8, i32 1} +!23 = !{i32 -2147483584} +!24 = !{i32 -1} From 1652202afb2af7f3b5903fb45241c0d20ed774b9 Mon Sep 17 00:00:00 2001 From: Jack Elliott Date: Tue, 3 Feb 2026 10:30:30 +1300 Subject: [PATCH 11/11] Verify source location for SPIR-V lowering --- .../test/CodeGenSPIRV/intrinsics.isdebugerpresent.error.hlsl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/clang/test/CodeGenSPIRV/intrinsics.isdebugerpresent.error.hlsl b/tools/clang/test/CodeGenSPIRV/intrinsics.isdebugerpresent.error.hlsl index 9e0aae003d..e82df70065 100644 --- a/tools/clang/test/CodeGenSPIRV/intrinsics.isdebugerpresent.error.hlsl +++ b/tools/clang/test/CodeGenSPIRV/intrinsics.isdebugerpresent.error.hlsl @@ -1,6 +1,6 @@ // RUN: not %dxc -T cs_6_10 -spirv %s 2>&1 | FileCheck %s -// CHECK: error: no equivalent for IsDebuggerPresent intrinsic function in Vulkan +// CHECK: :9:9: error: no equivalent for IsDebuggerPresent intrinsic function in Vulkan RWStructuredBuffer Output : register(u0);