1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236
|
/*========================== begin_copyright_notice ============================
Copyright (C) 2021 Intel Corporation
SPDX-License-Identifier: MIT
============================= end_copyright_notice ===========================*/
//===----------------------------------------------------------------------===//
///
/// This pass schedules latency of rayquery.Proceed() by moving SyncStackToShadowMemory instructions
/// to as far away as possible from TraceRaySyncProceed.
/// Note: any BB w/ suspendPoint is split first into <B3.0,B3.1>, <B7.0,B7.1> like below, where B3.1 and B7.1 holds suspendPoint.
/// Given CFG & DT like below. PTD is opposite of DT.
/// CFG DT
/// B0 B0
/// / \ / | \
/// B10 B11 B10 B3.0 B11
/// | | | |
/// B20 | B20 B3.1
/// \ / / | \
/// B3.0 B40 B7.0 B41
/// | | / | \
/// B3.1 B7.1 B51 B6 B52
/// / \
/// B40 B41
/// | | \
/// | B51 B52
/// | | /
/// | | /
/// | B6
/// \ /
/// B7.0
/// |
/// B7.1
/// Assume B0 has SyncStackToShadowMemory(). Note: q.Proceed() is in an upstream BB instead of B0.
/// The only possible candidates are: B0, B3.#, B7.#, which means,
/// we need to find the candidate node (CNode):
/// 1) DT&PTD with B0
/// 2) No suspendPoint between B0 and CNode.
/// Finally, we pick farthestBB among all candidate nodes.
/// Implementation wise, we only need to traverse all CNodes in DT (no other nodes) because
/// each CNode must be immediate DT&PDT to one of the other ones. No need to BFS whole DT!
/// Example Cases:
/// Case 1) If any node (B10,B11 or B20) between B0 and B3.0 has suspendPoint, then farthestBB is B0.
/// Case 2) If B3.1 has suspendPoint, then farthestBB is B3.0.
/// Case 3) If any node between B3.1 and B7.0 has suspendPoint, then farthestBB is B3.1.
/// Case 4) If B7.1 has suspendPoint, then farthestBB is B7.0.
/// Further Note: It doesn't matter if B0 itself is on a branch
/// because the branch itself is the subsystem we are working on then and B0 is still the srcBB.
/// If below happens, then, farthestBB will be B0 because B0 has no children in DT tree.
/// B0 |
/// \ /
/// B1
//===----------------------------------------------------------------------===//
#include "IGC/common/StringMacros.hpp"
#include "CrossingAnalysis.h"
#include "SplitAsyncUtils.h"
#include "RTBuilder.h"
#include "RTStackFormat.h"
#include "Compiler/IGCPassSupport.h"
#include "Compiler/CodeGenPublicEnums.h"
#include "common/LLVMWarningsPush.hpp"
#include "llvmWrapper/Support/Alignment.h"
#include <llvm/IR/InstIterator.h>
#include <llvm/IR/Dominators.h>
#include <llvm/Analysis/LoopInfo.h>
#include <llvm/Analysis/PostDominators.h>
#include <llvm/Support/MathExtras.h>
#include <llvm/Transforms/Utils/BasicBlockUtils.h>
#include "llvmWrapper/Transforms/Utils/LoopUtils.h"
#include "common/LLVMWarningsPop.hpp"
using namespace std;
using namespace llvm;
using namespace IGC;
using namespace RTStackFormat;
class TraceRayInlineLatencySchedulerPass : public FunctionPass
{
public:
TraceRayInlineLatencySchedulerPass(): FunctionPass(ID)
{
initializeTraceRayInlineLatencySchedulerPassPass(*PassRegistry::getPassRegistry());
}
void getAnalysisUsage(llvm::AnalysisUsage &AU) const override
{
AU.addRequired<CodeGenContextWrapper>();
}
bool runOnFunction(Function &F) override;
StringRef getPassName() const override
{
return "TraceRayInlineLatencySchedulerPass";
}
static char ID;
private:
void split(RayQuerySyncStackToShadowMemory* Stk2SM, vector<Instruction*>& SPIs);
void schedule(RayQuerySyncStackToShadowMemory* Stk2SM, vector<Instruction*>& SPIs);
BasicBlock* findFarthestSafeBB(Instruction* src, SuspendCrossingInfo& checker);
};
char TraceRayInlineLatencySchedulerPass::ID = 0;
#define PASS_FLAG2 "tracerayinline-latency-scheduler-pass"
#define PASS_DESCRIPTION2 "schedule tracerayinline latency"
#define PASS_CFG_ONLY2 false
#define PASS_ANALYSIS2 false
IGC_INITIALIZE_PASS_BEGIN(TraceRayInlineLatencySchedulerPass, PASS_FLAG2, PASS_DESCRIPTION2, PASS_CFG_ONLY2, PASS_ANALYSIS2)
IGC_INITIALIZE_PASS_DEPENDENCY(CodeGenContextWrapper)
IGC_INITIALIZE_PASS_END(TraceRayInlineLatencySchedulerPass, PASS_FLAG2, PASS_DESCRIPTION2, PASS_CFG_ONLY2, PASS_ANALYSIS2)
bool TraceRayInlineLatencySchedulerPass::runOnFunction(Function &F)
{
SmallVector<RayQuerySyncStackToShadowMemory*, 4> Stk2SMs;
for (auto& I : instructions(F))
{
if (auto* stk2SM = dyn_cast<RayQuerySyncStackToShadowMemory>(&I))
Stk2SMs.push_back(stk2SM);
}
unordered_map<RayQuerySyncStackToShadowMemory*, vector<Instruction*>> SPIs;
for (auto& Stk2SM : Stk2SMs) {
split(Stk2SM, SPIs[Stk2SM]);
}
for (auto& Stk2SM : Stk2SMs) {
schedule(Stk2SM, SPIs[Stk2SM]);
}
return true;
}
void TraceRayInlineLatencySchedulerPass::split(RayQuerySyncStackToShadowMemory* Stk2SM, vector<Instruction*>& SPIs) {
Function& F = *Stk2SM->getParent()->getParent();
//to be conservative, we only return false when two constant arguments are not equal.
auto mayAlias = [](Value* objIdx1, Value* objIdx2) {
ConstantInt* CIdx1 = dyn_cast<ConstantInt>(objIdx1);
ConstantInt* CIdx2 = dyn_cast<ConstantInt>(objIdx2);
if (CIdx1 && CIdx2) {
uint32_t idx1 = static_cast<uint32_t>(CIdx1->getZExtValue());
uint32_t idx2 = static_cast<uint32_t>(CIdx1->getZExtValue());
return (idx1 == idx2);
}
return true;
};
auto isSuspendPoint = [&](Instruction* inst) {
//RayQuery Instructions
if (auto* RQI = dyn_cast<RayQueryInstrisicBase>(inst)) {
return (RQI->getIntrinsicID() != GenISAIntrinsic::GenISA_SyncStackToShadowMemory &&
(RQI->getIntrinsicID() == GenISAIntrinsic::GenISA_TraceRaySyncProceed || mayAlias(RQI->getQueryObjIndex(), Stk2SM->getQueryObjIndex())));
}else if (auto* GI = dyn_cast<GenIntrinsicInst>(inst)){
//The last two asyncRT intrinsics, IgnoreHit() and AcceptHitAndEndSearch(), are not suspendpoints
//because they will cause shader to end immediately (instead of let shader to continue to end)
return (isa<ContinuationHLIntrinsic>(GI) ||
isa <TraceRayIntrinsic>(GI) ||
isa <ReportHitHLIntrinsic>(GI));
}else if (isa<CallInst>(inst) && !isa<IntrinsicInst>(inst)) {
//We are conservative here because non-intrinsic function might call SuspendPoint instructions.
return true;
}
return false;
};
for (auto& I : instructions(F)) {
if (isSuspendPoint(&I)){
SPIs.push_back(&I);
}
}
for (auto* user : Stk2SM->users()) {
if (Instruction* inst = dyn_cast<Instruction>(user))
SPIs.push_back(inst);
}
if (SPIs.empty())
return;
for (auto* SPI : SPIs) {
splitAround(SPI, VALUE_NAME("Cont"));
}
rewritePHIs(F);
}
void TraceRayInlineLatencySchedulerPass::schedule(RayQuerySyncStackToShadowMemory* Stk2SM, vector<Instruction*>& SPIs) {
Function& F = *Stk2SM->getParent()->getParent();
SuspendCrossingInfo checker(F, SPIs);
BasicBlock* tgt = findFarthestSafeBB(Stk2SM, checker);
Stk2SM->moveBefore(tgt->getTerminator());
}
//This function finds the farthest "safe" BB away from src BB.
//"safe" here means src can be safely moved to this BB.
//Note that "distance" here is not accurate because we use DT instead of CFG to traverse
BasicBlock* TraceRayInlineLatencySchedulerPass::findFarthestSafeBB(Instruction* src,
SuspendCrossingInfo& checker)
{
BasicBlock* srcBB = src->getParent();
PostDominatorTree PDT(*srcBB->getParent());
DominatorTree DT(*srcBB->getParent());
BasicBlock* farthestBB = srcBB;
DomTreeNodeBase<BasicBlock>* cNode = DT.getNode(srcBB);
while (cNode) {
DomTreeNodeBase<BasicBlock>* newCNode = nullptr;
// TODO: change to node->children() once we move to llvm11
for (auto nodeV = cNode->begin(); nodeV != cNode->end(); nodeV++) {
auto* BBV = (*nodeV)->getBlock();
if (PDT.dominates(BBV, srcBB) &&
!checker.hasPathCrossingSuspendPoint(srcBB, BBV)) {
newCNode = *nodeV;
farthestBB = BBV;
break;
}
}
cNode = newCNode;
}
return farthestBB;
}
namespace IGC
{
Pass* createTraceRayInlineLatencySchedulerPass(void)
{
return new TraceRayInlineLatencySchedulerPass();
}
} // namespace IGC
|