Skip to content

Commit 5176013

Browse files
author
nopandbrk
committed
Implementation for nonuniformresourceindex pix pass
1 parent 4d3a2f5 commit 5176013

8 files changed

Lines changed: 484 additions & 83 deletions

File tree

include/dxc/DxilPIXPasses/DxilPIXPasses.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ ModulePass *createDxilDebugInstrumentationPass();
2727
ModulePass *createDxilShaderAccessTrackingPass();
2828
ModulePass *createDxilPIXAddTidToAmplificationShaderPayloadPass();
2929
ModulePass *createDxilPIXDXRInvocationsLogPass();
30+
ModulePass *createDxilNonUniformResourceIndexInstrumentationPass();
3031

3132
void initializeDxilAddPixelHitInstrumentationPass(llvm::PassRegistry &);
3233
void initializeDxilDbgValueToDbgDeclarePass(llvm::PassRegistry &);
@@ -41,5 +42,7 @@ void initializeDxilShaderAccessTrackingPass(llvm::PassRegistry &);
4142
void initializeDxilPIXAddTidToAmplificationShaderPayloadPass(
4243
llvm::PassRegistry &);
4344
void initializeDxilPIXDXRInvocationsLogPass(llvm::PassRegistry &);
45+
void initializeDxilNonUniformResourceIndexInstrumentationPass(
46+
llvm::PassRegistry &);
4447

4548
} // namespace llvm

