2017-10-10 01:30:29 +03:00
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
|
|
// //
|
|
|
|
// DxilDebugInstrumentation.cpp //
|
|
|
|
// Copyright (C) Microsoft Corporation. All rights reserved. //
|
|
|
|
// This file is distributed under the University of Illinois Open Source //
|
|
|
|
// License. See LICENSE.TXT for details. //
|
|
|
|
// //
|
|
|
|
// Adds instrumentation that enables shader debugging in PIX //
|
|
|
|
// //
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
|
|
|
2018-10-16 10:28:35 +03:00
|
|
|
#include "dxc/DXIL/DxilModule.h"
|
|
|
|
#include "dxc/DXIL/DxilOperations.h"
|
2019-11-22 22:08:49 +03:00
|
|
|
#include "dxc/DXIL/DxilUtil.h"
|
2018-10-17 07:38:33 +03:00
|
|
|
#include "dxc/DxilPIXPasses/DxilPIXPasses.h"
|
2019-03-19 21:46:10 +03:00
|
|
|
#include "dxc/DxilPIXPasses/DxilPIXVirtualRegisters.h"
|
2019-11-22 22:08:49 +03:00
|
|
|
#include "dxc/HLSL/DxilGenerationPass.h"
|
2017-10-10 01:30:29 +03:00
|
|
|
|
2019-11-22 22:08:49 +03:00
|
|
|
#include "llvm/ADT/STLExtras.h"
|
2017-10-10 01:30:29 +03:00
|
|
|
#include "llvm/IR/Constants.h"
|
|
|
|
#include "llvm/IR/IRBuilder.h"
|
2019-11-22 22:08:49 +03:00
|
|
|
#include "llvm/IR/InstIterator.h"
|
|
|
|
#include "llvm/IR/Module.h"
|
2017-10-10 01:30:29 +03:00
|
|
|
|
|
|
|
using namespace llvm;
|
|
|
|
using namespace hlsl;
|
|
|
|
|
|
|
|
// Overview of instrumentation:
|
2019-11-22 22:08:49 +03:00
|
|
|
//
|
|
|
|
// In summary, instructions are added that cause a "trace" of the execution of
|
|
|
|
// the shader to be written out to a UAV. This trace is then used by a debugger
|
|
|
|
// application to provide a post-mortem debugging experience that reconstructs
|
|
|
|
// the execution history of the shader.
|
|
|
|
//
|
|
|
|
// The trace is only required for a particular shader instance of interest, and
|
|
|
|
// a branchless mechanism is used to write the trace either to an incrementing
|
|
|
|
// location within the UAV, or to a "dumping ground" area at the top of the UAV
|
|
|
|
// if the instance is not of interest.
|
|
|
|
//
|
2017-10-10 01:30:29 +03:00
|
|
|
// The following modifications are made:
|
2019-11-22 22:08:49 +03:00
|
|
|
//
|
|
|
|
// First, instructions are added to the top of the entry point function that
|
|
|
|
// implement the following:
|
|
|
|
// - Examine the input variables that define the instance of the shader that is
|
|
|
|
// running. This will
|
|
|
|
// be SV_Position for pixel shaders, SV_Vertex+SV_Instance for vertex
|
|
|
|
// shaders, thread id for compute shaders etc. If these system values need to
|
|
|
|
// be added to the shader, then they are also added to the input signature,
|
|
|
|
// if appropriate.
|
|
|
|
// - Compare the above variables with the instance of interest defined by the
|
|
|
|
// invoker of this pass.
|
|
|
|
// Deduce two values: a multiplicand and an addend that together allow a
|
|
|
|
// branchless calculation of the offset into the UAV at which to write via
|
|
|
|
// "offset = offset * multiplicand + addend." If the instance is NOT of
|
|
|
|
// interest, the multiplicand is zero and the addend is sizeof(UAV)-(a little
|
|
|
|
// bit), causing writes for uninteresting invocations to end up at the top of
|
2017-10-10 01:30:29 +03:00
|
|
|
// the UAV. Otherwise the multiplicand is 1 and the addend is 0.
|
2019-11-22 22:08:49 +03:00
|
|
|
// - Calculate an "instance identifier". Even with the above instance
|
|
|
|
// identification, several invocations may
|
|
|
|
// end up matching the selection criteria. Specifically, this happens during
|
|
|
|
// a draw call in which many triangles overlap the pixel of interest. More on
|
|
|
|
// this below.
|
|
|
|
//
|
|
|
|
// During execution, the instrumentation for most instructions cause data to be
|
|
|
|
// emitted to the UAV. The index at which data is written is identified by
|
|
|
|
// treating the first uint32 of the UAV as an index which is atomically
|
|
|
|
// incremented by the instrumentation. The very first value of this counter that
|
|
|
|
// is encountered by each invocation is used as the "instance identifier"
|
|
|
|
// mentioned above. That instance identifier is written out with each packet,
|
|
|
|
// since many pixel shaders executing in parallel will emit interleaved packets,
|
|
|
|
// and the debugger application uses the identifiers to group packets from each
|
|
|
|
// separate invocation together.
|
|
|
|
//
|
|
|
|
// If an instruction has a non-void and primitive return type, i.e. isn't a
|
|
|
|
// struct, then the instrumentation will write that value out to the UAV as well
|
|
|
|
// as part of the "step" data packet.
|
|
|
|
//
|
|
|
|
// The limiting size of the UAV is enforced in a branchless way by ANDing the
|
|
|
|
// offset with a precomputed value that is sizeof(UAV)-64. The actual size of
|
|
|
|
// the UAV allocated by the caller is required to be a power of two plus 64 for
|
|
|
|
// this reason. The caller detects UAV overrun by examining a canary value close
|
|
|
|
// to the end of the power-of-two size of the UAV. If this value has been
|
|
|
|
// overwritten, the debug session is deemed to have overflowed the UAV. The
|
|
|
|
// caller will than allocate a UAV that is twice the size and try again, up to a
|
|
|
|
// predefined maximum.
|
|
|
|
|
2020-05-19 19:21:30 +03:00
|
|
|
// Keep these in sync with the same-named value in the debugger application's
|
2019-11-22 22:08:49 +03:00
|
|
|
// WinPixShaderUtils.h
|
2020-05-19 19:21:30 +03:00
|
|
|
|
2017-10-10 01:30:29 +03:00
|
|
|
constexpr uint64_t DebugBufferDumpingGroundSize = 64 * 1024;
|
2020-05-19 19:21:30 +03:00
|
|
|
// The actual max size per record is much smaller than this, but it never
|
|
|
|
// hurts to be generous.
|
|
|
|
constexpr size_t CounterOffsetBeyondUsefulData = DebugBufferDumpingGroundSize / 2;
|
2017-10-10 01:30:29 +03:00
|
|
|
|
2019-11-22 22:08:49 +03:00
|
|
|
// These definitions echo those in the debugger application's
|
|
|
|
// debugshaderrecord.h file
|
2017-10-10 01:30:29 +03:00
|
|
|
enum DebugShaderModifierRecordType {
|
|
|
|
DebugShaderModifierRecordTypeInvocationStartMarker,
|
|
|
|
DebugShaderModifierRecordTypeStep,
|
|
|
|
DebugShaderModifierRecordTypeEvent,
|
|
|
|
DebugShaderModifierRecordTypeInputRegister,
|
|
|
|
DebugShaderModifierRecordTypeReadRegister,
|
|
|
|
DebugShaderModifierRecordTypeWrittenRegister,
|
|
|
|
DebugShaderModifierRecordTypeRegisterRelativeIndex0,
|
|
|
|
DebugShaderModifierRecordTypeRegisterRelativeIndex1,
|
|
|
|
DebugShaderModifierRecordTypeRegisterRelativeIndex2,
|
|
|
|
DebugShaderModifierRecordTypeDXILStepVoid = 251,
|
|
|
|
DebugShaderModifierRecordTypeDXILStepFloat = 252,
|
|
|
|
DebugShaderModifierRecordTypeDXILStepUint32 = 253,
|
|
|
|
DebugShaderModifierRecordTypeDXILStepUint64 = 254,
|
|
|
|
DebugShaderModifierRecordTypeDXILStepDouble = 255,
|
|
|
|
};
|
|
|
|
|
2019-11-22 22:08:49 +03:00
|
|
|
// These structs echo those in the debugger application's debugshaderrecord.h
|
|
|
|
// file, but are recapitulated here because the originals use unnamed unions
|
|
|
|
// which are disallowed by DXCompiler's build.
|
|
|
|
//
|
|
|
|
#pragma pack(push, 4)
|
2017-10-10 01:30:29 +03:00
|
|
|
struct DebugShaderModifierRecordHeader {
|
2019-11-22 22:08:49 +03:00
|
|
|
union {
|
2017-10-10 01:30:29 +03:00
|
|
|
struct {
|
|
|
|
uint32_t SizeDwords : 4;
|
|
|
|
uint32_t Flags : 4;
|
|
|
|
uint32_t Type : 8;
|
|
|
|
uint32_t HeaderPayload : 16;
|
|
|
|
} Details;
|
|
|
|
uint32_t u32Header;
|
|
|
|
} Header;
|
|
|
|
uint32_t UID;
|
|
|
|
};
|
|
|
|
|
|
|
|
struct DebugShaderModifierRecordDXILStepBase {
|
|
|
|
union {
|
|
|
|
struct {
|
|
|
|
uint32_t SizeDwords : 4;
|
|
|
|
uint32_t Flags : 4;
|
|
|
|
uint32_t Type : 8;
|
|
|
|
uint32_t Opcode : 16;
|
|
|
|
} Details;
|
|
|
|
uint32_t u32Header;
|
|
|
|
} Header;
|
|
|
|
uint32_t UID;
|
|
|
|
uint32_t InstructionOffset;
|
|
|
|
};
|
|
|
|
|
2019-11-22 22:08:49 +03:00
|
|
|
template <typename ReturnType>
|
|
|
|
struct DebugShaderModifierRecordDXILStep
|
|
|
|
: public DebugShaderModifierRecordDXILStepBase {
|
2017-10-10 01:30:29 +03:00
|
|
|
ReturnType ReturnValue;
|
2019-01-29 16:42:54 +03:00
|
|
|
union {
|
|
|
|
struct {
|
|
|
|
uint32_t ValueOrdinalBase : 16;
|
|
|
|
uint32_t ValueOrdinalIndex : 16;
|
|
|
|
} Details;
|
|
|
|
uint32_t u32ValueOrdinal;
|
|
|
|
} ValueOrdinal;
|
2017-10-10 01:30:29 +03:00
|
|
|
};
|
|
|
|
|
2019-11-22 22:08:49 +03:00
|
|
|
template <>
|
|
|
|
struct DebugShaderModifierRecordDXILStep<void>
|
|
|
|
: public DebugShaderModifierRecordDXILStepBase {};
|
2017-10-10 01:30:29 +03:00
|
|
|
#pragma pack(pop)
|
|
|
|
|
2019-11-22 22:08:49 +03:00
|
|
|
uint32_t
|
|
|
|
DebugShaderModifierRecordPayloadSizeDwords(size_t recordTotalSizeBytes) {
|
|
|
|
return ((recordTotalSizeBytes - sizeof(DebugShaderModifierRecordHeader)) /
|
|
|
|
sizeof(uint32_t));
|
2017-10-10 01:30:29 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
class DxilDebugInstrumentation : public ModulePass {
|
|
|
|
|
|
|
|
private:
|
|
|
|
union ParametersAllTogether {
|
|
|
|
unsigned Parameters[3];
|
|
|
|
struct PixelShaderParameters {
|
|
|
|
unsigned X;
|
|
|
|
unsigned Y;
|
|
|
|
} PixelShader;
|
|
|
|
struct VertexShaderParameters {
|
|
|
|
unsigned VertexId;
|
|
|
|
unsigned InstanceId;
|
|
|
|
} VertexShader;
|
|
|
|
struct ComputeShaderParameters {
|
|
|
|
unsigned ThreadIdX;
|
|
|
|
unsigned ThreadIdY;
|
|
|
|
unsigned ThreadIdZ;
|
|
|
|
} ComputeShader;
|
2018-01-22 20:14:30 +03:00
|
|
|
struct GeometryShaderParameters {
|
|
|
|
unsigned PrimitiveId;
|
|
|
|
unsigned InstanceId;
|
|
|
|
} GeometryShader;
|
2019-11-22 22:08:49 +03:00
|
|
|
} m_Parameters = {{0, 0, 0}};
|
2017-10-10 01:30:29 +03:00
|
|
|
|
|
|
|
union SystemValueIndices {
|
|
|
|
struct PixelShaderParameters {
|
|
|
|
unsigned Position;
|
|
|
|
} PixelShader;
|
|
|
|
struct VertexShaderParameters {
|
|
|
|
unsigned VertexId;
|
|
|
|
unsigned InstanceId;
|
|
|
|
} VertexShader;
|
2018-01-22 20:14:30 +03:00
|
|
|
struct GeometryShaderParameters {
|
|
|
|
unsigned PrimitiveId;
|
|
|
|
unsigned InstanceId;
|
|
|
|
} GeometryShader;
|
2017-10-10 01:30:29 +03:00
|
|
|
};
|
|
|
|
|
2019-11-22 22:08:49 +03:00
|
|
|
uint64_t m_UAVSize = 1024 * 1024;
|
|
|
|
Value *m_SelectionCriterion = nullptr;
|
|
|
|
CallInst *m_HandleForUAV = nullptr;
|
|
|
|
Value *m_InvocationId = nullptr;
|
2017-10-10 01:30:29 +03:00
|
|
|
|
2019-11-22 22:08:49 +03:00
|
|
|
// Together these two values allow branchless writing to the UAV. An
|
|
|
|
// invocation of the shader is either of interest or not (e.g. it writes to
|
|
|
|
// the pixel the user selected for debugging or it doesn't). If not of
|
|
|
|
// interest, debugging output will still occur, but it will be relegated to
|
|
|
|
// the very top few bytes of the UAV. Invocations of interest, by contrast,
|
|
|
|
// will be written to the UAV at sequentially increasing offsets.
|
2017-10-10 01:30:29 +03:00
|
|
|
|
2019-11-22 22:08:49 +03:00
|
|
|
// This value will either be one or zero (one if the invocation is of
|
|
|
|
// interest, zero otherwise)
|
|
|
|
Value *m_OffsetMultiplicand = nullptr;
|
|
|
|
// This will either be zero (if the invocation is of interest) or
|
|
|
|
// (UAVSize)-(SmallValue) if not.
|
|
|
|
Value *m_OffsetAddend = nullptr;
|
2017-10-10 01:30:29 +03:00
|
|
|
|
2019-11-22 22:08:49 +03:00
|
|
|
Constant *m_OffsetMask = nullptr;
|
2017-10-10 01:30:29 +03:00
|
|
|
|
2020-05-19 19:21:30 +03:00
|
|
|
Constant *m_CounterOffset = nullptr;
|
|
|
|
|
2017-10-10 01:30:29 +03:00
|
|
|
struct BuilderContext {
|
|
|
|
Module &M;
|
|
|
|
DxilModule &DM;
|
2019-11-22 22:08:49 +03:00
|
|
|
LLVMContext &Ctx;
|
|
|
|
OP *HlslOP;
|
|
|
|
IRBuilder<> &Builder;
|
2017-10-10 01:30:29 +03:00
|
|
|
};
|
|
|
|
|
|
|
|
uint32_t m_RemainingReservedSpaceInBytes = 0;
|
2019-11-22 22:08:49 +03:00
|
|
|
Value *m_CurrentIndex = nullptr;
|
2017-10-10 01:30:29 +03:00
|
|
|
|
|
|
|
public:
|
|
|
|
static char ID; // Pass identification, replacement for typeid
|
|
|
|
explicit DxilDebugInstrumentation() : ModulePass(ID) {}
|
2019-11-22 22:08:49 +03:00
|
|
|
const char *getPassName() const override {
|
|
|
|
return "Add PIX debug instrumentation";
|
|
|
|
}
|
2017-10-10 01:30:29 +03:00
|
|
|
void applyOptions(PassOptions O) override;
|
|
|
|
bool runOnModule(Module &M) override;
|
|
|
|
|
|
|
|
private:
|
|
|
|
SystemValueIndices addRequiredSystemValues(BuilderContext &BC);
|
|
|
|
void addUAV(BuilderContext &BC);
|
2019-11-22 22:08:49 +03:00
|
|
|
void addInvocationSelectionProlog(BuilderContext &BC,
|
|
|
|
SystemValueIndices SVIndices);
|
|
|
|
Value *addPixelShaderProlog(BuilderContext &BC, SystemValueIndices SVIndices);
|
|
|
|
Value *addGeometryShaderProlog(BuilderContext &BC,
|
|
|
|
SystemValueIndices SVIndices);
|
|
|
|
Value *addDispatchedShaderProlog(BuilderContext &BC);
|
|
|
|
Value *addVertexShaderProlog(BuilderContext &BC,
|
|
|
|
SystemValueIndices SVIndices);
|
|
|
|
void addDebugEntryValue(BuilderContext &BC, Value *TheValue);
|
2017-10-10 01:30:29 +03:00
|
|
|
void addInvocationStartMarker(BuilderContext &BC);
|
|
|
|
void reserveDebugEntrySpace(BuilderContext &BC, uint32_t SpaceInDwords);
|
2019-01-10 23:48:29 +03:00
|
|
|
void addStoreStepDebugEntry(BuilderContext &BC, StoreInst *Inst);
|
2017-10-10 01:30:29 +03:00
|
|
|
void addStepDebugEntry(BuilderContext &BC, Instruction *Inst);
|
2019-11-22 22:08:49 +03:00
|
|
|
void addStepDebugEntryValue(BuilderContext &BC, std::uint32_t InstNum,
|
|
|
|
Value *V, std::uint32_t ValueOrdinal,
|
|
|
|
Value *ValueOrdinalIndex);
|
2017-10-10 01:30:29 +03:00
|
|
|
uint32_t UAVDumpingGroundOffset();
|
2019-11-22 22:08:49 +03:00
|
|
|
template <typename ReturnType>
|
|
|
|
void addStepEntryForType(DebugShaderModifierRecordType RecordType,
|
|
|
|
BuilderContext &BC, std::uint32_t InstNum, Value *V,
|
|
|
|
std::uint32_t ValueOrdinal,
|
|
|
|
Value *ValueOrdinalIndex);
|
2017-10-10 01:30:29 +03:00
|
|
|
};
|
|
|
|
|
|
|
|
void DxilDebugInstrumentation::applyOptions(PassOptions O) {
|
2018-01-27 02:43:44 +03:00
|
|
|
GetPassOptionUnsigned(O, "parameter0", &m_Parameters.Parameters[0], 0);
|
|
|
|
GetPassOptionUnsigned(O, "parameter1", &m_Parameters.Parameters[1], 0);
|
|
|
|
GetPassOptionUnsigned(O, "parameter2", &m_Parameters.Parameters[2], 0);
|
|
|
|
GetPassOptionUInt64(O, "UAVSize", &m_UAVSize, 1024 * 1024);
|
2017-10-10 01:30:29 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
uint32_t DxilDebugInstrumentation::UAVDumpingGroundOffset() {
|
|
|
|
return static_cast<uint32_t>(m_UAVSize - DebugBufferDumpingGroundSize);
|
|
|
|
}
|
|
|
|
|
2019-11-22 22:08:49 +03:00
|
|
|
DxilDebugInstrumentation::SystemValueIndices
|
|
|
|
DxilDebugInstrumentation::addRequiredSystemValues(BuilderContext &BC) {
|
2017-10-10 01:30:29 +03:00
|
|
|
SystemValueIndices SVIndices{};
|
|
|
|
|
2019-11-22 22:08:49 +03:00
|
|
|
hlsl::DxilSignature &InputSignature = BC.DM.GetInputSignature();
|
2017-10-10 01:30:29 +03:00
|
|
|
|
2019-11-22 22:08:49 +03:00
|
|
|
auto &InputElements = InputSignature.GetElements();
|
2017-10-10 01:30:29 +03:00
|
|
|
|
|
|
|
auto ShaderModel = BC.DM.GetShaderModel();
|
|
|
|
switch (ShaderModel->GetKind()) {
|
2019-10-15 02:14:38 +03:00
|
|
|
case DXIL::ShaderKind::Amplification:
|
|
|
|
case DXIL::ShaderKind::Mesh:
|
|
|
|
case DXIL::ShaderKind::Compute:
|
|
|
|
// Dispatch* thread Id is not in the input signature
|
|
|
|
break;
|
2017-10-10 01:30:29 +03:00
|
|
|
case DXIL::ShaderKind::Vertex: {
|
|
|
|
{
|
|
|
|
auto Existing_SV_VertexId = std::find_if(
|
2019-11-22 22:08:49 +03:00
|
|
|
InputElements.begin(), InputElements.end(),
|
|
|
|
[](const std::unique_ptr<DxilSignatureElement> &Element) {
|
|
|
|
return Element->GetSemantic()->GetKind() ==
|
|
|
|
hlsl::DXIL::SemanticKind::VertexID;
|
|
|
|
});
|
2017-10-10 01:30:29 +03:00
|
|
|
|
|
|
|
if (Existing_SV_VertexId == InputElements.end()) {
|
2019-11-22 22:08:49 +03:00
|
|
|
auto Added_SV_VertexId =
|
|
|
|
llvm::make_unique<DxilSignatureElement>(DXIL::SigPointKind::VSIn);
|
|
|
|
Added_SV_VertexId->Initialize("VertexId", hlsl::CompType::getF32(),
|
|
|
|
hlsl::DXIL::InterpolationMode::Undefined,
|
|
|
|
1, 1);
|
2017-10-10 01:30:29 +03:00
|
|
|
Added_SV_VertexId->AppendSemanticIndex(0);
|
|
|
|
Added_SV_VertexId->SetSigPointKind(DXIL::SigPointKind::VSIn);
|
|
|
|
Added_SV_VertexId->SetKind(hlsl::DXIL::SemanticKind::VertexID);
|
|
|
|
|
|
|
|
auto index = InputSignature.AppendElement(std::move(Added_SV_VertexId));
|
|
|
|
SVIndices.VertexShader.VertexId = InputElements[index]->GetID();
|
2019-11-22 22:08:49 +03:00
|
|
|
} else {
|
2017-10-10 01:30:29 +03:00
|
|
|
SVIndices.VertexShader.VertexId = Existing_SV_VertexId->get()->GetID();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
{
|
|
|
|
auto Existing_SV_InstanceId = std::find_if(
|
2019-11-22 22:08:49 +03:00
|
|
|
InputElements.begin(), InputElements.end(),
|
|
|
|
[](const std::unique_ptr<DxilSignatureElement> &Element) {
|
|
|
|
return Element->GetSemantic()->GetKind() ==
|
|
|
|
hlsl::DXIL::SemanticKind::InstanceID;
|
|
|
|
});
|
2017-10-10 01:30:29 +03:00
|
|
|
|
|
|
|
if (Existing_SV_InstanceId == InputElements.end()) {
|
2019-11-22 22:08:49 +03:00
|
|
|
auto Added_SV_InstanceId =
|
|
|
|
llvm::make_unique<DxilSignatureElement>(DXIL::SigPointKind::VSIn);
|
|
|
|
Added_SV_InstanceId->Initialize(
|
|
|
|
"InstanceId", hlsl::CompType::getF32(),
|
|
|
|
hlsl::DXIL::InterpolationMode::Undefined, 1, 1);
|
2017-10-10 01:30:29 +03:00
|
|
|
Added_SV_InstanceId->AppendSemanticIndex(0);
|
|
|
|
Added_SV_InstanceId->SetSigPointKind(DXIL::SigPointKind::VSIn);
|
|
|
|
Added_SV_InstanceId->SetKind(hlsl::DXIL::SemanticKind::InstanceID);
|
|
|
|
|
2019-11-22 22:08:49 +03:00
|
|
|
auto index =
|
|
|
|
InputSignature.AppendElement(std::move(Added_SV_InstanceId));
|
2017-10-10 01:30:29 +03:00
|
|
|
SVIndices.VertexShader.InstanceId = InputElements[index]->GetID();
|
2019-11-22 22:08:49 +03:00
|
|
|
} else {
|
|
|
|
SVIndices.VertexShader.InstanceId =
|
|
|
|
Existing_SV_InstanceId->get()->GetID();
|
2017-10-10 01:30:29 +03:00
|
|
|
}
|
|
|
|
}
|
2019-10-15 02:14:38 +03:00
|
|
|
} break;
|
2019-11-22 22:08:49 +03:00
|
|
|
case DXIL::ShaderKind::Geometry:
|
2018-01-22 20:14:30 +03:00
|
|
|
// GS Instance Id and Primitive Id are not in the input signature
|
2019-11-22 22:08:49 +03:00
|
|
|
break;
|
2019-10-15 02:14:38 +03:00
|
|
|
case DXIL::ShaderKind::Pixel: {
|
|
|
|
auto Existing_SV_Position =
|
|
|
|
std::find_if(InputElements.begin(), InputElements.end(),
|
|
|
|
[](const std::unique_ptr<DxilSignatureElement> &Element) {
|
|
|
|
return Element->GetSemantic()->GetKind() ==
|
|
|
|
hlsl::DXIL::SemanticKind::Position;
|
|
|
|
});
|
|
|
|
|
|
|
|
// SV_Position, if present, has to have full mask, so we needn't worry
|
|
|
|
// about the shader having selected components that don't include x or y.
|
|
|
|
// If not present, we add it.
|
|
|
|
if (Existing_SV_Position == InputElements.end()) {
|
|
|
|
auto Added_SV_Position =
|
|
|
|
llvm::make_unique<DxilSignatureElement>(DXIL::SigPointKind::PSIn);
|
|
|
|
Added_SV_Position->Initialize("Position", hlsl::CompType::getF32(),
|
|
|
|
hlsl::DXIL::InterpolationMode::Linear, 1,
|
|
|
|
4);
|
|
|
|
Added_SV_Position->AppendSemanticIndex(0);
|
|
|
|
Added_SV_Position->SetSigPointKind(DXIL::SigPointKind::PSIn);
|
|
|
|
Added_SV_Position->SetKind(hlsl::DXIL::SemanticKind::Position);
|
|
|
|
|
|
|
|
auto index = InputSignature.AppendElement(std::move(Added_SV_Position));
|
|
|
|
SVIndices.PixelShader.Position = InputElements[index]->GetID();
|
|
|
|
} else {
|
|
|
|
SVIndices.PixelShader.Position = Existing_SV_Position->get()->GetID();
|
|
|
|
}
|
|
|
|
} break;
|
2017-10-10 01:30:29 +03:00
|
|
|
default:
|
|
|
|
assert(false); // guaranteed by runOnModule
|
|
|
|
}
|
|
|
|
|
|
|
|
return SVIndices;
|
|
|
|
}
|
|
|
|
|
2019-11-22 22:08:49 +03:00
|
|
|
Value *DxilDebugInstrumentation::addDispatchedShaderProlog(BuilderContext &BC) {
|
|
|
|
Constant *Zero32Arg = BC.HlslOP->GetU32Const(0);
|
|
|
|
Constant *One32Arg = BC.HlslOP->GetU32Const(1);
|
|
|
|
Constant *Two32Arg = BC.HlslOP->GetU32Const(2);
|
|
|
|
|
|
|
|
auto ThreadIdFunc =
|
|
|
|
BC.HlslOP->GetOpFunc(DXIL::OpCode::ThreadId, Type::getInt32Ty(BC.Ctx));
|
|
|
|
Constant *Opcode = BC.HlslOP->GetU32Const((unsigned)DXIL::OpCode::ThreadId);
|
|
|
|
auto ThreadIdX =
|
|
|
|
BC.Builder.CreateCall(ThreadIdFunc, {Opcode, Zero32Arg}, "ThreadIdX");
|
|
|
|
auto ThreadIdY =
|
|
|
|
BC.Builder.CreateCall(ThreadIdFunc, {Opcode, One32Arg}, "ThreadIdY");
|
|
|
|
auto ThreadIdZ =
|
|
|
|
BC.Builder.CreateCall(ThreadIdFunc, {Opcode, Two32Arg}, "ThreadIdZ");
|
2017-10-10 01:30:29 +03:00
|
|
|
|
|
|
|
// Compare to expected thread ID
|
2019-11-22 22:08:49 +03:00
|
|
|
auto CompareToX = BC.Builder.CreateICmpEQ(
|
|
|
|
ThreadIdX, BC.HlslOP->GetU32Const(m_Parameters.ComputeShader.ThreadIdX),
|
|
|
|
"CompareToThreadIdX");
|
|
|
|
auto CompareToY = BC.Builder.CreateICmpEQ(
|
|
|
|
ThreadIdY, BC.HlslOP->GetU32Const(m_Parameters.ComputeShader.ThreadIdY),
|
|
|
|
"CompareToThreadIdY");
|
|
|
|
auto CompareToZ = BC.Builder.CreateICmpEQ(
|
|
|
|
ThreadIdZ, BC.HlslOP->GetU32Const(m_Parameters.ComputeShader.ThreadIdZ),
|
|
|
|
"CompareToThreadIdZ");
|
|
|
|
|
|
|
|
auto CompareXAndY =
|
|
|
|
BC.Builder.CreateAnd(CompareToX, CompareToY, "CompareXAndY");
|
|
|
|
|
|
|
|
auto CompareAll =
|
|
|
|
BC.Builder.CreateAnd(CompareXAndY, CompareToZ, "CompareAll");
|
2017-10-10 01:30:29 +03:00
|
|
|
|
|
|
|
return CompareAll;
|
|
|
|
}
|
|
|
|
|
2019-11-22 22:08:49 +03:00
|
|
|
Value *
|
|
|
|
DxilDebugInstrumentation::addVertexShaderProlog(BuilderContext &BC,
|
|
|
|
SystemValueIndices SVIndices) {
|
|
|
|
Constant *Zero32Arg = BC.HlslOP->GetU32Const(0);
|
|
|
|
Constant *Zero8Arg = BC.HlslOP->GetI8Const(0);
|
|
|
|
UndefValue *UndefArg = UndefValue::get(Type::getInt32Ty(BC.Ctx));
|
|
|
|
|
|
|
|
auto LoadInputOpFunc =
|
|
|
|
BC.HlslOP->GetOpFunc(DXIL::OpCode::LoadInput, Type::getInt32Ty(BC.Ctx));
|
|
|
|
Constant *LoadInputOpcode =
|
|
|
|
BC.HlslOP->GetU32Const((unsigned)DXIL::OpCode::LoadInput);
|
|
|
|
Constant *SV_Vert_ID =
|
|
|
|
BC.HlslOP->GetU32Const(SVIndices.VertexShader.VertexId);
|
|
|
|
auto VertId =
|
|
|
|
BC.Builder.CreateCall(LoadInputOpFunc,
|
|
|
|
{LoadInputOpcode, SV_Vert_ID, Zero32Arg /*row*/,
|
|
|
|
Zero8Arg /*column*/, UndefArg},
|
|
|
|
"VertId");
|
|
|
|
|
|
|
|
Constant *SV_Instance_ID =
|
|
|
|
BC.HlslOP->GetU32Const(SVIndices.VertexShader.InstanceId);
|
|
|
|
auto InstanceId =
|
|
|
|
BC.Builder.CreateCall(LoadInputOpFunc,
|
|
|
|
{LoadInputOpcode, SV_Instance_ID, Zero32Arg /*row*/,
|
|
|
|
Zero8Arg /*column*/, UndefArg},
|
|
|
|
"InstanceId");
|
2017-10-10 01:30:29 +03:00
|
|
|
|
|
|
|
// Compare to expected vertex ID and instance ID
|
2019-11-22 22:08:49 +03:00
|
|
|
auto CompareToVert = BC.Builder.CreateICmpEQ(
|
|
|
|
VertId, BC.HlslOP->GetU32Const(m_Parameters.VertexShader.VertexId),
|
|
|
|
"CompareToVertId");
|
|
|
|
auto CompareToInstance = BC.Builder.CreateICmpEQ(
|
|
|
|
InstanceId, BC.HlslOP->GetU32Const(m_Parameters.VertexShader.InstanceId),
|
|
|
|
"CompareToInstanceId");
|
|
|
|
auto CompareBoth =
|
|
|
|
BC.Builder.CreateAnd(CompareToVert, CompareToInstance, "CompareBoth");
|
2017-10-10 01:30:29 +03:00
|
|
|
|
|
|
|
return CompareBoth;
|
|
|
|
}
|
|
|
|
|
2019-11-22 22:08:49 +03:00
|
|
|
Value *DxilDebugInstrumentation::addGeometryShaderProlog(
|
|
|
|
BuilderContext &BC, SystemValueIndices SVIndices) {
|
2018-01-22 20:14:30 +03:00
|
|
|
|
2019-11-22 22:08:49 +03:00
|
|
|
auto PrimitiveIdOpFunc =
|
|
|
|
BC.HlslOP->GetOpFunc(DXIL::OpCode::PrimitiveID, Type::getInt32Ty(BC.Ctx));
|
|
|
|
Constant *PrimitiveIdOpcode =
|
|
|
|
BC.HlslOP->GetU32Const((unsigned)DXIL::OpCode::PrimitiveID);
|
|
|
|
auto PrimId =
|
|
|
|
BC.Builder.CreateCall(PrimitiveIdOpFunc, {PrimitiveIdOpcode}, "PrimId");
|
2018-01-22 20:14:30 +03:00
|
|
|
|
2019-11-22 22:08:49 +03:00
|
|
|
auto CompareToPrim = BC.Builder.CreateICmpEQ(
|
|
|
|
PrimId, BC.HlslOP->GetU32Const(m_Parameters.GeometryShader.PrimitiveId),
|
|
|
|
"CompareToPrimId");
|
2018-01-22 20:14:30 +03:00
|
|
|
|
|
|
|
if (BC.DM.GetGSInstanceCount() <= 1) {
|
|
|
|
return CompareToPrim;
|
|
|
|
}
|
|
|
|
|
2019-11-22 22:08:49 +03:00
|
|
|
auto GSInstanceIdOpFunc = BC.HlslOP->GetOpFunc(DXIL::OpCode::GSInstanceID,
|
|
|
|
Type::getInt32Ty(BC.Ctx));
|
|
|
|
Constant *GSInstanceIdOpcode =
|
|
|
|
BC.HlslOP->GetU32Const((unsigned)DXIL::OpCode::GSInstanceID);
|
|
|
|
auto GSInstanceId = BC.Builder.CreateCall(
|
|
|
|
GSInstanceIdOpFunc, {GSInstanceIdOpcode}, "GSInstanceId");
|
2018-01-22 20:14:30 +03:00
|
|
|
|
|
|
|
// Compare to expected vertex ID and instance ID
|
2019-11-22 22:08:49 +03:00
|
|
|
auto CompareToInstance = BC.Builder.CreateICmpEQ(
|
|
|
|
GSInstanceId,
|
|
|
|
BC.HlslOP->GetU32Const(m_Parameters.GeometryShader.InstanceId),
|
|
|
|
"CompareToInstanceId");
|
|
|
|
auto CompareBoth =
|
|
|
|
BC.Builder.CreateAnd(CompareToPrim, CompareToInstance, "CompareBoth");
|
2018-01-22 20:14:30 +03:00
|
|
|
|
|
|
|
return CompareBoth;
|
|
|
|
}
|
|
|
|
|
2019-11-22 22:08:49 +03:00
|
|
|
Value *
|
|
|
|
DxilDebugInstrumentation::addPixelShaderProlog(BuilderContext &BC,
|
|
|
|
SystemValueIndices SVIndices) {
|
|
|
|
Constant *Zero32Arg = BC.HlslOP->GetU32Const(0);
|
|
|
|
Constant *Zero8Arg = BC.HlslOP->GetI8Const(0);
|
|
|
|
Constant *One8Arg = BC.HlslOP->GetI8Const(1);
|
|
|
|
UndefValue *UndefArg = UndefValue::get(Type::getInt32Ty(BC.Ctx));
|
|
|
|
|
|
|
|
// Convert SV_POSITION to UINT
|
|
|
|
Value *XAsInt;
|
|
|
|
Value *YAsInt;
|
2017-10-10 01:30:29 +03:00
|
|
|
{
|
2019-11-22 22:08:49 +03:00
|
|
|
auto LoadInputOpFunc =
|
|
|
|
BC.HlslOP->GetOpFunc(DXIL::OpCode::LoadInput, Type::getFloatTy(BC.Ctx));
|
|
|
|
Constant *LoadInputOpcode =
|
|
|
|
BC.HlslOP->GetU32Const((unsigned)DXIL::OpCode::LoadInput);
|
|
|
|
Constant *SV_Pos_ID =
|
|
|
|
BC.HlslOP->GetU32Const(SVIndices.PixelShader.Position);
|
|
|
|
auto XPos =
|
|
|
|
BC.Builder.CreateCall(LoadInputOpFunc,
|
|
|
|
{LoadInputOpcode, SV_Pos_ID, Zero32Arg /*row*/,
|
|
|
|
Zero8Arg /*column*/, UndefArg},
|
|
|
|
"XPos");
|
|
|
|
auto YPos =
|
|
|
|
BC.Builder.CreateCall(LoadInputOpFunc,
|
|
|
|
{LoadInputOpcode, SV_Pos_ID, Zero32Arg /*row*/,
|
|
|
|
One8Arg /*column*/, UndefArg},
|
|
|
|
"YPos");
|
|
|
|
|
|
|
|
XAsInt = BC.Builder.CreateCast(Instruction::CastOps::FPToUI, XPos,
|
|
|
|
Type::getInt32Ty(BC.Ctx), "XIndex");
|
|
|
|
YAsInt = BC.Builder.CreateCast(Instruction::CastOps::FPToUI, YPos,
|
|
|
|
Type::getInt32Ty(BC.Ctx), "YIndex");
|
2017-10-10 01:30:29 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
// Compare to expected pixel position and primitive ID
|
2019-11-22 22:08:49 +03:00
|
|
|
auto CompareToX = BC.Builder.CreateICmpEQ(
|
|
|
|
XAsInt, BC.HlslOP->GetU32Const(m_Parameters.PixelShader.X), "CompareToX");
|
|
|
|
auto CompareToY = BC.Builder.CreateICmpEQ(
|
|
|
|
YAsInt, BC.HlslOP->GetU32Const(m_Parameters.PixelShader.Y), "CompareToY");
|
2017-10-10 01:30:29 +03:00
|
|
|
auto ComparePos = BC.Builder.CreateAnd(CompareToX, CompareToY, "ComparePos");
|
|
|
|
|
|
|
|
return ComparePos;
|
|
|
|
}
|
|
|
|
|
2019-11-22 22:08:49 +03:00
|
|
|
void DxilDebugInstrumentation::addUAV(BuilderContext &BC) {
|
2017-10-10 01:30:29 +03:00
|
|
|
// Set up a UAV with structure of a single int
|
2019-11-22 22:08:49 +03:00
|
|
|
unsigned int UAVResourceHandle =
|
|
|
|
static_cast<unsigned int>(BC.DM.GetUAVs().size());
|
|
|
|
SmallVector<llvm::Type *, 1> Elements{Type::getInt32Ty(BC.Ctx)};
|
|
|
|
llvm::StructType *UAVStructTy =
|
|
|
|
llvm::StructType::create(Elements, "PIX_DebugUAV_Type");
|
2017-10-10 01:30:29 +03:00
|
|
|
std::unique_ptr<DxilResource> pUAV = llvm::make_unique<DxilResource>();
|
|
|
|
pUAV->SetGlobalName("PIX_DebugUAVName");
|
|
|
|
pUAV->SetGlobalSymbol(UndefValue::get(UAVStructTy->getPointerTo()));
|
|
|
|
pUAV->SetID(UAVResourceHandle);
|
2019-11-22 22:08:49 +03:00
|
|
|
pUAV->SetSpaceID(
|
|
|
|
(unsigned int)-2); // This is the reserved-for-tools register space
|
2017-10-10 01:30:29 +03:00
|
|
|
pUAV->SetSampleCount(1);
|
|
|
|
pUAV->SetGloballyCoherent(false);
|
|
|
|
pUAV->SetHasCounter(false);
|
|
|
|
pUAV->SetCompType(CompType::getI32());
|
|
|
|
pUAV->SetLowerBound(0);
|
|
|
|
pUAV->SetRangeSize(1);
|
|
|
|
pUAV->SetKind(DXIL::ResourceKind::RawBuffer);
|
|
|
|
pUAV->SetRW(true);
|
|
|
|
|
|
|
|
auto ID = BC.DM.AddUAV(std::move(pUAV));
|
|
|
|
assert(ID == UAVResourceHandle);
|
|
|
|
|
|
|
|
BC.DM.m_ShaderFlags.SetEnableRawAndStructuredBuffers(true);
|
|
|
|
|
|
|
|
// Create handle for the newly-added UAV
|
2019-11-22 22:08:49 +03:00
|
|
|
Function *CreateHandleOpFunc =
|
|
|
|
BC.HlslOP->GetOpFunc(DXIL::OpCode::CreateHandle, Type::getVoidTy(BC.Ctx));
|
|
|
|
Constant *CreateHandleOpcodeArg =
|
|
|
|
BC.HlslOP->GetU32Const((unsigned)DXIL::OpCode::CreateHandle);
|
|
|
|
Constant *UAVVArg = BC.HlslOP->GetI8Const(
|
|
|
|
static_cast<std::underlying_type<DxilResourceBase::Class>::type>(
|
|
|
|
DXIL::ResourceClass::UAV));
|
|
|
|
Constant *MetaDataArg = BC.HlslOP->GetU32Const(
|
|
|
|
ID); // position of the metadata record in the corresponding metadata list
|
|
|
|
Constant *IndexArg = BC.HlslOP->GetU32Const(0); //
|
|
|
|
Constant *FalseArg =
|
|
|
|
BC.HlslOP->GetI1Const(0); // non-uniform resource index: false
|
|
|
|
m_HandleForUAV = BC.Builder.CreateCall(
|
|
|
|
CreateHandleOpFunc,
|
|
|
|
{CreateHandleOpcodeArg, UAVVArg, MetaDataArg, IndexArg, FalseArg},
|
|
|
|
"PIX_DebugUAV_Handle");
|
2017-10-10 01:30:29 +03:00
|
|
|
}
|
|
|
|
|
2019-11-22 22:08:49 +03:00
|
|
|
void DxilDebugInstrumentation::addInvocationSelectionProlog(
|
|
|
|
BuilderContext &BC, SystemValueIndices SVIndices) {
|
2017-10-10 01:30:29 +03:00
|
|
|
auto ShaderModel = BC.DM.GetShaderModel();
|
|
|
|
|
2019-11-22 22:08:49 +03:00
|
|
|
Value *ParameterTestResult = nullptr;
|
2017-10-10 01:30:29 +03:00
|
|
|
switch (ShaderModel->GetKind()) {
|
2019-10-15 02:14:38 +03:00
|
|
|
case DXIL::ShaderKind::Compute:
|
|
|
|
case DXIL::ShaderKind::Amplification:
|
|
|
|
case DXIL::ShaderKind::Mesh:
|
|
|
|
ParameterTestResult = addDispatchedShaderProlog(BC);
|
2017-10-10 01:30:29 +03:00
|
|
|
break;
|
2018-01-22 20:14:30 +03:00
|
|
|
case DXIL::ShaderKind::Geometry:
|
|
|
|
ParameterTestResult = addGeometryShaderProlog(BC, SVIndices);
|
|
|
|
break;
|
|
|
|
case DXIL::ShaderKind::Vertex:
|
|
|
|
ParameterTestResult = addVertexShaderProlog(BC, SVIndices);
|
2017-10-10 01:30:29 +03:00
|
|
|
break;
|
2019-10-15 02:14:38 +03:00
|
|
|
case DXIL::ShaderKind::Pixel:
|
|
|
|
ParameterTestResult = addPixelShaderProlog(BC, SVIndices);
|
2017-10-10 01:30:29 +03:00
|
|
|
break;
|
|
|
|
default:
|
|
|
|
assert(false); // guaranteed by runOnModule
|
|
|
|
}
|
|
|
|
|
2019-11-22 22:08:49 +03:00
|
|
|
// This is a convenient place to calculate the values that modify the UAV
|
|
|
|
// offset for invocations of interest and for UAV size.
|
|
|
|
m_OffsetMultiplicand =
|
|
|
|
BC.Builder.CreateCast(Instruction::CastOps::ZExt, ParameterTestResult,
|
|
|
|
Type::getInt32Ty(BC.Ctx), "OffsetMultiplicand");
|
|
|
|
auto InverseOffsetMultiplicand =
|
|
|
|
BC.Builder.CreateSub(BC.HlslOP->GetU32Const(1), m_OffsetMultiplicand,
|
|
|
|
"ComplementOfMultiplicand");
|
|
|
|
m_OffsetAddend =
|
|
|
|
BC.Builder.CreateMul(BC.HlslOP->GetU32Const(UAVDumpingGroundOffset()),
|
|
|
|
InverseOffsetMultiplicand, "OffsetAddend");
|
2017-10-10 01:30:29 +03:00
|
|
|
m_OffsetMask = BC.HlslOP->GetU32Const(UAVDumpingGroundOffset() - 1);
|
|
|
|
|
2020-05-19 19:21:30 +03:00
|
|
|
m_CounterOffset = BC.HlslOP->GetU32Const(UAVDumpingGroundOffset() + CounterOffsetBeyondUsefulData);
|
|
|
|
|
2017-10-10 01:30:29 +03:00
|
|
|
m_SelectionCriterion = ParameterTestResult;
|
|
|
|
}
|
|
|
|
|
2019-11-22 22:08:49 +03:00
|
|
|
void DxilDebugInstrumentation::reserveDebugEntrySpace(BuilderContext &BC,
|
|
|
|
uint32_t SpaceInBytes) {
|
2017-10-10 01:30:29 +03:00
|
|
|
assert(m_CurrentIndex == nullptr);
|
|
|
|
assert(m_RemainingReservedSpaceInBytes == 0);
|
|
|
|
|
|
|
|
m_RemainingReservedSpaceInBytes = SpaceInBytes;
|
|
|
|
|
|
|
|
// Insert the UAV increment instruction:
|
2019-11-22 22:08:49 +03:00
|
|
|
Function *AtomicOpFunc =
|
|
|
|
BC.HlslOP->GetOpFunc(OP::OpCode::AtomicBinOp, Type::getInt32Ty(BC.Ctx));
|
|
|
|
Constant *AtomicBinOpcode =
|
|
|
|
BC.HlslOP->GetU32Const((unsigned)OP::OpCode::AtomicBinOp);
|
|
|
|
Constant *AtomicAdd =
|
|
|
|
BC.HlslOP->GetU32Const((unsigned)DXIL::AtomicBinOpCode::Add);
|
|
|
|
UndefValue *UndefArg = UndefValue::get(Type::getInt32Ty(BC.Ctx));
|
2017-10-10 01:30:29 +03:00
|
|
|
|
|
|
|
// so inc will be zero for uninteresting invocations:
|
2019-11-22 22:08:49 +03:00
|
|
|
Constant *Increment = BC.HlslOP->GetU32Const(SpaceInBytes);
|
|
|
|
Value *IncrementForThisInvocation = BC.Builder.CreateMul(
|
|
|
|
Increment, m_OffsetMultiplicand, "IncrementForThisInvocation");
|
|
|
|
|
|
|
|
auto PreviousValue = BC.Builder.CreateCall(
|
|
|
|
AtomicOpFunc,
|
|
|
|
{
|
2020-05-19 19:21:30 +03:00
|
|
|
AtomicBinOpcode, // i32, ; opcode
|
|
|
|
m_HandleForUAV, // %dx.types.Handle, ; resource handle
|
|
|
|
AtomicAdd, // i32, ; binary operation code : EXCHANGE, IADD, AND, OR,
|
|
|
|
// XOR, IMIN, IMAX, UMIN, UMAX
|
|
|
|
m_CounterOffset, // i32, ; coordinate c0: index in bytes
|
|
|
|
UndefArg, // i32, ; coordinate c1 (unused)
|
|
|
|
UndefArg, // i32, ; coordinate c2 (unused)
|
2019-11-22 22:08:49 +03:00
|
|
|
IncrementForThisInvocation, // i32); increment value
|
|
|
|
},
|
|
|
|
"UAVIncResult");
|
|
|
|
|
|
|
|
if (m_InvocationId == nullptr) {
|
|
|
|
m_InvocationId = PreviousValue;
|
2017-10-10 01:30:29 +03:00
|
|
|
}
|
|
|
|
|
2019-11-22 22:08:49 +03:00
|
|
|
auto MaskedForLimit =
|
|
|
|
BC.Builder.CreateAnd(PreviousValue, m_OffsetMask, "MaskedForUAVLimit");
|
|
|
|
// The return value will either end up being itself (multiplied by one and
|
|
|
|
// added with zero) or the "dump uninteresting things here" value of (UAVSize
|
|
|
|
// - a bit).
|
|
|
|
auto MultipliedForInterest = BC.Builder.CreateMul(
|
|
|
|
MaskedForLimit, m_OffsetMultiplicand, "MultipliedForInterest");
|
|
|
|
auto AddedForInterest = BC.Builder.CreateAdd(
|
|
|
|
MultipliedForInterest, m_OffsetAddend, "AddedForInterest");
|
2017-10-10 01:30:29 +03:00
|
|
|
m_CurrentIndex = AddedForInterest;
|
|
|
|
}
|
|
|
|
|
2019-11-22 22:08:49 +03:00
|
|
|
void DxilDebugInstrumentation::addDebugEntryValue(BuilderContext &BC,
|
|
|
|
Value *TheValue) {
|
2017-10-10 01:30:29 +03:00
|
|
|
assert(m_RemainingReservedSpaceInBytes > 0);
|
|
|
|
|
|
|
|
auto TheValueTypeID = TheValue->getType()->getTypeID();
|
|
|
|
if (TheValueTypeID == Type::TypeID::DoubleTyID) {
|
2019-11-22 22:08:49 +03:00
|
|
|
Function *SplitDouble =
|
|
|
|
BC.HlslOP->GetOpFunc(OP::OpCode::SplitDouble, TheValue->getType());
|
|
|
|
Constant *SplitDoubleOpcode =
|
|
|
|
BC.HlslOP->GetU32Const((unsigned)DXIL::OpCode::SplitDouble);
|
|
|
|
auto SplitDoubleIntruction = BC.Builder.CreateCall(
|
|
|
|
SplitDouble, {SplitDoubleOpcode, TheValue}, "SplitDouble");
|
|
|
|
auto LowBits =
|
|
|
|
BC.Builder.CreateExtractValue(SplitDoubleIntruction, 0, "LowBits");
|
|
|
|
auto HighBits =
|
|
|
|
BC.Builder.CreateExtractValue(SplitDoubleIntruction, 1, "HighBits");
|
|
|
|
// addDebugEntryValue(BC, BC.HlslOP->GetU32Const(0)); // padding
|
2017-10-10 01:30:29 +03:00
|
|
|
addDebugEntryValue(BC, LowBits);
|
|
|
|
addDebugEntryValue(BC, HighBits);
|
2019-11-22 22:08:49 +03:00
|
|
|
} else if (TheValueTypeID == Type::TypeID::IntegerTyID &&
|
|
|
|
TheValue->getType()->getIntegerBitWidth() == 64) {
|
|
|
|
auto LowBits =
|
|
|
|
BC.Builder.CreateTrunc(TheValue, Type::getInt32Ty(BC.Ctx), "LowBits");
|
2017-10-10 01:30:29 +03:00
|
|
|
auto ShiftedBits = BC.Builder.CreateLShr(TheValue, 32, "ShiftedBits");
|
2019-11-22 22:08:49 +03:00
|
|
|
auto HighBits = BC.Builder.CreateTrunc(
|
|
|
|
ShiftedBits, Type::getInt32Ty(BC.Ctx), "HighBits");
|
|
|
|
// addDebugEntryValue(BC, BC.HlslOP->GetU32Const(0)); // padding
|
2017-10-10 01:30:29 +03:00
|
|
|
addDebugEntryValue(BC, LowBits);
|
|
|
|
addDebugEntryValue(BC, HighBits);
|
2019-11-22 22:08:49 +03:00
|
|
|
} else if (TheValueTypeID == Type::TypeID::IntegerTyID &&
|
|
|
|
(TheValue->getType()->getIntegerBitWidth() == 16 ||
|
|
|
|
TheValue->getType()->getIntegerBitWidth() == 1)) {
|
|
|
|
auto As32 =
|
|
|
|
BC.Builder.CreateZExt(TheValue, Type::getInt32Ty(BC.Ctx), "As32");
|
2017-10-10 01:30:29 +03:00
|
|
|
addDebugEntryValue(BC, As32);
|
2019-11-22 22:08:49 +03:00
|
|
|
} else if (TheValueTypeID == Type::TypeID::HalfTyID) {
|
|
|
|
auto AsFloat =
|
|
|
|
BC.Builder.CreateFPCast(TheValue, Type::getFloatTy(BC.Ctx), "AsFloat");
|
2017-10-10 01:30:29 +03:00
|
|
|
addDebugEntryValue(BC, AsFloat);
|
2019-11-22 22:08:49 +03:00
|
|
|
} else {
|
|
|
|
Function *StoreValue =
|
|
|
|
BC.HlslOP->GetOpFunc(OP::OpCode::BufferStore,
|
|
|
|
TheValue->getType()); // Type::getInt32Ty(BC.Ctx));
|
|
|
|
Constant *StoreValueOpcode =
|
|
|
|
BC.HlslOP->GetU32Const((unsigned)DXIL::OpCode::BufferStore);
|
|
|
|
UndefValue *Undef32Arg = UndefValue::get(Type::getInt32Ty(BC.Ctx));
|
|
|
|
UndefValue *UndefArg = nullptr;
|
2017-10-10 01:30:29 +03:00
|
|
|
if (TheValueTypeID == Type::TypeID::IntegerTyID) {
|
2019-11-22 22:08:49 +03:00
|
|
|
UndefArg = UndefValue::get(Type::getInt32Ty(BC.Ctx));
|
|
|
|
} else if (TheValueTypeID == Type::TypeID::FloatTyID) {
|
|
|
|
UndefArg = UndefValue::get(Type::getFloatTy(BC.Ctx));
|
|
|
|
} else {
|
|
|
|
// The above are the only two valid types for a UAV store
|
|
|
|
assert(false);
|
2017-10-10 01:30:29 +03:00
|
|
|
}
|
2019-11-22 22:08:49 +03:00
|
|
|
Constant *WriteMask_X = BC.HlslOP->GetI8Const(1);
|
|
|
|
(void)BC.Builder.CreateCall(
|
|
|
|
StoreValue, {StoreValueOpcode, // i32 opcode
|
|
|
|
m_HandleForUAV, // %dx.types.Handle, ; resource handle
|
|
|
|
m_CurrentIndex, // i32 c0: index in bytes into UAV
|
|
|
|
Undef32Arg, // i32 c1: unused
|
|
|
|
TheValue,
|
|
|
|
UndefArg, // unused values
|
|
|
|
UndefArg, // unused values
|
|
|
|
UndefArg, // unused values
|
|
|
|
WriteMask_X});
|
2017-10-10 01:30:29 +03:00
|
|
|
|
|
|
|
m_RemainingReservedSpaceInBytes -= 4;
|
2019-11-22 22:08:49 +03:00
|
|
|
assert(m_RemainingReservedSpaceInBytes < 1024); // check for underflow
|
2017-10-10 01:30:29 +03:00
|
|
|
|
|
|
|
if (m_RemainingReservedSpaceInBytes != 0) {
|
2019-11-22 22:08:49 +03:00
|
|
|
m_CurrentIndex =
|
|
|
|
BC.Builder.CreateAdd(m_CurrentIndex, BC.HlslOP->GetU32Const(4));
|
|
|
|
} else {
|
2017-10-10 01:30:29 +03:00
|
|
|
m_CurrentIndex = nullptr;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void DxilDebugInstrumentation::addInvocationStartMarker(BuilderContext &BC) {
|
2019-11-22 22:08:49 +03:00
|
|
|
DebugShaderModifierRecordHeader marker{{{0, 0, 0, 0}}, 0};
|
2017-10-10 01:30:29 +03:00
|
|
|
reserveDebugEntrySpace(BC, sizeof(marker));
|
|
|
|
|
2019-11-22 22:08:49 +03:00
|
|
|
marker.Header.Details.SizeDwords =
|
|
|
|
DebugShaderModifierRecordPayloadSizeDwords(sizeof(marker));
|
|
|
|
;
|
2017-10-10 01:30:29 +03:00
|
|
|
marker.Header.Details.Flags = 0;
|
2019-11-22 22:08:49 +03:00
|
|
|
marker.Header.Details.Type =
|
|
|
|
DebugShaderModifierRecordTypeInvocationStartMarker;
|
2017-10-10 01:30:29 +03:00
|
|
|
addDebugEntryValue(BC, BC.HlslOP->GetU32Const(marker.Header.u32Header));
|
|
|
|
addDebugEntryValue(BC, m_InvocationId);
|
|
|
|
}
|
|
|
|
|
2019-11-22 22:08:49 +03:00
|
|
|
template <typename ReturnType>
|
|
|
|
void DxilDebugInstrumentation::addStepEntryForType(
|
|
|
|
DebugShaderModifierRecordType RecordType, BuilderContext &BC,
|
|
|
|
std::uint32_t InstNum, Value *V, std::uint32_t ValueOrdinal,
|
|
|
|
Value *ValueOrdinalIndex) {
|
2017-10-10 01:30:29 +03:00
|
|
|
DebugShaderModifierRecordDXILStep<ReturnType> step = {};
|
|
|
|
reserveDebugEntrySpace(BC, sizeof(step));
|
|
|
|
|
2019-11-22 22:08:49 +03:00
|
|
|
step.Header.Details.SizeDwords =
|
|
|
|
DebugShaderModifierRecordPayloadSizeDwords(sizeof(step));
|
2017-10-10 01:30:29 +03:00
|
|
|
step.Header.Details.Type = static_cast<uint8_t>(RecordType);
|
|
|
|
addDebugEntryValue(BC, BC.HlslOP->GetU32Const(step.Header.u32Header));
|
|
|
|
addDebugEntryValue(BC, m_InvocationId);
|
2019-01-29 16:42:54 +03:00
|
|
|
addDebugEntryValue(BC, BC.HlslOP->GetU32Const(InstNum));
|
2017-10-10 01:30:29 +03:00
|
|
|
|
|
|
|
if (RecordType != DebugShaderModifierRecordTypeDXILStepVoid) {
|
2019-01-10 23:48:29 +03:00
|
|
|
addDebugEntryValue(BC, V);
|
2019-01-29 16:42:54 +03:00
|
|
|
|
|
|
|
IRBuilder<> &B = BC.Builder;
|
|
|
|
|
|
|
|
Value *VO = BC.HlslOP->GetU32Const(ValueOrdinal << 16);
|
2019-11-22 22:08:49 +03:00
|
|
|
Value *VOI = B.CreateAnd(ValueOrdinalIndex, BC.HlslOP->GetU32Const(0xFFFF),
|
|
|
|
"ValueOrdinalIndex");
|
|
|
|
Value *EncodedValueOrdinalAndIndex =
|
|
|
|
BC.Builder.CreateOr(VO, VOI, "ValueOrdinal");
|
2019-01-29 16:42:54 +03:00
|
|
|
addDebugEntryValue(BC, EncodedValueOrdinalAndIndex);
|
2019-01-10 23:48:29 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-11-22 22:08:49 +03:00
|
|
|
void DxilDebugInstrumentation::addStoreStepDebugEntry(BuilderContext &BC,
|
|
|
|
StoreInst *Inst) {
|
2019-01-29 16:42:54 +03:00
|
|
|
std::uint32_t ValueOrdinalBase;
|
|
|
|
std::uint32_t UnusedValueOrdinalSize;
|
|
|
|
llvm::Value *ValueOrdinalIndex;
|
2019-11-22 22:08:49 +03:00
|
|
|
if (!pix_dxil::PixAllocaRegWrite::FromInst(Inst, &ValueOrdinalBase,
|
|
|
|
&UnusedValueOrdinalSize,
|
|
|
|
&ValueOrdinalIndex)) {
|
2019-01-10 23:48:29 +03:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2019-01-29 16:42:54 +03:00
|
|
|
std::uint32_t InstNum;
|
|
|
|
if (!pix_dxil::PixDxilInstNum::FromInst(Inst, &InstNum)) {
|
2019-01-10 23:48:29 +03:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2019-11-22 22:08:49 +03:00
|
|
|
addStepDebugEntryValue(BC, InstNum, Inst->getValueOperand(), ValueOrdinalBase,
|
|
|
|
ValueOrdinalIndex);
|
2017-10-10 01:30:29 +03:00
|
|
|
}
|
|
|
|
|
2019-11-22 22:08:49 +03:00
|
|
|
void DxilDebugInstrumentation::addStepDebugEntry(BuilderContext &BC,
|
|
|
|
Instruction *Inst) {
|
2017-10-10 01:30:29 +03:00
|
|
|
if (Inst->getOpcode() == Instruction::OtherOps::PHI) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2020-10-02 01:06:02 +03:00
|
|
|
if (Inst->getOpcode() == Instruction::OtherOps::Call) {
|
|
|
|
if (Inst->getNumOperands() > 0) {
|
|
|
|
if (auto *asInt =
|
|
|
|
llvm::cast_or_null<llvm::ConstantInt>(Inst->getOperand(0))) {
|
|
|
|
if (asInt->getZExtValue() == (uint64_t)DXIL::OpCode::AllocateRayQuery) {
|
|
|
|
// Ray query handles should not be stored in the debug trace UAV
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-01-10 23:48:29 +03:00
|
|
|
if (auto *St = llvm::dyn_cast<llvm::StoreInst>(Inst)) {
|
|
|
|
addStoreStepDebugEntry(BC, St);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
std::uint32_t RegNum;
|
|
|
|
if (!pix_dxil::PixDxilReg::FromInst(Inst, &RegNum)) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2019-01-29 16:42:54 +03:00
|
|
|
std::uint32_t InstNum;
|
|
|
|
if (!pix_dxil::PixDxilInstNum::FromInst(Inst, &InstNum)) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
addStepDebugEntryValue(BC, InstNum, Inst, RegNum, BC.Builder.getInt32(0));
|
2019-01-10 23:48:29 +03:00
|
|
|
}
|
|
|
|
|
2019-11-22 22:08:49 +03:00
|
|
|
void DxilDebugInstrumentation::addStepDebugEntryValue(
|
|
|
|
BuilderContext &BC, std::uint32_t InstNum, Value *V,
|
|
|
|
std::uint32_t ValueOrdinal, Value *ValueOrdinalIndex) {
|
2019-01-10 23:48:29 +03:00
|
|
|
const Type::TypeID ID = V->getType()->getTypeID();
|
2017-10-10 01:30:29 +03:00
|
|
|
|
|
|
|
switch (ID) {
|
|
|
|
case Type::TypeID::StructTyID:
|
|
|
|
case Type::TypeID::VoidTyID:
|
2019-11-22 22:08:49 +03:00
|
|
|
addStepEntryForType<void>(DebugShaderModifierRecordTypeDXILStepVoid, BC,
|
|
|
|
InstNum, V, ValueOrdinal, ValueOrdinalIndex);
|
2017-10-10 01:30:29 +03:00
|
|
|
break;
|
|
|
|
case Type::TypeID::FloatTyID:
|
2019-11-22 22:08:49 +03:00
|
|
|
addStepEntryForType<float>(DebugShaderModifierRecordTypeDXILStepFloat, BC,
|
|
|
|
InstNum, V, ValueOrdinal, ValueOrdinalIndex);
|
2017-10-10 01:30:29 +03:00
|
|
|
break;
|
|
|
|
case Type::TypeID::IntegerTyID:
|
2019-01-10 23:48:29 +03:00
|
|
|
if (V->getType()->getIntegerBitWidth() == 64) {
|
2019-11-22 22:08:49 +03:00
|
|
|
addStepEntryForType<uint64_t>(DebugShaderModifierRecordTypeDXILStepUint64,
|
|
|
|
BC, InstNum, V, ValueOrdinal,
|
|
|
|
ValueOrdinalIndex);
|
|
|
|
} else {
|
|
|
|
addStepEntryForType<uint32_t>(DebugShaderModifierRecordTypeDXILStepUint32,
|
|
|
|
BC, InstNum, V, ValueOrdinal,
|
|
|
|
ValueOrdinalIndex);
|
2017-10-10 01:30:29 +03:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
case Type::TypeID::DoubleTyID:
|
2019-11-22 22:08:49 +03:00
|
|
|
addStepEntryForType<double>(DebugShaderModifierRecordTypeDXILStepDouble, BC,
|
|
|
|
InstNum, V, ValueOrdinal, ValueOrdinalIndex);
|
2017-10-10 01:30:29 +03:00
|
|
|
break;
|
|
|
|
case Type::TypeID::HalfTyID:
|
2019-11-22 22:08:49 +03:00
|
|
|
addStepEntryForType<float>(DebugShaderModifierRecordTypeDXILStepFloat, BC,
|
|
|
|
InstNum, V, ValueOrdinal, ValueOrdinalIndex);
|
2017-10-10 01:30:29 +03:00
|
|
|
break;
|
2017-11-01 22:31:05 +03:00
|
|
|
case Type::TypeID::PointerTyID:
|
2019-11-22 22:08:49 +03:00
|
|
|
// Skip pointer calculation instructions. They aren't particularly
|
|
|
|
// meaningful to the user (being a mere implementation detail for lookup
|
|
|
|
// tables, etc.), and their type is problematic from a UI point of view. The
|
|
|
|
// subsequent instructions that dereference the pointer will be properly
|
|
|
|
// instrumented and show the (meaningful) retrieved value.
|
2017-11-01 22:31:05 +03:00
|
|
|
break;
|
2017-10-10 01:30:29 +03:00
|
|
|
case Type::TypeID::FP128TyID:
|
|
|
|
case Type::TypeID::LabelTyID:
|
|
|
|
case Type::TypeID::MetadataTyID:
|
|
|
|
case Type::TypeID::FunctionTyID:
|
|
|
|
case Type::TypeID::ArrayTyID:
|
|
|
|
case Type::TypeID::VectorTyID:
|
2018-06-09 03:19:52 +03:00
|
|
|
case Type::TypeID::X86_FP80TyID:
|
|
|
|
case Type::TypeID::X86_MMXTyID:
|
|
|
|
case Type::TypeID::PPC_FP128TyID:
|
2017-10-10 01:30:29 +03:00
|
|
|
assert(false);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
bool DxilDebugInstrumentation::runOnModule(Module &M) {
|
|
|
|
DxilModule &DM = M.GetOrCreateDxilModule();
|
2019-11-22 22:08:49 +03:00
|
|
|
LLVMContext &Ctx = M.getContext();
|
2017-10-10 01:30:29 +03:00
|
|
|
OP *HlslOP = DM.GetOP();
|
|
|
|
|
|
|
|
auto ShaderModel = DM.GetShaderModel();
|
|
|
|
switch (ShaderModel->GetKind()) {
|
2019-10-15 02:14:38 +03:00
|
|
|
case DXIL::ShaderKind::Amplification:
|
|
|
|
case DXIL::ShaderKind::Mesh:
|
2017-10-10 01:30:29 +03:00
|
|
|
case DXIL::ShaderKind::Vertex:
|
2018-01-22 20:14:30 +03:00
|
|
|
case DXIL::ShaderKind::Geometry:
|
2019-10-15 02:14:38 +03:00
|
|
|
case DXIL::ShaderKind::Pixel:
|
|
|
|
case DXIL::ShaderKind::Compute:
|
2017-10-10 01:30:29 +03:00
|
|
|
break;
|
|
|
|
default:
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
// First record pointers to all instructions in the function:
|
2019-11-22 22:08:49 +03:00
|
|
|
std::vector<Instruction *> AllInstructions;
|
|
|
|
for (inst_iterator I = inst_begin(DM.GetEntryFunction()),
|
|
|
|
E = inst_end(DM.GetEntryFunction());
|
|
|
|
I != E; ++I) {
|
2017-10-10 01:30:29 +03:00
|
|
|
AllInstructions.push_back(&*I);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Branchless instrumentation requires taking care of a few things:
|
2019-11-22 22:08:49 +03:00
|
|
|
// -Each invocation of the shader will be either of interest or not of
|
|
|
|
// interest
|
2017-10-10 01:30:29 +03:00
|
|
|
// -If of interest, the offset into the output UAV will be as expected
|
2019-11-22 22:08:49 +03:00
|
|
|
// -If not, the offset is forced to (UAVsize) - (Small Amount), and that
|
|
|
|
// output is ignored by the CPU-side code.
|
|
|
|
// -The invocation of interest may overflow the UAV. This is handled by taking
|
|
|
|
// the modulus of the
|
|
|
|
// output index. Overflow is then detected on the CPU side by checking for
|
|
|
|
// the presence of a canary value at (UAVSize) - (Small Amount) * 2 (which is
|
|
|
|
// actually a conservative definition of overflow).
|
2017-10-10 01:30:29 +03:00
|
|
|
//
|
|
|
|
|
2019-11-22 22:08:49 +03:00
|
|
|
Instruction *firstInsertionPt =
|
2020-10-06 02:23:12 +03:00
|
|
|
dxilutil::FirstNonAllocaInsertionPt(DM.GetEntryFunction());
|
2017-10-10 01:30:29 +03:00
|
|
|
IRBuilder<> Builder(firstInsertionPt);
|
|
|
|
|
2019-11-22 22:08:49 +03:00
|
|
|
BuilderContext BC{M, DM, Ctx, HlslOP, Builder};
|
2017-10-10 01:30:29 +03:00
|
|
|
|
|
|
|
addUAV(BC);
|
|
|
|
auto SystemValues = addRequiredSystemValues(BC);
|
|
|
|
addInvocationSelectionProlog(BC, SystemValues);
|
|
|
|
addInvocationStartMarker(BC);
|
|
|
|
|
2019-12-04 04:11:31 +03:00
|
|
|
// Explicitly name new blocks in order to provide stable names for testing purposes
|
|
|
|
int NewBlockCounter = 0;
|
|
|
|
|
2019-11-22 22:08:49 +03:00
|
|
|
auto Fn = DM.GetEntryFunction();
|
|
|
|
auto &Blocks = Fn->getBasicBlockList();
|
2019-11-22 23:46:33 +03:00
|
|
|
for (auto &CurrentBlock : Blocks) {
|
2019-11-22 22:08:49 +03:00
|
|
|
struct ValueAndPhi {
|
|
|
|
Value *Val;
|
|
|
|
PHINode *Phi;
|
|
|
|
unsigned Index;
|
|
|
|
};
|
|
|
|
|
|
|
|
std::map<BasicBlock *, std::vector<ValueAndPhi>> InsertableEdges;
|
|
|
|
|
2019-11-22 23:46:33 +03:00
|
|
|
auto &Is = CurrentBlock.getInstList();
|
2019-11-22 22:08:49 +03:00
|
|
|
for (auto &Inst : Is) {
|
|
|
|
if (Inst.getOpcode() != Instruction::OtherOps::PHI) {
|
|
|
|
break;
|
|
|
|
}
|
2019-11-22 23:46:33 +03:00
|
|
|
PHINode &PN = llvm::cast<PHINode>(Inst);
|
2019-11-22 22:08:49 +03:00
|
|
|
for (unsigned i = 0, e = PN.getNumIncomingValues(); i != e; ++i) {
|
|
|
|
BasicBlock *PhiBB = PN.getIncomingBlock(i);
|
|
|
|
Value *PhiVal = PN.getIncomingValue(i);
|
|
|
|
InsertableEdges[PhiBB].push_back({PhiVal, &PN, i});
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
for (auto &InsertableEdge : InsertableEdges) {
|
2019-11-28 03:33:13 +03:00
|
|
|
auto *NewBlock = BasicBlock::Create(Ctx, "PIXDebug" + std::to_string(NewBlockCounter++),
|
2019-11-22 22:08:49 +03:00
|
|
|
InsertableEdge.first->getParent());
|
|
|
|
IRBuilder<> Builder(NewBlock);
|
|
|
|
|
|
|
|
auto *PreviousBlock = InsertableEdge.first;
|
2019-11-22 23:46:33 +03:00
|
|
|
|
|
|
|
// Modify all successor operands of the terminator in the previous block
|
|
|
|
// that match the current block to point to the new block:
|
|
|
|
TerminatorInst *terminator = PreviousBlock->getTerminator();
|
|
|
|
unsigned NumSuccessors = terminator->getNumSuccessors();
|
|
|
|
for (unsigned SuccessorIndex = 0; SuccessorIndex < NumSuccessors;
|
|
|
|
++SuccessorIndex) {
|
|
|
|
auto *CurrentSuccessor = terminator->getSuccessor(SuccessorIndex);
|
|
|
|
if (CurrentSuccessor == &CurrentBlock) {
|
|
|
|
terminator->setSuccessor(SuccessorIndex, NewBlock);
|
2019-11-22 22:08:49 +03:00
|
|
|
}
|
2019-11-22 23:46:33 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
// Modify the Phis and add debug instrumentation
|
|
|
|
for (auto &ValueNPhi : InsertableEdge.second) {
|
|
|
|
// Modify the phi to refer to the new block:
|
2019-11-22 22:08:49 +03:00
|
|
|
ValueNPhi.Phi->setIncomingBlock(ValueNPhi.Index, NewBlock);
|
|
|
|
|
2019-11-22 23:46:33 +03:00
|
|
|
// Add instrumentation to the new block
|
2019-11-22 22:08:49 +03:00
|
|
|
std::uint32_t RegNum;
|
|
|
|
if (!pix_dxil::PixDxilReg::FromInst(ValueNPhi.Phi, &RegNum)) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
std::uint32_t InstNum;
|
|
|
|
if (!pix_dxil::PixDxilInstNum::FromInst(ValueNPhi.Phi, &InstNum)) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
BuilderContext BC{M, DM, Ctx, HlslOP, Builder};
|
|
|
|
addStepDebugEntryValue(BC, InstNum, ValueNPhi.Val, RegNum,
|
|
|
|
BC.Builder.getInt32(0));
|
|
|
|
}
|
|
|
|
|
2019-11-22 23:46:33 +03:00
|
|
|
// Add a branch to the new block to point to the current block
|
|
|
|
Builder.CreateBr(&CurrentBlock);
|
2019-11-22 22:08:49 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-10-10 01:30:29 +03:00
|
|
|
// Instrument original instructions:
|
2019-11-22 22:08:49 +03:00
|
|
|
for (auto &Inst : AllInstructions) {
|
|
|
|
// Instrumentation goes after the instruction if it is not a terminator.
|
|
|
|
// Otherwise, Instrumentation goes prior to the instruction.
|
2019-01-10 23:48:29 +03:00
|
|
|
if (!Inst->isTerminator()) {
|
2017-10-18 00:41:40 +03:00
|
|
|
IRBuilder<> Builder(Inst->getNextNode());
|
2019-11-22 22:08:49 +03:00
|
|
|
BuilderContext BC2{BC.M, BC.DM, BC.Ctx, BC.HlslOP, Builder};
|
2017-10-18 00:41:40 +03:00
|
|
|
addStepDebugEntry(BC2, Inst);
|
2019-11-22 22:08:49 +03:00
|
|
|
} else {
|
2017-10-18 00:41:40 +03:00
|
|
|
// Insert before this instruction
|
|
|
|
IRBuilder<> Builder(Inst);
|
2019-11-22 22:08:49 +03:00
|
|
|
BuilderContext BC2{BC.M, BC.DM, BC.Ctx, BC.HlslOP, Builder};
|
2017-10-18 00:41:40 +03:00
|
|
|
addStepDebugEntry(BC2, Inst);
|
2017-10-10 01:30:29 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
DM.ReEmitDxilResources();
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
char DxilDebugInstrumentation::ID = 0;
|
|
|
|
|
|
|
|
ModulePass *llvm::createDxilDebugInstrumentationPass() {
|
|
|
|
return new DxilDebugInstrumentation();
|
|
|
|
}
|
|
|
|
|
2019-11-22 22:08:49 +03:00
|
|
|
INITIALIZE_PASS(DxilDebugInstrumentation, "hlsl-dxil-debug-instrumentation",
|
|
|
|
"HLSL DXIL debug instrumentation for PIX", false, false)
|