Skip to content

Commit a031dc1

Browse files
jeffnnnopandbrkllvm-beanz
authored
PIX: CP NURI pass, multi-UAV bugfix (#7323)
Brings in these PRs: #7272 [PIX] Add a pass for PIX to log missing NonUniformResourceIndex usage into a UAV. #7238 [PIX: Check for existing PIX UAV in roots sigs before adding it again. --------- Co-authored-by: nopandbrk <[email protected]> Co-authored-by: Chris B <[email protected]>
1 parent 2399215 commit a031dc1

11 files changed

Lines changed: 552 additions & 95 deletions

File tree

CMakeLists.txt

Lines changed: 0 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -17,15 +17,6 @@ if(POLICY CMP0022)
1717
cmake_policy(SET CMP0022 NEW) # automatic when 2.8.12 is required
1818
endif()
1919

20-
if (POLICY CMP0051)
21-
# CMake 3.1 and higher include generator expressions of the form
22-
# $<TARGETLIB:obj> in the SOURCES property. These need to be
23-
# stripped everywhere that access the SOURCES property, so we just
24-
# defer to the OLD behavior of not including generator expressions
25-
# in the output for now.
26-
cmake_policy(SET CMP0051 OLD)
27-
endif()
28-
2920
if(CMAKE_VERSION VERSION_LESS 3.1.20141117)
3021
set(cmake_3_2_USES_TERMINAL)
3122
else()

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: 173 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,173 @@
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+
std::map<Function *, CallInst *> FunctionToUAVHandle;
61+
62+
// This is the main pass that will iterate through all of the resources that
63+
// are dynamically indexed. If not already marked NonUniformResourceIndex,
64+
// then insert WaveActiveAllEqual to determine if the index is uniform
65+
// and finally write to a UAV resource with the result.
66+
67+
PIXPassHelpers::ForEachDynamicallyIndexedResource(
68+
DM, [&](bool IsNonUniformIndex, Instruction *CreateHandle,
69+
Value *IndexOperand) {
70+
if (IsNonUniformIndex) {
71+
// The NonUniformResourceIndex qualifier was used, continue.
72+
return true;
73+
}
74+
75+
if (!PixUAVResource) {
76+
PixUAVResource =
77+
PIXPassHelpers::CreateGlobalUAVResource(DM, 0, "PixUAVResource");
78+
}
79+
80+
CallInst *PixUAVHandle = nullptr;
81+
Function *F = CreateHandle->getParent()->getParent();
82+
83+
const auto FunctionToUAVHandleIter = FunctionToUAVHandle.lower_bound(F);
84+
85+
if ((FunctionToUAVHandleIter != FunctionToUAVHandle.end()) &&
86+
(FunctionToUAVHandleIter->first == F)) {
87+
PixUAVHandle = FunctionToUAVHandleIter->second;
88+
} else {
89+
IRBuilder<> Builder(F->getEntryBlock().getFirstInsertionPt());
90+
91+
PixUAVHandle = PIXPassHelpers::CreateHandleForResource(
92+
DM, Builder, PixUAVResource, "PixUAVHandle");
93+
94+
FunctionToUAVHandle.insert(FunctionToUAVHandleIter,
95+
{F, PixUAVHandle});
96+
}
97+
98+
IRBuilder<> Builder(CreateHandle);
99+
100+
uint32_t InstructionNumber = 0;
101+
if (!pix_dxil::PixDxilInstNum::FromInst(CreateHandle,
102+
&InstructionNumber)) {
103+
DXASSERT_NOMSG(false);
104+
}
105+
106+
// The output UAV is treated as a bit array where each bit corresponds
107+
// to an instruction number. This determines what byte offset to write
108+
// our result to based on the instruction number.
109+
const uint32_t InstructionNumByteOffset =
110+
(InstructionNumber / 32u) * sizeof(uint32_t);
111+
const uint32_t InstructionNumBitPosition = (InstructionNumber % 32u);
112+
const uint32_t InstructionNumBitMask = 1u << InstructionNumBitPosition;
113+
114+
Constant *UAVByteOffsetArg =
115+
HlslOP->GetU32Const(InstructionNumByteOffset);
116+
117+
CallInst *WaveActiveAllEqualCall = Builder.CreateCall(
118+
WaveActiveAllEqualFunc, {WaveActiveAllEqualOpCode, IndexOperand});
119+
120+
// This takes the result of the WaveActiveAllEqual result and shifts
121+
// it into the same bit position as the instruction number, followed
122+
// by an xor to determine what to write to the UAV
123+
Value *IsWaveEqual =
124+
Builder.CreateZExt(WaveActiveAllEqualCall, Builder.getInt32Ty());
125+
Value *WaveEqualBitMask =
126+
Builder.CreateShl(IsWaveEqual, InstructionNumBitPosition);
127+
Value *FinalResult =
128+
Builder.CreateXor(WaveEqualBitMask, InstructionNumBitMask);
129+
130+
// Generate instructions to bitwise OR a UAV value corresponding
131+
// to the instruction number and result of WaveActiveAllEqual.
132+
// If WaveActiveAllEqual was false, we write a 1, otherwise a 0.
133+
Builder.CreateCall(
134+
AtomicOpFunc,
135+
{
136+
AtomicBinOpcode, // i32, ; opcode
137+
PixUAVHandle, // %dx.types.Handle, ; resource handle
138+
AtomicOr, // i32, ; binary operation code :
139+
// EXCHANGE, IADD, AND, OR, XOR
140+
// IMIN, IMAX, UMIN, UMAX
141+
UAVByteOffsetArg, // i32, ; coordinate c0: byte offset
142+
UndefArg, // i32, ; coordinate c1 (unused)
143+
UndefArg, // i32, ; coordinate c2 (unused)
144+
FinalResult // i32); value
145+
},
146+
"UAVInstructionNumberBitSet");
147+
return true;
148+
});
149+
150+
const bool modified = (PixUAVResource != nullptr);
151+
152+
if (modified) {
153+
DM.ReEmitDxilResources();
154+
155+
if (OSOverride != nullptr) {
156+
formatted_raw_ostream FOS(*OSOverride);
157+
FOS << "\nFoundDynamicIndexingNoNuri\n";
158+
}
159+
}
160+
161+
return modified;
162+
}
163+
164+
char DxilNonUniformResourceIndexInstrumentation::ID = 0;
165+
166+
ModulePass *llvm::createDxilNonUniformResourceIndexInstrumentationPass() {
167+
return new DxilNonUniformResourceIndexInstrumentation();
168+
}
169+
170+
INITIALIZE_PASS(DxilNonUniformResourceIndexInstrumentation,
171+
"hlsl-dxil-non-uniform-resource-index-instrumentation",
172+
"HLSL DXIL NonUniformResourceIndex instrumentation for PIX",
173+
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) {

0 commit comments

Comments
 (0)