lib/DxilPIXPasses/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ add_llvm_library(LLVMDxilPIXPasses
2020
PixPassHelpers.cpp
2121
DxilPIXAddTidToAmplificationShaderPayload.cpp
2222
DxilPIXDXRInvocationsLog.cpp
23+
DxilNonUniformResourceIndexInstrumentation.cpp
2324

2425
ADDITIONAL_HEADER_DIRS
2526
${LLVM_MAIN_INCLUDE_DIR}/llvm/IR
Lines changed: 156 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,156 @@
1+
///////////////////////////////////////////////////////////////////////////////
2+
// //
3+
// DxilNonUniformResourceIndexInstrumentation.cpp //
4+
// Copyright (C) Microsoft Corporation. All rights reserved. //
5+
// This file is distributed under the University of Illinois Open Source //
6+
// License. See LICENSE.TXT for details. //
7+
// //
8+
// Provides a pass to add instrumentation to determine missing usage of the //
9+
// NonUniformResourceIndex qualifier when dynamically indexing resources. //
10+
// Used by PIX. //
11+
// //
12+
///////////////////////////////////////////////////////////////////////////////
13+
14+
#include "PixPassHelpers.h"
15+
#include "dxc/DXIL/DxilInstructions.h"
16+
#include "dxc/DxilPIXPasses/DxilPIXPasses.h"
17+
#include "dxc/DxilPIXPasses/DxilPIXVirtualRegisters.h"
18+
#include "dxc/Support/Global.h"
19+
#include "llvm/IR/Module.h"
20+
#include "llvm/Support/FormattedStream.h"
21+
22+
using namespace llvm;
23+
using namespace hlsl;
24+
25+
class DxilNonUniformResourceIndexInstrumentation : public ModulePass {
26+
27+
public:
28+
static char ID; // Pass identification, replacement for typeid
29+
explicit DxilNonUniformResourceIndexInstrumentation() : ModulePass(ID) {}
30+
StringRef getPassName() const override {
31+
return "DXIL NonUniformResourceIndex Instrumentation";
32+
}
33+
bool runOnModule(Module &M) override;
34+
};
35+
36+
bool DxilNonUniformResourceIndexInstrumentation::runOnModule(Module &M) {
37+
// This pass adds instrumentation for incorrect NonUniformResourceIndex usage
38+
39+
DxilModule &DM = M.GetOrCreateDxilModule();
40+
LLVMContext &Ctx = M.getContext();
41+
OP *HlslOP = DM.GetOP();
42+
43+
hlsl::DxilResource *PixUavResource = nullptr;
44+
45+
UndefValue *UndefArg = UndefValue::get(Type::getInt32Ty(Ctx));
46+
47+
// Use WaveActiveAllEqual to check if a dynamic index is uniform
48+
Function *WaveActiveAllEqualFunc = HlslOP->GetOpFunc(
49+
DXIL::OpCode::WaveActiveAllEqual, Type::getInt32Ty(Ctx));
50+
Constant *WaveActiveAllEqualOpCode =
51+
HlslOP->GetI32Const((int32_t)DXIL::OpCode::WaveActiveAllEqual);
52+
53+
// Atomic operation to use for writing to the result uav resource
54+
Function *AtomicOpFunc =
55+
HlslOP->GetOpFunc(OP::OpCode::AtomicBinOp, Type::getInt32Ty(Ctx));
56+
Constant *AtomicBinOpcode =
57+
HlslOP->GetU32Const((uint32_t)OP::OpCode::AtomicBinOp);
58+
Constant *AtomicOr = HlslOP->GetU32Const((uint32_t)DXIL::AtomicBinOpCode::Or);
59+
60+
// This is the main pass that will iterate through all of the resources that
61+
// are dynamically indexed. If not already marked NonUniformResourceIndex,
62+
// then insert WaveActiveAllEqual to determine if the index is uniform
63+
// and finally write to a UAV resource with the result.
64+
65+
PIXPassHelpers::ForEachDynamicallyIndexedResource(
66+
DM, [&](bool IsNonUniformIndex, Instruction *CreateHandle,
67+
Value *IndexOperand) {
68+
if (IsNonUniformIndex) {
69+
// The NonUniformResourceIndex qualifier was used, continue.
70+
return true;
71+
}
72+
73+
if (!PixUavResource) {
74+
PixUavResource =
75+
PIXPassHelpers::CreateGlobalUAVResource(DM, 0, "PixUavResource");
76+
}
77+
78+
IRBuilder<> Builder(CreateHandle);
79+
80+
CallInst *HandleForUAV = PIXPassHelpers::CreateHandleForResource(
81+
DM, Builder, PixUavResource, "PixUavHandle");
82+
83+
uint32_t InstructionNumber = 0;
84+
if (!pix_dxil::PixDxilInstNum::FromInst(CreateHandle,
85+
&InstructionNumber)) {
86+
DXASSERT_NOMSG(false);
87+
}
88+
89+
// The output UAV is treated as a bit array where each bit corresponds
90+
// to an instruction number. This determines what byte offset to write
91+
// our result to based on the instruction number.
92+
const uint32_t InstructionNumByteOffset =
93+
(InstructionNumber / 32u) * sizeof(uint32_t);
94+
const uint32_t InstructionNumBitPosition = (InstructionNumber % 32u);
95+
const uint32_t InstructionNumBitMask = 1u << InstructionNumBitPosition;
96+
97+
Constant *UAVByteOffsetArg =
98+
HlslOP->GetU32Const(InstructionNumByteOffset);
99+
100+
CallInst *WaveActiveAllEqualCall = Builder.CreateCall(
101+
WaveActiveAllEqualFunc, {WaveActiveAllEqualOpCode, IndexOperand});
102+
103+
// This takes the result of the WaveActiveAllEqual result and shifts
104+
// it into the same bit position as the instruction number, followed
105+
// by an xor to determine what to write to the UAV
106+
Value *IsWaveEqual =
107+
Builder.CreateZExt(WaveActiveAllEqualCall, Builder.getInt32Ty());
108+
Value *WaveEqualBitMask =
109+
Builder.CreateShl(IsWaveEqual, InstructionNumBitPosition);
110+
Value *FinalResult =
111+
Builder.CreateXor(WaveEqualBitMask, InstructionNumBitMask);
112+
113+
// Generate instructions to bitwise OR a UAV value corresponding
114+
// to the instruction number and result of WaveActiveAllEqual.
115+
// If WaveActiveAllEqual was false, we write a 1, otherwise a 0.
116+
Builder.CreateCall(
117+
AtomicOpFunc,
118+
{
119+
AtomicBinOpcode, // i32, ; opcode
120+
HandleForUAV, // %dx.types.Handle, ; resource handle
121+
AtomicOr, // i32, ; binary operation code :
122+
// EXCHANGE, IADD, AND, OR, XOR
123+
// IMIN, IMAX, UMIN, UMAX
124+
UAVByteOffsetArg, // i32, ; coordinate c0: byte offset
125+
UndefArg, // i32, ; coordinate c1 (unused)
126+
UndefArg, // i32, ; coordinate c2 (unused)
127+
FinalResult // i32); value
128+
},
129+
"UAVInstructionNumberBitSet");
130+
return true;
131+
});
132+
133+
const bool modified = (PixUavResource != nullptr);
134+
135+
if (modified) {
136+
DM.ReEmitDxilResources();
137+
138+
if (OSOverride != nullptr) {
139+
formatted_raw_ostream FOS(*OSOverride);
140+
FOS << "FoundDynamicIndexingNoNuri";
141+
}
142+
}
143+
144+
return modified;
145+
}
146+
147+
char DxilNonUniformResourceIndexInstrumentation::ID = 0;
148+
149+
ModulePass *llvm::createDxilNonUniformResourceIndexInstrumentationPass() {
150+
return new DxilNonUniformResourceIndexInstrumentation();
151+
}
152+
153+
INITIALIZE_PASS(DxilNonUniformResourceIndexInstrumentation,
154+
"hlsl-dxil-non-uniform-resource-index-instrumentation",
155+
"HLSL DXIL NonUniformResourceIndex instrumentation for PIX",
156+
false, false)

lib/DxilPIXPasses/DxilShaderAccessTracking.cpp

Lines changed: 7 additions & 82 deletions
Original file line numberDiff line numberDiff line change
@@ -795,87 +795,6 @@ DxilShaderAccessTracking::GetResourceFromHandle(Value *resHandle,
795795
return ret;
796796
}
797797

798-
static bool CheckForDynamicIndexing(OP *HlslOP, LLVMContext &Ctx,
799-
DxilModule &DM) {
800-
bool FoundDynamicIndexing = false;
801-
802-
for (llvm::Function &F : DM.GetModule()->functions()) {
803-
if (F.isDeclaration() && !F.use_empty() && OP::IsDxilOpFunc(&F)) {
804-
if (F.hasName()) {
805-
if (F.getName().find("createHandleForLib") != StringRef::npos) {
806-
auto FunctionUses = F.uses();
807-
for (auto FI = FunctionUses.begin(); FI != FunctionUses.end();) {
808-
auto &FunctionUse = *FI++;
809-
auto FunctionUser = FunctionUse.getUser();
810-
auto instruction = cast<Instruction>(FunctionUser);
811-
Value *resourceLoad =
812-
instruction->getOperand(kCreateHandleForLibResOpIdx);
813-
if (auto *load = cast<LoadInst>(resourceLoad)) {
814-
auto *resOrGep = load->getOperand(0);
815-
if (isa<GetElementPtrInst>(resOrGep)) {
816-
FoundDynamicIndexing = true;
817-
break;
818-
}
819-
}
820-
}
821-
}
822-
}
823-
}
824-
if (FoundDynamicIndexing) {
825-
break;
826-
}
827-
}
828-
829-
if (!FoundDynamicIndexing) {
830-
auto CreateHandleFn =
831-
HlslOP->GetOpFunc(DXIL::OpCode::CreateHandle, Type::getVoidTy(Ctx));
832-
for (auto FI = CreateHandleFn->user_begin();
833-
FI != CreateHandleFn->user_end();) {
834-
auto *FunctionUser = *FI++;
835-
auto instruction = cast<Instruction>(FunctionUser);
836-
Value *index = instruction->getOperand(kCreateHandleResIndexOpIdx);
837-
if (!isa<Constant>(index)) {
838-
FoundDynamicIndexing = true;
839-
break;
840-
}
841-
}
842-
}
843-
844-
if (!FoundDynamicIndexing) {
845-
auto CreateHandleFromBindingFn = HlslOP->GetOpFunc(
846-
DXIL::OpCode::CreateHandleFromBinding, Type::getVoidTy(Ctx));
847-
for (auto FI = CreateHandleFromBindingFn->user_begin();
848-
FI != CreateHandleFromBindingFn->user_end();) {
849-
auto *FunctionUser = *FI++;
850-
auto instruction = cast<Instruction>(FunctionUser);
851-
Value *index =
852-
instruction->getOperand(kCreateHandleFromBindingResIndexOpIdx);
853-
if (!isa<Constant>(index)) {
854-
FoundDynamicIndexing = true;
855-
break;
856-
}
857-
}
858-
}
859-
860-
if (!FoundDynamicIndexing) {
861-
auto CreateHandleFromHeapFn = HlslOP->GetOpFunc(
862-
DXIL::OpCode::CreateHandleFromHeap, Type::getVoidTy(Ctx));
863-
for (auto FI = CreateHandleFromHeapFn->user_begin();
864-
FI != CreateHandleFromHeapFn->user_end();) {
865-
auto *FunctionUser = *FI++;
866-
auto instruction = cast<Instruction>(FunctionUser);
867-
Value *index =
868-
instruction->getOperand(kCreateHandleFromHeapHeapIndexOpIdx);
869-
if (!isa<Constant>(index)) {
870-
FoundDynamicIndexing = true;
871-
break;
872-
}
873-
}
874-
}
875-
876-
return FoundDynamicIndexing;
877-
}
878-
879798
bool DxilShaderAccessTracking::runOnModule(Module &M) {
880799
// This pass adds instrumentation for shader access to resources
881800

@@ -887,7 +806,13 @@ bool DxilShaderAccessTracking::runOnModule(Module &M) {
887806

888807
if (m_CheckForDynamicIndexing) {
889808

890-
bool FoundDynamicIndexing = CheckForDynamicIndexing(HlslOP, Ctx, DM);
809+
bool FoundDynamicIndexing = false;
810+
811+
PIXPassHelpers::ForEachDynamicallyIndexedResource(
812+
DM, [&FoundDynamicIndexing](bool, Instruction *, Value *) {
813+
FoundDynamicIndexing = true;
814+
return false;
815+
});
891816

892817
if (FoundDynamicIndexing) {
893818
if (OSOverride != nullptr) {

lib/DxilPIXPasses/PixPassHelpers.cpp

Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -500,6 +500,90 @@ unsigned int FindOrAddSV_Position(hlsl::DxilModule &DM,
500500
}
501501
}
502502

503+
void ForEachDynamicallyIndexedResource(
504+
hlsl::DxilModule &DM,
505+
const std::function<bool(bool, Instruction *, Value *)> &Visitor) {
506+
OP *HlslOP = DM.GetOP();
507+
LLVMContext &Ctx = DM.GetModule()->getContext();
508+
509+
for (llvm::Function &F : DM.GetModule()->functions()) {
510+
if (F.isDeclaration() && !F.use_empty() && OP::IsDxilOpFunc(&F)) {
511+
if (F.hasName()) {
512+
if (F.getName().find("createHandleForLib") != StringRef::npos) {
513+
auto FunctionUses = F.uses();
514+
for (auto FI = FunctionUses.begin(); FI != FunctionUses.end();) {
515+
auto &FunctionUse = *FI++;
516+
auto FunctionUser = FunctionUse.getUser();
517+
auto instruction = cast<Instruction>(FunctionUser);
518+
Value *resourceLoad = instruction->getOperand(
519+
DXIL::OperandIndex::kCreateHandleForLibResOpIdx);
520+
if (auto *load = cast<LoadInst>(resourceLoad)) {
521+
auto *resOrGep = load->getOperand(0);
522+
if (auto *gep = dyn_cast<GetElementPtrInst>(resOrGep)) {
523+
if (!Visitor(DxilMDHelper::IsMarkedNonUniform(gep), load,
524+
gep->getOperand(2))) {
525+
return;
526+
}
527+
}
528+
}
529+
}
530+
}
531+
}
532+
}
533+
}
534+
535+
auto CreateHandleFn =
536+
HlslOP->GetOpFunc(DXIL::OpCode::CreateHandle, Type::getVoidTy(Ctx));
537+
for (auto FI = CreateHandleFn->user_begin();
538+
FI != CreateHandleFn->user_end();) {
539+
auto *FunctionUser = *FI++;
540+
auto instruction = cast<Instruction>(FunctionUser);
541+
Value *index =
542+
instruction->getOperand(DXIL::OperandIndex::kCreateHandleResIndexOpIdx);
543+
if (!isa<Constant>(index)) {
544+
const DxilInst_CreateHandle createHandle(instruction);
545+
if (!Visitor(createHandle.get_nonUniformIndex_val(), instruction,
546+
index)) {
547+
return;
548+
}
549+
}
550+
}
551+
552+
auto CreateHandleFromBindingFn = HlslOP->GetOpFunc(
553+
DXIL::OpCode::CreateHandleFromBinding, Type::getVoidTy(Ctx));
554+
for (auto FI = CreateHandleFromBindingFn->user_begin();
555+
FI != CreateHandleFromBindingFn->user_end();) {
556+
auto *FunctionUser = *FI++;
557+
auto instruction = cast<Instruction>(FunctionUser);
558+
Value *index = instruction->getOperand(
559+
DXIL::OperandIndex::kCreateHandleFromBindingResIndexOpIdx);
560+
if (!isa<Constant>(index)) {
561+
const DxilInst_CreateHandleFromBinding createHandle(instruction);
562+
if (!Visitor(createHandle.get_nonUniformIndex_val(), instruction,
563+
index)) {
564+
return;
565+
}
566+
}
567+
}
568+
569+
auto CreateHandleFromHeapFn = HlslOP->GetOpFunc(
570+
DXIL::OpCode::CreateHandleFromHeap, Type::getVoidTy(Ctx));
571+
for (auto FI = CreateHandleFromHeapFn->user_begin();
572+
FI != CreateHandleFromHeapFn->user_end();) {
573+
auto *FunctionUser = *FI++;
574+
auto instruction = cast<Instruction>(FunctionUser);
575+
Value *index = instruction->getOperand(
576+
DXIL::OperandIndex::kCreateHandleFromHeapHeapIndexOpIdx);
577+
if (!isa<Constant>(index)) {
578+
const DxilInst_CreateHandleFromHeap createHandle(instruction);
579+
if (!Visitor(createHandle.get_nonUniformIndex_val(), instruction,
580+
index)) {
581+
return;
582+
}
583+
}
584+
}
585+
}
586+
503587
#ifdef PIX_DEBUG_DUMP_HELPER
504588

505589
static int g_logIndent = 0;

0 commit comments

Comments
 (0)