Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions docs/DXIL.rst
Original file line number Diff line number Diff line change
Expand Up @@ -3098,6 +3098,8 @@ ID Name Description
2147483678 LinAlgMatrixReserved0 reserved
2147483679 LinAlgMatrixReserved1 reserved
2147483680 LinAlgMatrixReserved2 reserved
2147483681 DebugBreak triggers a breakpoint if a debugger is attached
2147483682 IsDebuggerPresent returns true if a debugger is attached
========== ======================================== ===================================================================================================================


Expand Down
5 changes: 4 additions & 1 deletion docs/ReleaseNotes.md
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down Expand Up @@ -80,7 +84,6 @@ The included licenses apply to the following files:
- Several small bug fixes.

#### Other Changes

- 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.
Expand Down
18 changes: 16 additions & 2 deletions include/dxc/DXIL/DxilConstants.h
Original file line number Diff line number Diff line change
Expand Up @@ -516,6 +516,10 @@ enum class OpCode : unsigned {
LinAlgMatrixReserved1 = 31, // reserved
LinAlgMatrixReserved2 = 32, // reserved

// Debugging
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
GetGroupWaveIndex = 1, // returns the index of the wave in the thread group
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -1324,6 +1328,12 @@ 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 a debugger is attached
// IsDebuggerPresent = 0x80000022, 2147483682U, -2147483614
EXP_OPCODE(ExperimentalOps,
IsDebuggerPresent), // returns true if a debugger is attached
};
// OPCODE-ENUM:END
#undef EXP_OPCODE
Expand Down Expand Up @@ -1386,6 +1396,10 @@ enum class OpCodeClass : unsigned {
IndexNodeHandle,
createNodeOutputHandle,

// Debugging
DebugBreak,
IsDebuggerPresent,

// Derivatives
CalculateLOD,
Unary,
Expand Down Expand Up @@ -1688,7 +1702,7 @@ enum class OpCodeClass : unsigned {
NodeOutputIsValid,
OutputComplete,

NumOpClasses = 223, // exclusive last value of enumeration
NumOpClasses = 225, // exclusive last value of enumeration
};
// OPCODECLASS-ENUM:END

Expand Down
39 changes: 39 additions & 0 deletions include/dxc/DXIL/DxilInstructions.h
Original file line number Diff line number Diff line change
Expand Up @@ -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 a 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<llvm::CallInst>(Instr)->getNumArgOperands())
return false;
return true;
}
// Metadata
bool requiresUniformInputs() const { return false; }
};

/// This instruction returns true if a 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<llvm::CallInst>(Instr)->getNumArgOperands())
return false;
return true;
}
// Metadata
bool requiresUniformInputs() const { return false; }
};
// INSTR-HELPER:END
} // namespace hlsl
4 changes: 3 additions & 1 deletion include/dxc/HlslIntrinsicOp.h
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down Expand Up @@ -399,6 +400,7 @@ enum class IntrinsicOp {
MOP_DxHitObject_SetShaderTableIndex = 388,
MOP_DxHitObject_TraceRay = 389,
MOP_DxHitObject_TriangleObjectPositions = 404,
IOP_DxIsDebuggerPresent = 426,
IOP_DxMaybeReorderThread = 359,
MOP_Count = 328,
MOP_FinishedCrossGroupSharing = 329,
Expand Down Expand Up @@ -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) {
Expand Down
36 changes: 34 additions & 2 deletions lib/DXIL/DxilOperations.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down Expand Up @@ -3919,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;
Expand Down Expand Up @@ -6683,6 +6703,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");
Expand Down Expand Up @@ -6998,6 +7028,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);
Expand Down
4 changes: 4 additions & 0 deletions lib/HLSL/HLOperationLower.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -7697,6 +7697,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]);
Expand Down
5 changes: 5 additions & 0 deletions tools/clang/include/clang/SPIRV/SpirvBuilder.h
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down Expand Up @@ -434,6 +435,10 @@ class SpirvBuilder {
QualType resultType, NonSemanticDebugPrintfInstructions instId,
llvm::ArrayRef<SpirvInstruction *> 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);
Expand Down
3 changes: 3 additions & 0 deletions tools/clang/lib/SPIRV/CapabilityVisitor.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}
Expand Down
10 changes: 10 additions & 0 deletions tools/clang/lib/SPIRV/SpirvBuilder.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down
4 changes: 4 additions & 0 deletions tools/clang/lib/SPIRV/SpirvEmitter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -9345,6 +9345,9 @@ SpirvEmitter::processIntrinsicCallExpr(const CallExpr *callExpr) {
/*groupSync*/ true,
/*isAllBarrier*/ true);
break;
case hlsl::IntrinsicOp::IOP_DebugBreak:
retVal = spvBuilder.createNonSemanticDebugBreakExtInst(srcLoc);
break;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is the ordering of the cases arbitrary?

case hlsl::IntrinsicOp::IOP_GetRemainingRecursionLevels:
retVal = processIntrinsicGetRemainingRecursionLevels(callExpr);
break;
Expand Down Expand Up @@ -9565,6 +9568,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)
Expand Down
3 changes: 3 additions & 0 deletions tools/clang/lib/Sema/SemaHLSL.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3634,6 +3634,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;
Expand Down
12 changes: 12 additions & 0 deletions tools/clang/test/CodeGenSPIRV/intrinsics.debugbreak.hlsl
Original file line number Diff line number Diff line change
@@ -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();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
// RUN: not %dxc -T cs_6_10 -spirv %s 2>&1 | FileCheck %s

// CHECK: :9:9: error: no equivalent for IsDebuggerPresent intrinsic function in Vulkan

RWStructuredBuffer<uint> Output : register(u0);

[numthreads(8, 8, 1)]
void main(uint3 threadId : SV_DispatchThreadID) {
if (dx::IsDebuggerPresent()) {
Output[threadId.x] = 1;
}
}
59 changes: 59 additions & 0 deletions tools/clang/test/DXC/Passes/DxilGen/debugbreak.ll
Original file line number Diff line number Diff line change
@@ -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}
Loading
Loading