ComputeViewIdState.cpp 42 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039
  1. ///////////////////////////////////////////////////////////////////////////////
  2. // //
  3. // ViewIdAnalysis.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. ///////////////////////////////////////////////////////////////////////////////
  9. #include "dxc/HLSL/ComputeViewIdState.h"
  10. #include "dxc/Support/Global.h"
  11. #include "dxc/HLSL/DxilModule.h"
  12. #include "dxc/HLSL/DxilOperations.h"
  13. #include "dxc/HLSL/DxilInstructions.h"
  14. #include "llvm/IR/LLVMContext.h"
  15. #include "llvm/IR/Module.h"
  16. #include "llvm/IR/Function.h"
  17. #include "llvm/IR/Operator.h"
  18. #include "llvm/Pass.h"
  19. #include "llvm/IR/LegacyPassManager.h"
  20. #include "llvm/Support/Debug.h"
  21. #include "llvm/IR/CFG.h"
  22. #include "llvm/Analysis/CallGraph.h"
  23. #include <algorithm>
  24. using namespace llvm;
  25. using namespace llvm::legacy;
  26. using namespace hlsl;
  27. using llvm::legacy::PassManager;
  28. using llvm::legacy::FunctionPassManager;
  29. using std::vector;
  30. using std::unordered_set;
  31. using std::unordered_map;
  32. #define DXILVIEWID_DBG 0
  33. #define DEBUG_TYPE "viewid"
  34. DxilViewIdState::DxilViewIdState(DxilModule *pDxilModule) : m_pModule(pDxilModule) {}
  35. unsigned DxilViewIdState::getNumInputSigScalars() const { return m_NumInputSigScalars; }
  36. unsigned DxilViewIdState::getNumOutputSigScalars(unsigned StreamId) const { return m_NumOutputSigScalars[StreamId]; }
  37. unsigned DxilViewIdState::getNumPCSigScalars() const { return m_NumPCSigScalars; }
  38. const DxilViewIdState::OutputsDependentOnViewIdType &DxilViewIdState::getOutputsDependentOnViewId(unsigned StreamId) const { return m_OutputsDependentOnViewId[StreamId]; }
  39. const DxilViewIdState::OutputsDependentOnViewIdType &DxilViewIdState::getPCOutputsDependentOnViewId() const { return m_PCOutputsDependentOnViewId; }
  40. const DxilViewIdState::InputsContributingToOutputType &DxilViewIdState::getInputsContributingToOutputs(unsigned StreamId) const { return m_InputsContributingToOutputs[StreamId]; }
  41. const DxilViewIdState::InputsContributingToOutputType &DxilViewIdState::getInputsContributingToPCOutputs() const { return m_InputsContributingToPCOutputs; }
  42. const DxilViewIdState::InputsContributingToOutputType &DxilViewIdState::getPCInputsContributingToOutputs() const { return m_PCInputsContributingToOutputs; }
  43. void DxilViewIdState::Compute() {
  44. Clear();
  45. const ShaderModel *pSM = m_pModule->GetShaderModel();
  46. m_bUsesViewId = m_pModule->m_ShaderFlags.GetViewID();
  47. // 1. Traverse signature MD to determine max packed location.
  48. DetermineMaxPackedLocation(m_pModule->GetInputSignature(), &m_NumInputSigScalars, 1);
  49. DetermineMaxPackedLocation(m_pModule->GetOutputSignature(), &m_NumOutputSigScalars[0], pSM->IsGS() ? kNumStreams : 1);
  50. DetermineMaxPackedLocation(m_pModule->GetPatchConstantSignature(), &m_NumPCSigScalars, 1);
  51. // 2. Collect sets of functions reachable from main and pc entries.
  52. CallGraphAnalysis CGA;
  53. CallGraph CG = CGA.run(m_pModule->GetModule());
  54. m_Entry.pEntryFunc = m_pModule->GetEntryFunction();
  55. m_PCEntry.pEntryFunc = m_pModule->GetPatchConstantFunction();
  56. ComputeReachableFunctionsRec(CG, CG[m_Entry.pEntryFunc], m_Entry.Functions);
  57. if (m_PCEntry.pEntryFunc) {
  58. DXASSERT_NOMSG(pSM->IsHS());
  59. ComputeReachableFunctionsRec(CG, CG[m_PCEntry.pEntryFunc], m_PCEntry.Functions);
  60. }
  61. // 3. Determine shape components that are dynamically accesses and collect all sig outputs.
  62. AnalyzeFunctions(m_Entry);
  63. if (m_PCEntry.pEntryFunc) {
  64. AnalyzeFunctions(m_PCEntry);
  65. }
  66. // 4. Collect sets of values contributing to outputs.
  67. CollectValuesContributingToOutputs(m_Entry);
  68. if (m_PCEntry.pEntryFunc) {
  69. CollectValuesContributingToOutputs(m_PCEntry);
  70. }
  71. // 5. Construct dependency sets.
  72. for (unsigned StreamId = 0; StreamId < (pSM->IsGS() ? kNumStreams : 1u); StreamId++) {
  73. CreateViewIdSets(m_Entry.ContributingInstructions[StreamId],
  74. m_OutputsDependentOnViewId[StreamId],
  75. m_InputsContributingToOutputs[StreamId], false);
  76. }
  77. if (pSM->IsHS()) {
  78. CreateViewIdSets(m_PCEntry.ContributingInstructions[0],
  79. m_PCOutputsDependentOnViewId,
  80. m_InputsContributingToPCOutputs, true);
  81. } else if (pSM->IsDS()) {
  82. OutputsDependentOnViewIdType OutputsDependentOnViewId;
  83. CreateViewIdSets(m_Entry.ContributingInstructions[0],
  84. OutputsDependentOnViewId,
  85. m_PCInputsContributingToOutputs, true);
  86. DXASSERT_NOMSG(OutputsDependentOnViewId == m_OutputsDependentOnViewId[0]);
  87. }
  88. // 6. Update dynamically indexed input/output component masks.
  89. UpdateDynamicIndexUsageState();
  90. #if DXILVIEWID_DBG
  91. PrintSets(dbgs());
  92. #endif
  93. }
  94. void DxilViewIdState::PrintSets(llvm::raw_ostream &OS) {
  95. const ShaderModel *pSM = m_pModule->GetShaderModel();
  96. OS << "ViewId state: \n";
  97. if (!pSM->IsGS()) {
  98. OS << "Number of inputs: " << m_NumInputSigScalars <<
  99. ", outputs: " << m_NumOutputSigScalars[0] <<
  100. ", patchconst: " << m_NumPCSigScalars << "\n";
  101. } else {
  102. OS << "Number of inputs: " << m_NumInputSigScalars <<
  103. ", outputs: { " << m_NumOutputSigScalars[0] << ", " << m_NumOutputSigScalars[1] << ", " <<
  104. m_NumOutputSigScalars[2] << ", " << m_NumOutputSigScalars[3] << " }" <<
  105. ", patchconst: " << m_NumPCSigScalars << "\n";
  106. }
  107. if (!pSM->IsGS()) {
  108. PrintOutputsDependentOnViewId(OS, "Outputs", m_NumOutputSigScalars[0], m_OutputsDependentOnViewId[0]);
  109. } else {
  110. PrintOutputsDependentOnViewId(OS, "Outputs for Stream0", m_NumOutputSigScalars[0], m_OutputsDependentOnViewId[0]);
  111. PrintOutputsDependentOnViewId(OS, "Outputs for Stream1", m_NumOutputSigScalars[1], m_OutputsDependentOnViewId[1]);
  112. PrintOutputsDependentOnViewId(OS, "Outputs for Stream2", m_NumOutputSigScalars[2], m_OutputsDependentOnViewId[2]);
  113. PrintOutputsDependentOnViewId(OS, "Outputs for Stream3", m_NumOutputSigScalars[3], m_OutputsDependentOnViewId[3]);
  114. }
  115. if (pSM->IsHS()) {
  116. PrintOutputsDependentOnViewId(OS, "PCOutputs", m_NumPCSigScalars, m_PCOutputsDependentOnViewId);
  117. }
  118. if (!pSM->IsGS()) {
  119. PrintInputsContributingToOutputs(OS, "Inputs", "Outputs", m_InputsContributingToOutputs[0]);
  120. } else {
  121. PrintInputsContributingToOutputs(OS, "Inputs", "Outputs for Stream0", m_InputsContributingToOutputs[0]);
  122. PrintInputsContributingToOutputs(OS, "Inputs", "Outputs for Stream1", m_InputsContributingToOutputs[1]);
  123. PrintInputsContributingToOutputs(OS, "Inputs", "Outputs for Stream2", m_InputsContributingToOutputs[2]);
  124. PrintInputsContributingToOutputs(OS, "Inputs", "Outputs for Stream3", m_InputsContributingToOutputs[3]);
  125. }
  126. if (pSM->IsHS()) {
  127. PrintInputsContributingToOutputs(OS, "Inputs", "PCOutputs", m_InputsContributingToPCOutputs);
  128. } else if (pSM->IsDS()) {
  129. PrintInputsContributingToOutputs(OS, "PCInputs", "Outputs", m_PCInputsContributingToOutputs);
  130. }
  131. OS << "\n";
  132. }
  133. void DxilViewIdState::PrintOutputsDependentOnViewId(llvm::raw_ostream &OS,
  134. llvm::StringRef SetName,
  135. unsigned NumOutputs,
  136. const OutputsDependentOnViewIdType &OutputsDependentOnViewId) {
  137. OS << SetName << " dependent on ViewId: { ";
  138. bool bFirst = true;
  139. for (unsigned i = 0; i < NumOutputs; i++) {
  140. if (OutputsDependentOnViewId[i]) {
  141. if (!bFirst) OS << ", ";
  142. OS << i;
  143. bFirst = false;
  144. }
  145. }
  146. OS << " }\n";
  147. }
  148. void DxilViewIdState::PrintInputsContributingToOutputs(llvm::raw_ostream &OS,
  149. llvm::StringRef InputSetName,
  150. llvm::StringRef OutputSetName,
  151. const InputsContributingToOutputType &InputsContributingToOutputs) {
  152. OS << InputSetName << " contributing to computation of " << OutputSetName << ":\n";
  153. for (auto &it : InputsContributingToOutputs) {
  154. unsigned outIdx = it.first;
  155. auto &Inputs = it.second;
  156. OS << "output " << outIdx << " depends on inputs: { ";
  157. bool bFirst = true;
  158. for (unsigned i : Inputs) {
  159. if (!bFirst) OS << ", ";
  160. OS << i;
  161. bFirst = false;
  162. }
  163. OS << " }\n";
  164. }
  165. }
  166. void DxilViewIdState::Clear() {
  167. m_bUsesViewId = false;
  168. m_NumInputSigScalars = 0;
  169. for (unsigned i = 0; i < kNumStreams; i++) {
  170. m_NumOutputSigScalars[i] = 0;
  171. m_OutputsDependentOnViewId[i].reset();
  172. m_InputsContributingToOutputs[i].clear();
  173. }
  174. m_NumPCSigScalars = 0;
  175. m_InpSigDynIdxElems.clear();
  176. m_OutSigDynIdxElems.clear();
  177. m_PCSigDynIdxElems.clear();
  178. m_PCOutputsDependentOnViewId.reset();
  179. m_InputsContributingToPCOutputs.clear();
  180. m_PCInputsContributingToOutputs.clear();
  181. m_Entry.Clear();
  182. m_PCEntry.Clear();
  183. m_FuncInfo.clear();
  184. m_ReachingDeclsCache.clear();
  185. m_SerializedState.clear();
  186. }
  187. void DxilViewIdState::EntryInfo::Clear() {
  188. pEntryFunc = nullptr;
  189. Functions.clear();
  190. Outputs.clear();
  191. for (unsigned i = 0; i < kNumStreams; i++)
  192. ContributingInstructions[i].clear();
  193. }
  194. void DxilViewIdState::FuncInfo::Clear() {
  195. Returns.clear();
  196. CtrlDep.Clear();
  197. pDomTree.reset();
  198. }
  199. void DxilViewIdState::DetermineMaxPackedLocation(DxilSignature &DxilSig,
  200. unsigned *pMaxSigLoc,
  201. unsigned NumStreams) {
  202. if (&DxilSig == nullptr) return;
  203. DXASSERT_NOMSG(NumStreams == 1 || NumStreams == kNumStreams);
  204. for (unsigned i = 0; i < NumStreams; i++) {
  205. pMaxSigLoc[i] = 0;
  206. }
  207. for (auto &E : DxilSig.GetElements()) {
  208. if (E->GetStartRow() == Semantic::kUndefinedRow) continue;
  209. unsigned StreamId = E->GetOutputStream();
  210. unsigned endLoc = GetLinearIndex(*E, E->GetRows() - 1, E->GetCols() - 1);
  211. pMaxSigLoc[StreamId] = std::max(pMaxSigLoc[StreamId], endLoc + 1);
  212. E->GetCols();
  213. }
  214. }
  215. void DxilViewIdState::ComputeReachableFunctionsRec(CallGraph &CG, CallGraphNode *pNode, FunctionSetType &FuncSet) {
  216. Function *F = pNode->getFunction();
  217. // Accumulate only functions with bodies.
  218. if (F->empty()) return;
  219. auto itIns = FuncSet.emplace(F);
  220. DXASSERT_NOMSG(itIns.second);
  221. for (auto it = pNode->begin(), itEnd = pNode->end(); it != itEnd; ++it) {
  222. CallGraphNode *pSuccNode = it->second;
  223. ComputeReachableFunctionsRec(CG, pSuccNode, FuncSet);
  224. }
  225. }
  226. static bool GetUnsignedVal(Value *V, uint32_t *pValue) {
  227. ConstantInt *CI = dyn_cast<ConstantInt>(V);
  228. if (!CI) return false;
  229. uint64_t u = CI->getZExtValue();
  230. if (u > UINT32_MAX) return false;
  231. *pValue = (uint32_t)u;
  232. return true;
  233. }
  234. void DxilViewIdState::AnalyzeFunctions(EntryInfo &Entry) {
  235. for (auto *F : Entry.Functions) {
  236. DXASSERT_NOMSG(!F->empty());
  237. auto itFI = m_FuncInfo.find(F);
  238. FuncInfo *pFuncInfo = nullptr;
  239. if (itFI != m_FuncInfo.end()) {
  240. pFuncInfo = itFI->second.get();
  241. } else {
  242. m_FuncInfo[F] = make_unique<FuncInfo>();
  243. pFuncInfo = m_FuncInfo[F].get();
  244. }
  245. for (auto itBB = F->begin(), endBB = F->end(); itBB != endBB; ++itBB) {
  246. BasicBlock *BB = itBB;
  247. for (auto itInst = BB->begin(), endInst = BB->end(); itInst != endInst; ++itInst) {
  248. if (ReturnInst *RI = dyn_cast<ReturnInst>(itInst)) {
  249. pFuncInfo->Returns.emplace(RI);
  250. continue;
  251. }
  252. CallInst *CI = dyn_cast<CallInst>(itInst);
  253. if (!CI) continue;
  254. DynamicallyIndexedElemsType *pDynIdxElems = nullptr;
  255. int row = Semantic::kUndefinedRow;
  256. unsigned id, col;
  257. if (DxilInst_LoadInput LI = DxilInst_LoadInput(CI)) {
  258. pDynIdxElems = &m_InpSigDynIdxElems;
  259. IFTBOOL(GetUnsignedVal(LI.get_inputSigId(), &id), DXC_E_GENERAL_INTERNAL_ERROR);
  260. GetUnsignedVal(LI.get_rowIndex(), (uint32_t*)&row);
  261. IFTBOOL(GetUnsignedVal(LI.get_colIndex(), &col), DXC_E_GENERAL_INTERNAL_ERROR);
  262. } else if (DxilInst_StoreOutput SO = DxilInst_StoreOutput(CI)) {
  263. pDynIdxElems = &m_OutSigDynIdxElems;
  264. IFTBOOL(GetUnsignedVal(SO.get_outputSigId(), &id), DXC_E_GENERAL_INTERNAL_ERROR);
  265. GetUnsignedVal(SO.get_rowIndex(), (uint32_t*)&row);
  266. IFTBOOL(GetUnsignedVal(SO.get_colIndex(), &col), DXC_E_GENERAL_INTERNAL_ERROR);
  267. Entry.Outputs.emplace(CI);
  268. } else if (DxilInst_LoadPatchConstant LPC = DxilInst_LoadPatchConstant(CI)) {
  269. if (m_pModule->GetShaderModel()->IsDS()) {
  270. pDynIdxElems = &m_PCSigDynIdxElems;
  271. IFTBOOL(GetUnsignedVal(LPC.get_inputSigId(), &id), DXC_E_GENERAL_INTERNAL_ERROR);
  272. GetUnsignedVal(LPC.get_row(), (uint32_t*)&row);
  273. IFTBOOL(GetUnsignedVal(LPC.get_col(), &col), DXC_E_GENERAL_INTERNAL_ERROR);
  274. } else {
  275. // Do nothing. This is an internal helper function for DXBC-2-DXIL converter.
  276. DXASSERT_NOMSG(m_pModule->GetShaderModel()->IsHS());
  277. }
  278. } else if (DxilInst_StorePatchConstant SPC = DxilInst_StorePatchConstant(CI)) {
  279. pDynIdxElems = &m_PCSigDynIdxElems;
  280. IFTBOOL(GetUnsignedVal(SPC.get_outputSigID(), &id), DXC_E_GENERAL_INTERNAL_ERROR);
  281. GetUnsignedVal(SPC.get_row(), (uint32_t*)&row);
  282. IFTBOOL(GetUnsignedVal(SPC.get_col(), &col), DXC_E_GENERAL_INTERNAL_ERROR);
  283. Entry.Outputs.emplace(CI);
  284. } else if (DxilInst_LoadOutputControlPoint LOCP = DxilInst_LoadOutputControlPoint(CI)) {
  285. if (m_pModule->GetShaderModel()->IsDS()) {
  286. pDynIdxElems = &m_InpSigDynIdxElems;
  287. IFTBOOL(GetUnsignedVal(LOCP.get_inputSigId(), &id), DXC_E_GENERAL_INTERNAL_ERROR);
  288. GetUnsignedVal(LOCP.get_row(), (uint32_t*)&row);
  289. IFTBOOL(GetUnsignedVal(LOCP.get_col(), &col), DXC_E_GENERAL_INTERNAL_ERROR);
  290. } else if (m_pModule->GetShaderModel()->IsHS()) {
  291. // Do nothings, as the information has been captured by the output signature of CP entry.
  292. } else {
  293. DXASSERT_NOMSG(false);
  294. }
  295. } else {
  296. continue;
  297. }
  298. // Record dynamic index usage.
  299. if (pDynIdxElems && row == Semantic::kUndefinedRow) {
  300. (*pDynIdxElems)[id] |= (1 << col);
  301. }
  302. }
  303. }
  304. // Compute dominator relation.
  305. pFuncInfo->pDomTree = make_unique<DominatorTreeBase<BasicBlock> >(false);
  306. pFuncInfo->pDomTree->recalculate(*F);
  307. #if DXILVIEWID_DBG
  308. pFuncInfo->pDomTree->print(dbgs());
  309. #endif
  310. // Compute postdominator relation.
  311. DominatorTreeBase<BasicBlock> PDR(true);
  312. PDR.recalculate(*F);
  313. #if DXILVIEWID_DBG
  314. PDR.print(dbgs());
  315. #endif
  316. // Compute control dependence.
  317. pFuncInfo->CtrlDep.Compute(F, PDR);
  318. #if DXILVIEWID_DBG
  319. pFuncInfo->CtrlDep.print(dbgs());
  320. #endif
  321. }
  322. }
  323. void DxilViewIdState::CollectValuesContributingToOutputs(EntryInfo &Entry) {
  324. for (auto *CI : Entry.Outputs) { // CI = call instruction
  325. DxilSignature *pDxilSig = nullptr;
  326. Value *pContributingValue = nullptr;
  327. unsigned id = (unsigned)-1;
  328. int startRow = Semantic::kUndefinedRow, endRow = Semantic::kUndefinedRow;
  329. unsigned col = (unsigned)-1;
  330. if (DxilInst_StoreOutput SO = DxilInst_StoreOutput(CI)) {
  331. pDxilSig = &m_pModule->GetOutputSignature();
  332. pContributingValue = SO.get_value();
  333. GetUnsignedVal(SO.get_outputSigId(), &id);
  334. GetUnsignedVal(SO.get_colIndex(), &col);
  335. GetUnsignedVal(SO.get_rowIndex(), (uint32_t*)&startRow);
  336. } else if (DxilInst_StorePatchConstant SPC = DxilInst_StorePatchConstant(CI)) {
  337. pDxilSig = &m_pModule->GetPatchConstantSignature();
  338. pContributingValue = SPC.get_value();
  339. GetUnsignedVal(SPC.get_outputSigID(), &id);
  340. GetUnsignedVal(SPC.get_row(), (uint32_t*)&startRow);
  341. GetUnsignedVal(SPC.get_col(), &col);
  342. } else {
  343. IFT(DXC_E_GENERAL_INTERNAL_ERROR);
  344. }
  345. DxilSignatureElement &SigElem = pDxilSig->GetElement(id);
  346. if (!SigElem.IsAllocated())
  347. continue;
  348. unsigned StreamId = SigElem.GetOutputStream();
  349. if (startRow != Semantic::kUndefinedRow) {
  350. endRow = startRow;
  351. } else {
  352. // The entire column is affected by value.
  353. DXASSERT_NOMSG(SigElem.GetID() == id && SigElem.GetStartRow() != Semantic::kUndefinedRow);
  354. startRow = 0;
  355. endRow = SigElem.GetRows() - 1;
  356. }
  357. InstructionSetType ContributingInstructionsAllRows;
  358. InstructionSetType *pContributingInstructions = &ContributingInstructionsAllRows;
  359. if (startRow == endRow) {
  360. // Scalar or indexable with known index.
  361. unsigned index = GetLinearIndex(SigElem, startRow, col);
  362. pContributingInstructions = &Entry.ContributingInstructions[StreamId][index];
  363. }
  364. CollectValuesContributingToOutputRec(Entry, pContributingValue, *pContributingInstructions);
  365. // Handle control dependence of this instruction BB.
  366. BasicBlock *pBB = CI->getParent();
  367. Function *F = pBB->getParent();
  368. FuncInfo *pFuncInfo = m_FuncInfo[F].get();
  369. const BasicBlockSet &CtrlDepSet = pFuncInfo->CtrlDep.GetCDBlocks(pBB);
  370. for (BasicBlock *B : CtrlDepSet) {
  371. CollectValuesContributingToOutputRec(Entry, B->getTerminator(), *pContributingInstructions);
  372. }
  373. if (pContributingInstructions == &ContributingInstructionsAllRows) {
  374. // Write dynamically indexed output contributions to all rows.
  375. for (int row = startRow; row <= endRow; row++) {
  376. unsigned index = GetLinearIndex(SigElem, row, col);
  377. Entry.ContributingInstructions[StreamId][index].insert(ContributingInstructionsAllRows.begin(), ContributingInstructionsAllRows.end());
  378. }
  379. }
  380. }
  381. }
  382. void DxilViewIdState::CollectValuesContributingToOutputRec(EntryInfo &Entry,
  383. Value *pContributingValue,
  384. InstructionSetType &ContributingInstructions) {
  385. if (Argument *pArg = dyn_cast<Argument>(pContributingValue)) {
  386. // This must be a leftover signature argument of an entry function.
  387. DXASSERT_NOMSG(Entry.pEntryFunc == m_pModule->GetEntryFunction() ||
  388. Entry.pEntryFunc == m_pModule->GetPatchConstantFunction());
  389. return;
  390. }
  391. Instruction *pContributingInst = dyn_cast<Instruction>(pContributingValue);
  392. if (pContributingInst == nullptr) {
  393. // Can be literal constant, global decl, branch target.
  394. DXASSERT_NOMSG(isa<Constant>(pContributingValue) || isa<BasicBlock>(pContributingValue));
  395. return;
  396. }
  397. auto itInst = ContributingInstructions.emplace(pContributingInst);
  398. // Already visited instruction.
  399. if (!itInst.second) return;
  400. // Handle special cases.
  401. if (PHINode *phi = dyn_cast<PHINode>(pContributingInst)) {
  402. CollectPhiCFValuesContributingToOutputRec(phi, Entry, ContributingInstructions);
  403. } else if (isa<LoadInst>(pContributingInst) ||
  404. isa<AtomicCmpXchgInst>(pContributingInst) ||
  405. isa<AtomicRMWInst>(pContributingInst)) {
  406. Value *pPtrValue = pContributingInst->getOperand(0);
  407. DXASSERT_NOMSG(pPtrValue->getType()->isPointerTy());
  408. const ValueSetType &ReachingDecls = CollectReachingDecls(pPtrValue);
  409. DXASSERT_NOMSG(ReachingDecls.size() > 0);
  410. for (Value *pDeclValue : ReachingDecls) {
  411. const ValueSetType &Stores = CollectStores(pDeclValue);
  412. for (Value *V : Stores) {
  413. CollectValuesContributingToOutputRec(Entry, V, ContributingInstructions);
  414. }
  415. }
  416. } else if (CallInst *CI = dyn_cast<CallInst>(pContributingInst)) {
  417. if (!hlsl::OP::IsDxilOpFuncCallInst(CI)) {
  418. Function *F = CI->getCalledFunction();
  419. if (!F->empty()) {
  420. // Return value of a user function.
  421. if (Entry.Functions.find(F) != Entry.Functions.end()) {
  422. const FuncInfo &FI = *m_FuncInfo[F];
  423. for (ReturnInst *pRetInst : FI.Returns) {
  424. CollectValuesContributingToOutputRec(Entry, pRetInst, ContributingInstructions);
  425. }
  426. }
  427. }
  428. }
  429. }
  430. // Handle instruction inputs.
  431. unsigned NumOps = pContributingInst->getNumOperands();
  432. for (unsigned i = 0; i < NumOps; i++) {
  433. Value *O = pContributingInst->getOperand(i);
  434. CollectValuesContributingToOutputRec(Entry, O, ContributingInstructions);
  435. }
  436. // Handle control dependence of this instruction BB.
  437. BasicBlock *pBB = pContributingInst->getParent();
  438. Function *F = pBB->getParent();
  439. FuncInfo *pFuncInfo = m_FuncInfo[F].get();
  440. const BasicBlockSet &CtrlDepSet = pFuncInfo->CtrlDep.GetCDBlocks(pBB);
  441. for (BasicBlock *B : CtrlDepSet) {
  442. CollectValuesContributingToOutputRec(Entry, B->getTerminator(), ContributingInstructions);
  443. }
  444. }
  445. // Only process control-dependent basic blocks for constant operands of the phi-function.
  446. // An obvious "definition" point for a constant operand is the predecessor along corresponding edge.
  447. // However, this may be too conservative and, as such, pick up extra control dependent BBs.
  448. // A better "definition" point is the highest dominator where it is still legal to "insert" constant assignment.
  449. // In this context, "legal" means that only one value "leaves" the dominator and reaches Phi.
  450. void DxilViewIdState::CollectPhiCFValuesContributingToOutputRec(PHINode *pPhi,
  451. EntryInfo &Entry,
  452. InstructionSetType &ContributingInstructions) {
  453. Function *F = pPhi->getParent()->getParent();
  454. FuncInfo *pFuncInfo = m_FuncInfo[F].get();
  455. unordered_map<DomTreeNodeBase<BasicBlock> *, Value *> DomTreeMarkers;
  456. // Mark predecessors of each value, so that there is a legal "definition" point.
  457. for (unsigned i = 0; i < pPhi->getNumOperands(); i++) {
  458. Value *pValue = pPhi->getIncomingValue(i);
  459. BasicBlock *pBB = pPhi->getIncomingBlock(i);
  460. DomTreeNodeBase<BasicBlock> *pDomNode = pFuncInfo->pDomTree->getNode(pBB);
  461. auto it = DomTreeMarkers.emplace(pDomNode, pValue);
  462. DXASSERT_NOMSG(it.second || it.first->second == pValue); it;
  463. }
  464. // Mark the dominator tree with "definition" values, walking up to the parent.
  465. for (unsigned i = 0; i < pPhi->getNumOperands(); i++) {
  466. Value *pValue = pPhi->getIncomingValue(i);
  467. BasicBlock *pDefBB = &F->getEntryBlock();
  468. if (Instruction *pDefInst = dyn_cast<Instruction>(pValue)) {
  469. pDefBB = pDefInst->getParent();
  470. }
  471. BasicBlock *pBB = pPhi->getIncomingBlock(i);
  472. if (pBB == pDefBB) {
  473. continue; // we already handled the predecessor.
  474. }
  475. DomTreeNodeBase<BasicBlock> *pDomNode = pFuncInfo->pDomTree->getNode(pBB);
  476. pDomNode = pDomNode->getIDom();
  477. while (pDomNode) {
  478. auto it = DomTreeMarkers.emplace(pDomNode, pValue);
  479. if (!it.second) {
  480. if (it.first->second != pValue && it.first->second != nullptr) {
  481. if (!isa<Constant>(it.first->second) || !isa<Constant>(pValue)) {
  482. // Unless both are different constants, mark the "definition" point as illegal.
  483. it.first->second = nullptr;
  484. // If both are constants, leave the marker of the first one.
  485. }
  486. }
  487. break;
  488. }
  489. // Do not go higher than a legal definition point.
  490. pBB = pDomNode->getBlock();
  491. if (pBB == pDefBB)
  492. break;
  493. pDomNode = pDomNode->getIDom();
  494. }
  495. }
  496. // Handle control dependence for Constant arguments of Phi.
  497. for (unsigned i = 0; i < pPhi->getNumOperands(); i++) {
  498. Value *pValue = pPhi->getIncomingValue(i);
  499. if (!isa<Constant>(pValue))
  500. continue;
  501. // Determine the higher legal "definition" point.
  502. BasicBlock *pBB = pPhi->getIncomingBlock(i);
  503. DomTreeNodeBase<BasicBlock> *pDomNode = pFuncInfo->pDomTree->getNode(pBB);
  504. DomTreeNodeBase<BasicBlock> *pDefDomNode = pDomNode;
  505. while (pDomNode) {
  506. auto it = DomTreeMarkers.find(pDomNode);
  507. DXASSERT_NOMSG(it != DomTreeMarkers.end());
  508. if (it->second != pValue) {
  509. DXASSERT_NOMSG(it->second == nullptr || isa<Constant>(it->second));
  510. break;
  511. }
  512. pDefDomNode = pDomNode;
  513. pDomNode = pDomNode->getIDom();
  514. }
  515. // Handle control dependence of this constant argument highest legal "definition" point.
  516. pBB = pDefDomNode->getBlock();
  517. const BasicBlockSet &CtrlDepSet = pFuncInfo->CtrlDep.GetCDBlocks(pBB);
  518. for (BasicBlock *B : CtrlDepSet) {
  519. CollectValuesContributingToOutputRec(Entry, B->getTerminator(), ContributingInstructions);
  520. }
  521. }
  522. }
  523. const DxilViewIdState::ValueSetType &DxilViewIdState::CollectReachingDecls(Value *pValue) {
  524. auto it = m_ReachingDeclsCache.emplace(pValue, ValueSetType());
  525. if (it.second) {
  526. // We have not seen this value before.
  527. ValueSetType Visited;
  528. CollectReachingDeclsRec(pValue, it.first->second, Visited);
  529. }
  530. return it.first->second;
  531. }
  532. void DxilViewIdState::CollectReachingDeclsRec(Value *pValue, ValueSetType &ReachingDecls, ValueSetType &Visited) {
  533. if (Visited.find(pValue) != Visited.end())
  534. return;
  535. bool bInitialValue = Visited.size() == 0;
  536. Visited.emplace(pValue);
  537. if (!bInitialValue) {
  538. auto it = m_ReachingDeclsCache.find(pValue);
  539. if (it != m_ReachingDeclsCache.end()) {
  540. ReachingDecls.insert(it->second.begin(), it->second.end());
  541. return;
  542. }
  543. }
  544. if (GlobalVariable *GV = dyn_cast<GlobalVariable>(pValue)) {
  545. ReachingDecls.emplace(pValue);
  546. return;
  547. }
  548. if (GetElementPtrInst *pGepInst = dyn_cast<GetElementPtrInst>(pValue)) {
  549. Value *pPtrValue = pGepInst->getPointerOperand();
  550. CollectReachingDeclsRec(pPtrValue, ReachingDecls, Visited);
  551. } else if (GEPOperator *pGepOp = dyn_cast<GEPOperator>(pValue)) {
  552. Value *pPtrValue = pGepOp->getPointerOperand();
  553. CollectReachingDeclsRec(pPtrValue, ReachingDecls, Visited);
  554. } else if (AllocaInst *AI = dyn_cast<AllocaInst>(pValue)) {
  555. ReachingDecls.emplace(pValue);
  556. } else if (PHINode *phi = dyn_cast<PHINode>(pValue)) {
  557. for (Value *pPtrValue : phi->operands()) {
  558. CollectReachingDeclsRec(pPtrValue, ReachingDecls, Visited);
  559. }
  560. } else if (SelectInst *SelI = dyn_cast<SelectInst>(pValue)) {
  561. CollectReachingDeclsRec(SelI->getTrueValue(), ReachingDecls, Visited);
  562. CollectReachingDeclsRec(SelI->getFalseValue(), ReachingDecls, Visited);
  563. } else if (Argument *pArg = dyn_cast<Argument>(pValue)) {
  564. ReachingDecls.emplace(pValue);
  565. } else if (BitCastInst *BCI = dyn_cast<BitCastInst>(pValue)) {
  566. CollectReachingDeclsRec(BCI->getOperand(0), ReachingDecls, Visited);
  567. } else {
  568. IFT(DXC_E_GENERAL_INTERNAL_ERROR);
  569. }
  570. }
  571. const DxilViewIdState::ValueSetType &DxilViewIdState::CollectStores(llvm::Value *pValue) {
  572. auto it = m_StoresPerDeclCache.emplace(pValue, ValueSetType());
  573. if (it.second) {
  574. // We have not seen this value before.
  575. ValueSetType Visited;
  576. CollectStoresRec(pValue, it.first->second, Visited);
  577. }
  578. return it.first->second;
  579. }
  580. void DxilViewIdState::CollectStoresRec(llvm::Value *pValue, ValueSetType &Stores, ValueSetType &Visited) {
  581. if (Visited.find(pValue) != Visited.end())
  582. return;
  583. bool bInitialValue = Visited.size() == 0;
  584. Visited.emplace(pValue);
  585. if (!bInitialValue) {
  586. auto it = m_StoresPerDeclCache.find(pValue);
  587. if (it != m_StoresPerDeclCache.end()) {
  588. Stores.insert(it->second.begin(), it->second.end());
  589. return;
  590. }
  591. }
  592. if (isa<LoadInst>(pValue)) {
  593. return;
  594. } else if (isa<StoreInst>(pValue) ||
  595. isa<AtomicCmpXchgInst>(pValue) ||
  596. isa<AtomicRMWInst>(pValue)) {
  597. Stores.emplace(pValue);
  598. return;
  599. }
  600. for (auto *U : pValue->users()) {
  601. CollectStoresRec(U, Stores, Visited);
  602. }
  603. }
  604. void DxilViewIdState::CreateViewIdSets(const std::unordered_map<unsigned, InstructionSetType> &ContributingInstructions,
  605. OutputsDependentOnViewIdType &OutputsDependentOnViewId,
  606. InputsContributingToOutputType &InputsContributingToOutputs,
  607. bool bPC) {
  608. const ShaderModel *pSM = m_pModule->GetShaderModel();
  609. for (auto &itOut : ContributingInstructions) {
  610. unsigned outIdx = itOut.first;
  611. for (Instruction *pInst : itOut.second) {
  612. // Set output dependence on ViewId.
  613. if (DxilInst_ViewID VID = DxilInst_ViewID(pInst)) {
  614. DXASSERT(m_bUsesViewId, "otherwise, DxilModule flag not set properly");
  615. OutputsDependentOnViewId[outIdx] = true;
  616. continue;
  617. }
  618. // Start setting output dependence on inputs.
  619. DxilSignatureElement *pSigElem = nullptr;
  620. bool bLoadOutputCPInHS = false;
  621. unsigned inpId = (unsigned)-1;
  622. int startRow = Semantic::kUndefinedRow, endRow = Semantic::kUndefinedRow;
  623. unsigned col = (unsigned)-1;
  624. if (DxilInst_LoadInput LI = DxilInst_LoadInput(pInst)) {
  625. GetUnsignedVal(LI.get_inputSigId(), &inpId);
  626. GetUnsignedVal(LI.get_colIndex(), &col);
  627. GetUnsignedVal(LI.get_rowIndex(), (uint32_t*)&startRow);
  628. pSigElem = &m_pModule->GetInputSignature().GetElement(inpId);
  629. if (pSM->IsDS() && bPC) {
  630. pSigElem = nullptr;
  631. }
  632. } else if (DxilInst_LoadOutputControlPoint LOCP = DxilInst_LoadOutputControlPoint(pInst)) {
  633. GetUnsignedVal(LOCP.get_inputSigId(), &inpId);
  634. GetUnsignedVal(LOCP.get_col(), &col);
  635. GetUnsignedVal(LOCP.get_row(), (uint32_t*)&startRow);
  636. if (pSM->IsHS()) {
  637. pSigElem = &m_pModule->GetOutputSignature().GetElement(inpId);
  638. bLoadOutputCPInHS = true;
  639. } else if (pSM->IsDS()) {
  640. if (!bPC) {
  641. pSigElem = &m_pModule->GetInputSignature().GetElement(inpId);
  642. }
  643. } else {
  644. DXASSERT_NOMSG(false);
  645. }
  646. } else if (DxilInst_LoadPatchConstant LPC = DxilInst_LoadPatchConstant(pInst)) {
  647. if (pSM->IsDS() && bPC) {
  648. GetUnsignedVal(LPC.get_inputSigId(), &inpId);
  649. GetUnsignedVal(LPC.get_col(), &col);
  650. GetUnsignedVal(LPC.get_row(), (uint32_t*)&startRow);
  651. pSigElem = &m_pModule->GetPatchConstantSignature().GetElement(inpId);
  652. }
  653. } else {
  654. continue;
  655. }
  656. // Finalize setting output dependence on inputs.
  657. if (pSigElem && pSigElem->IsAllocated()) {
  658. if (startRow != Semantic::kUndefinedRow) {
  659. endRow = startRow;
  660. } else {
  661. // The entire column contributes to output.
  662. startRow = 0;
  663. endRow = pSigElem->GetRows() - 1;
  664. }
  665. auto &ContributingInputs = InputsContributingToOutputs[outIdx];
  666. for (int row = startRow; row <= endRow; row++) {
  667. unsigned index = GetLinearIndex(*pSigElem, row, col);
  668. if (!bLoadOutputCPInHS) {
  669. ContributingInputs.emplace(index);
  670. } else {
  671. // This HS patch-constant output depends on an input value of LoadOutputControlPoint
  672. // that is the output value of the HS main (control-point) function.
  673. // Transitively update this (patch-constant) output dependence on main (control-point) output.
  674. DXASSERT_NOMSG(&OutputsDependentOnViewId == &m_PCOutputsDependentOnViewId);
  675. OutputsDependentOnViewId[outIdx] = OutputsDependentOnViewId[outIdx] || m_OutputsDependentOnViewId[0][index];
  676. const auto it = m_InputsContributingToOutputs[0].find(index);
  677. if (it != m_InputsContributingToOutputs[0].end()) {
  678. const std::set<unsigned> &LoadOutputCPInputsContributingToOutputs = it->second;
  679. ContributingInputs.insert(LoadOutputCPInputsContributingToOutputs.begin(),
  680. LoadOutputCPInputsContributingToOutputs.end());
  681. }
  682. }
  683. }
  684. }
  685. }
  686. }
  687. }
  688. unsigned DxilViewIdState::GetLinearIndex(DxilSignatureElement &SigElem, int row, unsigned col) const {
  689. DXASSERT_NOMSG(row >= 0 && col < kNumComps && SigElem.GetStartRow() != Semantic::kUndefinedRow);
  690. unsigned idx = (((unsigned)row) + SigElem.GetStartRow())*kNumComps + col + SigElem.GetStartCol();
  691. DXASSERT_NOMSG(idx < kMaxSigScalars);
  692. return idx;
  693. }
  694. void DxilViewIdState::UpdateDynamicIndexUsageState() const {
  695. UpdateDynamicIndexUsageStateForSig(m_pModule->GetInputSignature(), m_InpSigDynIdxElems);
  696. UpdateDynamicIndexUsageStateForSig(m_pModule->GetOutputSignature(), m_OutSigDynIdxElems);
  697. UpdateDynamicIndexUsageStateForSig(m_pModule->GetPatchConstantSignature(), m_PCSigDynIdxElems);
  698. }
  699. void DxilViewIdState::UpdateDynamicIndexUsageStateForSig(DxilSignature &Sig,
  700. const DynamicallyIndexedElemsType &DynIdxElems) const {
  701. for (auto it : DynIdxElems) {
  702. unsigned id = it.first;
  703. unsigned mask = it.second;
  704. DxilSignatureElement &E = Sig.GetElement(id);
  705. E.SetDynIdxCompMask(mask);
  706. }
  707. }
  708. static unsigned RoundUpToUINT(unsigned x) {
  709. return (x + 31)/32;
  710. }
  711. void DxilViewIdState::Serialize() {
  712. const ShaderModel *pSM = m_pModule->GetShaderModel();
  713. m_SerializedState.clear();
  714. // Compute serialized state size in UINTs.
  715. unsigned NumInputs = getNumInputSigScalars();
  716. unsigned NumStreams = pSM->IsGS()? kNumStreams : 1;
  717. unsigned Size = 0;
  718. Size += 1; // #Inputs.
  719. for (unsigned StreamId = 0; StreamId < NumStreams; StreamId++) {
  720. Size += 1; // #Outputs for stream StreamId.
  721. unsigned NumOutputs = getNumOutputSigScalars(StreamId);
  722. unsigned NumOutUINTs = RoundUpToUINT(NumOutputs);
  723. if (m_bUsesViewId) {
  724. Size += NumOutUINTs; // m_OutputsDependentOnViewId[StreamId]
  725. }
  726. Size += NumInputs * NumOutUINTs; // m_InputsContributingToOutputs[StreamId]
  727. }
  728. if (pSM->IsHS() || pSM->IsDS()) {
  729. Size += 1; // #PatchConstant.
  730. unsigned NumPCs = getNumPCSigScalars();
  731. unsigned NumPCUINTs = RoundUpToUINT(NumPCs);
  732. if (pSM->IsHS()) {
  733. if (m_bUsesViewId) {
  734. Size += NumPCUINTs; // m_PCOutputsDependentOnViewId
  735. }
  736. Size += NumInputs * NumPCUINTs; // m_InputsContributingToPCOutputs
  737. } else {
  738. unsigned NumOutputs = getNumOutputSigScalars(0);
  739. unsigned NumOutUINTs = RoundUpToUINT(NumOutputs);
  740. Size += NumPCs * NumOutUINTs; // m_PCInputsContributingToOutputs
  741. }
  742. }
  743. m_SerializedState.resize(Size);
  744. std::fill(m_SerializedState.begin(), m_SerializedState.end(), 0u);
  745. // Serialize ViewId state.
  746. unsigned *pData = &m_SerializedState[0];
  747. *pData++ = NumInputs;
  748. for (unsigned StreamId = 0; StreamId < NumStreams; StreamId++) {
  749. unsigned NumOutputs = getNumOutputSigScalars(StreamId);
  750. *pData++ = NumOutputs;
  751. if (m_bUsesViewId) {
  752. SerializeOutputsDependentOnViewId(NumOutputs, m_OutputsDependentOnViewId[StreamId], pData);
  753. }
  754. SerializeInputsContributingToOutput(NumInputs, NumOutputs, m_InputsContributingToOutputs[StreamId], pData);
  755. }
  756. if (pSM->IsHS() || pSM->IsDS()) {
  757. unsigned NumPCs = getNumPCSigScalars();
  758. *pData++ = NumPCs;
  759. if (pSM->IsHS()) {
  760. if (m_bUsesViewId) {
  761. SerializeOutputsDependentOnViewId(NumPCs, m_PCOutputsDependentOnViewId, pData);
  762. }
  763. SerializeInputsContributingToOutput(NumInputs, NumPCs, m_InputsContributingToPCOutputs, pData);
  764. } else {
  765. unsigned NumOutputs = getNumOutputSigScalars(0);
  766. SerializeInputsContributingToOutput(NumPCs, NumOutputs, m_PCInputsContributingToOutputs, pData);
  767. }
  768. }
  769. DXASSERT_NOMSG(pData == (&m_SerializedState[0] + Size));
  770. }
  771. const vector<unsigned> &DxilViewIdState::GetSerialized() {
  772. if (m_SerializedState.empty())
  773. Serialize();
  774. return m_SerializedState;
  775. }
  776. const vector<unsigned> &DxilViewIdState::GetSerialized() const {
  777. return m_SerializedState;
  778. }
  779. void DxilViewIdState::SerializeOutputsDependentOnViewId(unsigned NumOutputs,
  780. const OutputsDependentOnViewIdType &OutputsDependentOnViewId,
  781. unsigned *&pData) {
  782. unsigned NumOutUINTs = RoundUpToUINT(NumOutputs);
  783. // Serialize output dependence on ViewId.
  784. for (unsigned i = 0; i < NumOutUINTs; i++) {
  785. unsigned x = 0;
  786. for (unsigned j = 0; j < std::min(32u, NumOutputs - 32u*i); j++) {
  787. if (OutputsDependentOnViewId[i*32 + j]) {
  788. x |= (1u << j);
  789. }
  790. }
  791. *pData++ = x;
  792. }
  793. }
  794. void DxilViewIdState::SerializeInputsContributingToOutput(unsigned NumInputs, unsigned NumOutputs,
  795. const InputsContributingToOutputType &InputsContributingToOutputs,
  796. unsigned *&pData) {
  797. unsigned NumOutUINTs = RoundUpToUINT(NumOutputs);
  798. // Serialize output dependence on inputs.
  799. for (unsigned outputIdx = 0; outputIdx < NumOutputs; outputIdx++) {
  800. auto it = InputsContributingToOutputs.find(outputIdx);
  801. if (it != InputsContributingToOutputs.end()) {
  802. for (unsigned inputIdx : it->second) {
  803. unsigned w = outputIdx / 32;
  804. unsigned b = outputIdx % 32;
  805. pData[inputIdx*NumOutUINTs + w] |= (1u << b);
  806. }
  807. }
  808. }
  809. pData += NumInputs * NumOutUINTs;
  810. }
  811. void DxilViewIdState::Deserialize(const unsigned *pData, unsigned DataSizeInUINTs) {
  812. Clear();
  813. m_SerializedState.resize(DataSizeInUINTs);
  814. memcpy(m_SerializedState.data(), pData, DataSizeInUINTs * sizeof(unsigned));
  815. const ShaderModel *pSM = m_pModule->GetShaderModel();
  816. m_bUsesViewId = m_pModule->m_ShaderFlags.GetViewID();
  817. unsigned ConsumedUINTs = 0;
  818. IFTBOOL(DataSizeInUINTs-ConsumedUINTs >= 1, DXC_E_GENERAL_INTERNAL_ERROR);
  819. unsigned NumInputs = pData[ConsumedUINTs++];
  820. m_NumInputSigScalars = NumInputs;
  821. unsigned NumStreams = pSM->IsGS()? kNumStreams : 1;
  822. for (unsigned StreamId = 0; StreamId < NumStreams; StreamId++) {
  823. IFTBOOL(DataSizeInUINTs-ConsumedUINTs >= 1, DXC_E_GENERAL_INTERNAL_ERROR);
  824. unsigned NumOutputs = pData[ConsumedUINTs++];
  825. m_NumOutputSigScalars[StreamId] = NumOutputs;
  826. if (m_bUsesViewId) {
  827. ConsumedUINTs += DeserializeOutputsDependentOnViewId(NumOutputs,
  828. m_OutputsDependentOnViewId[StreamId],
  829. &pData[ConsumedUINTs],
  830. DataSizeInUINTs-ConsumedUINTs);
  831. }
  832. ConsumedUINTs += DeserializeInputsContributingToOutput(NumInputs, NumOutputs,
  833. m_InputsContributingToOutputs[StreamId],
  834. &pData[ConsumedUINTs],
  835. DataSizeInUINTs-ConsumedUINTs);
  836. }
  837. if (pSM->IsHS() || pSM->IsDS()) {
  838. IFTBOOL(DataSizeInUINTs-ConsumedUINTs >= 1, DXC_E_GENERAL_INTERNAL_ERROR);
  839. unsigned NumPCs = pData[ConsumedUINTs++];
  840. m_NumPCSigScalars = NumPCs;
  841. if (pSM->IsHS()) {
  842. if (m_bUsesViewId) {
  843. ConsumedUINTs += DeserializeOutputsDependentOnViewId(NumPCs,
  844. m_PCOutputsDependentOnViewId,
  845. &pData[ConsumedUINTs],
  846. DataSizeInUINTs-ConsumedUINTs);
  847. }
  848. ConsumedUINTs += DeserializeInputsContributingToOutput(NumInputs, NumPCs,
  849. m_InputsContributingToPCOutputs,
  850. &pData[ConsumedUINTs],
  851. DataSizeInUINTs-ConsumedUINTs);
  852. } else {
  853. unsigned NumOutputs = getNumOutputSigScalars(0);
  854. ConsumedUINTs += DeserializeInputsContributingToOutput(NumPCs, NumOutputs,
  855. m_PCInputsContributingToOutputs,
  856. &pData[ConsumedUINTs],
  857. DataSizeInUINTs-ConsumedUINTs);
  858. }
  859. }
  860. DXASSERT_NOMSG(ConsumedUINTs == DataSizeInUINTs);
  861. }
  862. unsigned DxilViewIdState::DeserializeOutputsDependentOnViewId(unsigned NumOutputs,
  863. OutputsDependentOnViewIdType &OutputsDependentOnViewId,
  864. const unsigned *pData, unsigned DataSize) {
  865. unsigned NumOutUINTs = RoundUpToUINT(NumOutputs);
  866. IFTBOOL(NumOutUINTs <= DataSize, DXC_E_GENERAL_INTERNAL_ERROR);
  867. // Deserialize output dependence on ViewId.
  868. for (unsigned i = 0; i < NumOutUINTs; i++) {
  869. unsigned x = *pData++;
  870. for (unsigned j = 0; j < std::min(32u, NumOutputs - 32u*i); j++) {
  871. if (x & (1u << j)) {
  872. OutputsDependentOnViewId[i*32 + j] = true;
  873. }
  874. }
  875. }
  876. return NumOutUINTs;
  877. }
  878. unsigned DxilViewIdState::DeserializeInputsContributingToOutput(unsigned NumInputs, unsigned NumOutputs,
  879. InputsContributingToOutputType &InputsContributingToOutputs,
  880. const unsigned *pData, unsigned DataSize) {
  881. unsigned NumOutUINTs = RoundUpToUINT(NumOutputs);
  882. unsigned Size = NumInputs * NumOutUINTs;
  883. IFTBOOL(Size <= DataSize, DXC_E_GENERAL_INTERNAL_ERROR);
  884. // Deserialize output dependence on inputs.
  885. for (unsigned inputIdx = 0; inputIdx < NumInputs; inputIdx++) {
  886. for (unsigned outputIdx = 0; outputIdx < NumOutputs; outputIdx++) {
  887. unsigned w = outputIdx / 32;
  888. unsigned b = outputIdx % 32;
  889. if (pData[inputIdx*NumOutUINTs + w] & (1u << b)) {
  890. InputsContributingToOutputs[outputIdx].insert(inputIdx);
  891. }
  892. }
  893. }
  894. return Size;
  895. }
  896. char ComputeViewIdState::ID = 0;
  897. INITIALIZE_PASS_BEGIN(ComputeViewIdState, "viewid-state",
  898. "Compute information related to ViewID", true, true)
  899. INITIALIZE_PASS_END(ComputeViewIdState, "viewid-state",
  900. "Compute information related to ViewID", true, true)
  901. ComputeViewIdState::ComputeViewIdState() : ModulePass(ID) {
  902. }
  903. bool ComputeViewIdState::runOnModule(Module &M) {
  904. DxilModule &DxilModule = M.GetOrCreateDxilModule();
  905. const ShaderModel *pSM = DxilModule.GetShaderModel();
  906. if (!pSM->IsCS() && !pSM->IsLib()) {
  907. DxilViewIdState &ViewIdState = DxilModule.GetViewIdState();
  908. ViewIdState.Compute();
  909. return true;
  910. }
  911. return false;
  912. }
  913. void ComputeViewIdState::getAnalysisUsage(AnalysisUsage &AU) const {
  914. AU.setPreservesAll();
  915. }
  916. namespace llvm {
  917. ModulePass *createComputeViewIdStatePass() {
  918. return new ComputeViewIdState();
  919. }
  920. } // end of namespace llvm