ComputeViewIdState.cpp 42 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034
  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 (Argument *pArg = dyn_cast<Argument>(pValue)) {
  561. ReachingDecls.emplace(pValue);
  562. } else {
  563. IFT(DXC_E_GENERAL_INTERNAL_ERROR);
  564. }
  565. }
  566. const DxilViewIdState::ValueSetType &DxilViewIdState::CollectStores(llvm::Value *pValue) {
  567. auto it = m_StoresPerDeclCache.emplace(pValue, ValueSetType());
  568. if (it.second) {
  569. // We have not seen this value before.
  570. ValueSetType Visited;
  571. CollectStoresRec(pValue, it.first->second, Visited);
  572. }
  573. return it.first->second;
  574. }
  575. void DxilViewIdState::CollectStoresRec(llvm::Value *pValue, ValueSetType &Stores, ValueSetType &Visited) {
  576. if (Visited.find(pValue) != Visited.end())
  577. return;
  578. bool bInitialValue = Visited.size() == 0;
  579. Visited.emplace(pValue);
  580. if (!bInitialValue) {
  581. auto it = m_StoresPerDeclCache.find(pValue);
  582. if (it != m_StoresPerDeclCache.end()) {
  583. Stores.insert(it->second.begin(), it->second.end());
  584. return;
  585. }
  586. }
  587. if (isa<LoadInst>(pValue)) {
  588. return;
  589. } else if (isa<StoreInst>(pValue) ||
  590. isa<AtomicCmpXchgInst>(pValue) ||
  591. isa<AtomicRMWInst>(pValue)) {
  592. Stores.emplace(pValue);
  593. return;
  594. }
  595. for (auto *U : pValue->users()) {
  596. CollectStoresRec(U, Stores, Visited);
  597. }
  598. }
  599. void DxilViewIdState::CreateViewIdSets(const std::unordered_map<unsigned, InstructionSetType> &ContributingInstructions,
  600. OutputsDependentOnViewIdType &OutputsDependentOnViewId,
  601. InputsContributingToOutputType &InputsContributingToOutputs,
  602. bool bPC) {
  603. const ShaderModel *pSM = m_pModule->GetShaderModel();
  604. for (auto &itOut : ContributingInstructions) {
  605. unsigned outIdx = itOut.first;
  606. for (Instruction *pInst : itOut.second) {
  607. // Set output dependence on ViewId.
  608. if (DxilInst_ViewID VID = DxilInst_ViewID(pInst)) {
  609. DXASSERT(m_bUsesViewId, "otherwise, DxilModule flag not set properly");
  610. OutputsDependentOnViewId[outIdx] = true;
  611. continue;
  612. }
  613. // Start setting output dependence on inputs.
  614. DxilSignatureElement *pSigElem = nullptr;
  615. bool bLoadOutputCPInHS = false;
  616. unsigned inpId = (unsigned)-1;
  617. int startRow = Semantic::kUndefinedRow, endRow = Semantic::kUndefinedRow;
  618. unsigned col = (unsigned)-1;
  619. if (DxilInst_LoadInput LI = DxilInst_LoadInput(pInst)) {
  620. GetUnsignedVal(LI.get_inputSigId(), &inpId);
  621. GetUnsignedVal(LI.get_colIndex(), &col);
  622. GetUnsignedVal(LI.get_rowIndex(), (uint32_t*)&startRow);
  623. pSigElem = &m_pModule->GetInputSignature().GetElement(inpId);
  624. if (pSM->IsDS() && bPC) {
  625. pSigElem = nullptr;
  626. }
  627. } else if (DxilInst_LoadOutputControlPoint LOCP = DxilInst_LoadOutputControlPoint(pInst)) {
  628. GetUnsignedVal(LOCP.get_inputSigId(), &inpId);
  629. GetUnsignedVal(LOCP.get_col(), &col);
  630. GetUnsignedVal(LOCP.get_row(), (uint32_t*)&startRow);
  631. if (pSM->IsHS()) {
  632. pSigElem = &m_pModule->GetOutputSignature().GetElement(inpId);
  633. bLoadOutputCPInHS = true;
  634. } else if (pSM->IsDS()) {
  635. if (!bPC) {
  636. pSigElem = &m_pModule->GetInputSignature().GetElement(inpId);
  637. }
  638. } else {
  639. DXASSERT_NOMSG(false);
  640. }
  641. } else if (DxilInst_LoadPatchConstant LPC = DxilInst_LoadPatchConstant(pInst)) {
  642. if (pSM->IsDS() && bPC) {
  643. GetUnsignedVal(LPC.get_inputSigId(), &inpId);
  644. GetUnsignedVal(LPC.get_col(), &col);
  645. GetUnsignedVal(LPC.get_row(), (uint32_t*)&startRow);
  646. pSigElem = &m_pModule->GetPatchConstantSignature().GetElement(inpId);
  647. }
  648. } else {
  649. continue;
  650. }
  651. // Finalize setting output dependence on inputs.
  652. if (pSigElem && pSigElem->IsAllocated()) {
  653. if (startRow != Semantic::kUndefinedRow) {
  654. endRow = startRow;
  655. } else {
  656. // The entire column contributes to output.
  657. startRow = 0;
  658. endRow = pSigElem->GetRows() - 1;
  659. }
  660. auto &ContributingInputs = InputsContributingToOutputs[outIdx];
  661. for (int row = startRow; row <= endRow; row++) {
  662. unsigned index = GetLinearIndex(*pSigElem, row, col);
  663. if (!bLoadOutputCPInHS) {
  664. ContributingInputs.emplace(index);
  665. } else {
  666. // This HS patch-constant output depends on an input value of LoadOutputControlPoint
  667. // that is the output value of the HS main (control-point) function.
  668. // Transitively update this (patch-constant) output dependence on main (control-point) output.
  669. DXASSERT_NOMSG(&OutputsDependentOnViewId == &m_PCOutputsDependentOnViewId);
  670. OutputsDependentOnViewId[outIdx] = OutputsDependentOnViewId[outIdx] || m_OutputsDependentOnViewId[0][index];
  671. const auto it = m_InputsContributingToOutputs[0].find(index);
  672. if (it != m_InputsContributingToOutputs[0].end()) {
  673. const std::set<unsigned> &LoadOutputCPInputsContributingToOutputs = it->second;
  674. ContributingInputs.insert(LoadOutputCPInputsContributingToOutputs.begin(),
  675. LoadOutputCPInputsContributingToOutputs.end());
  676. }
  677. }
  678. }
  679. }
  680. }
  681. }
  682. }
  683. unsigned DxilViewIdState::GetLinearIndex(DxilSignatureElement &SigElem, int row, unsigned col) const {
  684. DXASSERT_NOMSG(row >= 0 && col < kNumComps && SigElem.GetStartRow() != Semantic::kUndefinedRow);
  685. unsigned idx = (((unsigned)row) + SigElem.GetStartRow())*kNumComps + col + SigElem.GetStartCol();
  686. DXASSERT_NOMSG(idx < kMaxSigScalars);
  687. return idx;
  688. }
  689. void DxilViewIdState::UpdateDynamicIndexUsageState() const {
  690. UpdateDynamicIndexUsageStateForSig(m_pModule->GetInputSignature(), m_InpSigDynIdxElems);
  691. UpdateDynamicIndexUsageStateForSig(m_pModule->GetOutputSignature(), m_OutSigDynIdxElems);
  692. UpdateDynamicIndexUsageStateForSig(m_pModule->GetPatchConstantSignature(), m_PCSigDynIdxElems);
  693. }
  694. void DxilViewIdState::UpdateDynamicIndexUsageStateForSig(DxilSignature &Sig,
  695. const DynamicallyIndexedElemsType &DynIdxElems) const {
  696. for (auto it : DynIdxElems) {
  697. unsigned id = it.first;
  698. unsigned mask = it.second;
  699. DxilSignatureElement &E = Sig.GetElement(id);
  700. E.SetDynIdxCompMask(mask);
  701. }
  702. }
  703. static unsigned RoundUpToUINT(unsigned x) {
  704. return (x + 31)/32;
  705. }
  706. void DxilViewIdState::Serialize() {
  707. const ShaderModel *pSM = m_pModule->GetShaderModel();
  708. m_SerializedState.clear();
  709. // Compute serialized state size in UINTs.
  710. unsigned NumInputs = getNumInputSigScalars();
  711. unsigned NumStreams = pSM->IsGS()? kNumStreams : 1;
  712. unsigned Size = 0;
  713. Size += 1; // #Inputs.
  714. for (unsigned StreamId = 0; StreamId < NumStreams; StreamId++) {
  715. Size += 1; // #Outputs for stream StreamId.
  716. unsigned NumOutputs = getNumOutputSigScalars(StreamId);
  717. unsigned NumOutUINTs = RoundUpToUINT(NumOutputs);
  718. if (m_bUsesViewId) {
  719. Size += NumOutUINTs; // m_OutputsDependentOnViewId[StreamId]
  720. }
  721. Size += NumInputs * NumOutUINTs; // m_InputsContributingToOutputs[StreamId]
  722. }
  723. if (pSM->IsHS() || pSM->IsDS()) {
  724. Size += 1; // #PatchConstant.
  725. unsigned NumPCs = getNumPCSigScalars();
  726. unsigned NumPCUINTs = RoundUpToUINT(NumPCs);
  727. if (pSM->IsHS()) {
  728. if (m_bUsesViewId) {
  729. Size += NumPCUINTs; // m_PCOutputsDependentOnViewId
  730. }
  731. Size += NumInputs * NumPCUINTs; // m_InputsContributingToPCOutputs
  732. } else {
  733. unsigned NumOutputs = getNumOutputSigScalars(0);
  734. unsigned NumOutUINTs = RoundUpToUINT(NumOutputs);
  735. Size += NumPCs * NumOutUINTs; // m_PCInputsContributingToOutputs
  736. }
  737. }
  738. m_SerializedState.resize(Size);
  739. std::fill(m_SerializedState.begin(), m_SerializedState.end(), 0u);
  740. // Serialize ViewId state.
  741. unsigned *pData = &m_SerializedState[0];
  742. *pData++ = NumInputs;
  743. for (unsigned StreamId = 0; StreamId < NumStreams; StreamId++) {
  744. unsigned NumOutputs = getNumOutputSigScalars(StreamId);
  745. *pData++ = NumOutputs;
  746. if (m_bUsesViewId) {
  747. SerializeOutputsDependentOnViewId(NumOutputs, m_OutputsDependentOnViewId[StreamId], pData);
  748. }
  749. SerializeInputsContributingToOutput(NumInputs, NumOutputs, m_InputsContributingToOutputs[StreamId], pData);
  750. }
  751. if (pSM->IsHS() || pSM->IsDS()) {
  752. unsigned NumPCs = getNumPCSigScalars();
  753. *pData++ = NumPCs;
  754. if (pSM->IsHS()) {
  755. if (m_bUsesViewId) {
  756. SerializeOutputsDependentOnViewId(NumPCs, m_PCOutputsDependentOnViewId, pData);
  757. }
  758. SerializeInputsContributingToOutput(NumInputs, NumPCs, m_InputsContributingToPCOutputs, pData);
  759. } else {
  760. unsigned NumOutputs = getNumOutputSigScalars(0);
  761. SerializeInputsContributingToOutput(NumPCs, NumOutputs, m_PCInputsContributingToOutputs, pData);
  762. }
  763. }
  764. DXASSERT_NOMSG(pData == (&m_SerializedState[0] + Size));
  765. }
  766. const vector<unsigned> &DxilViewIdState::GetSerialized() {
  767. if (m_SerializedState.empty())
  768. Serialize();
  769. return m_SerializedState;
  770. }
  771. const vector<unsigned> &DxilViewIdState::GetSerialized() const {
  772. return m_SerializedState;
  773. }
  774. void DxilViewIdState::SerializeOutputsDependentOnViewId(unsigned NumOutputs,
  775. const OutputsDependentOnViewIdType &OutputsDependentOnViewId,
  776. unsigned *&pData) {
  777. unsigned NumOutUINTs = RoundUpToUINT(NumOutputs);
  778. // Serialize output dependence on ViewId.
  779. for (unsigned i = 0; i < NumOutUINTs; i++) {
  780. unsigned x = 0;
  781. for (unsigned j = 0; j < std::min(32u, NumOutputs - 32u*i); j++) {
  782. if (OutputsDependentOnViewId[i*32 + j]) {
  783. x |= (1u << j);
  784. }
  785. }
  786. *pData++ = x;
  787. }
  788. }
  789. void DxilViewIdState::SerializeInputsContributingToOutput(unsigned NumInputs, unsigned NumOutputs,
  790. const InputsContributingToOutputType &InputsContributingToOutputs,
  791. unsigned *&pData) {
  792. unsigned NumOutUINTs = RoundUpToUINT(NumOutputs);
  793. // Serialize output dependence on inputs.
  794. for (unsigned outputIdx = 0; outputIdx < NumOutputs; outputIdx++) {
  795. auto it = InputsContributingToOutputs.find(outputIdx);
  796. if (it != InputsContributingToOutputs.end()) {
  797. for (unsigned inputIdx : it->second) {
  798. unsigned w = outputIdx / 32;
  799. unsigned b = outputIdx % 32;
  800. pData[inputIdx*NumOutUINTs + w] |= (1u << b);
  801. }
  802. }
  803. }
  804. pData += NumInputs * NumOutUINTs;
  805. }
  806. void DxilViewIdState::Deserialize(const unsigned *pData, unsigned DataSizeInUINTs) {
  807. Clear();
  808. m_SerializedState.resize(DataSizeInUINTs);
  809. memcpy(m_SerializedState.data(), pData, DataSizeInUINTs * sizeof(unsigned));
  810. const ShaderModel *pSM = m_pModule->GetShaderModel();
  811. m_bUsesViewId = m_pModule->m_ShaderFlags.GetViewID();
  812. unsigned ConsumedUINTs = 0;
  813. IFTBOOL(DataSizeInUINTs-ConsumedUINTs >= 1, DXC_E_GENERAL_INTERNAL_ERROR);
  814. unsigned NumInputs = pData[ConsumedUINTs++];
  815. m_NumInputSigScalars = NumInputs;
  816. unsigned NumStreams = pSM->IsGS()? kNumStreams : 1;
  817. for (unsigned StreamId = 0; StreamId < NumStreams; StreamId++) {
  818. IFTBOOL(DataSizeInUINTs-ConsumedUINTs >= 1, DXC_E_GENERAL_INTERNAL_ERROR);
  819. unsigned NumOutputs = pData[ConsumedUINTs++];
  820. m_NumOutputSigScalars[StreamId] = NumOutputs;
  821. if (m_bUsesViewId) {
  822. ConsumedUINTs += DeserializeOutputsDependentOnViewId(NumOutputs,
  823. m_OutputsDependentOnViewId[StreamId],
  824. &pData[ConsumedUINTs],
  825. DataSizeInUINTs-ConsumedUINTs);
  826. }
  827. ConsumedUINTs += DeserializeInputsContributingToOutput(NumInputs, NumOutputs,
  828. m_InputsContributingToOutputs[StreamId],
  829. &pData[ConsumedUINTs],
  830. DataSizeInUINTs-ConsumedUINTs);
  831. }
  832. if (pSM->IsHS() || pSM->IsDS()) {
  833. IFTBOOL(DataSizeInUINTs-ConsumedUINTs >= 1, DXC_E_GENERAL_INTERNAL_ERROR);
  834. unsigned NumPCs = pData[ConsumedUINTs++];
  835. m_NumPCSigScalars = NumPCs;
  836. if (pSM->IsHS()) {
  837. if (m_bUsesViewId) {
  838. ConsumedUINTs += DeserializeOutputsDependentOnViewId(NumPCs,
  839. m_PCOutputsDependentOnViewId,
  840. &pData[ConsumedUINTs],
  841. DataSizeInUINTs-ConsumedUINTs);
  842. }
  843. ConsumedUINTs += DeserializeInputsContributingToOutput(NumInputs, NumPCs,
  844. m_InputsContributingToPCOutputs,
  845. &pData[ConsumedUINTs],
  846. DataSizeInUINTs-ConsumedUINTs);
  847. } else {
  848. unsigned NumOutputs = getNumOutputSigScalars(0);
  849. ConsumedUINTs += DeserializeInputsContributingToOutput(NumPCs, NumOutputs,
  850. m_PCInputsContributingToOutputs,
  851. &pData[ConsumedUINTs],
  852. DataSizeInUINTs-ConsumedUINTs);
  853. }
  854. }
  855. DXASSERT_NOMSG(ConsumedUINTs == DataSizeInUINTs);
  856. }
  857. unsigned DxilViewIdState::DeserializeOutputsDependentOnViewId(unsigned NumOutputs,
  858. OutputsDependentOnViewIdType &OutputsDependentOnViewId,
  859. const unsigned *pData, unsigned DataSize) {
  860. unsigned NumOutUINTs = RoundUpToUINT(NumOutputs);
  861. IFTBOOL(NumOutUINTs <= DataSize, DXC_E_GENERAL_INTERNAL_ERROR);
  862. // Deserialize output dependence on ViewId.
  863. for (unsigned i = 0; i < NumOutUINTs; i++) {
  864. unsigned x = *pData++;
  865. for (unsigned j = 0; j < std::min(32u, NumOutputs - 32u*i); j++) {
  866. if (x & (1u << j)) {
  867. OutputsDependentOnViewId[i*32 + j] = true;
  868. }
  869. }
  870. }
  871. return NumOutUINTs;
  872. }
  873. unsigned DxilViewIdState::DeserializeInputsContributingToOutput(unsigned NumInputs, unsigned NumOutputs,
  874. InputsContributingToOutputType &InputsContributingToOutputs,
  875. const unsigned *pData, unsigned DataSize) {
  876. unsigned NumOutUINTs = RoundUpToUINT(NumOutputs);
  877. unsigned Size = NumInputs * NumOutUINTs;
  878. IFTBOOL(Size <= DataSize, DXC_E_GENERAL_INTERNAL_ERROR);
  879. // Deserialize output dependence on inputs.
  880. for (unsigned inputIdx = 0; inputIdx < NumInputs; inputIdx++) {
  881. for (unsigned outputIdx = 0; outputIdx < NumOutputs; outputIdx++) {
  882. unsigned w = outputIdx / 32;
  883. unsigned b = outputIdx % 32;
  884. if (pData[inputIdx*NumOutUINTs + w] & (1u << b)) {
  885. InputsContributingToOutputs[outputIdx].insert(inputIdx);
  886. }
  887. }
  888. }
  889. return Size;
  890. }
  891. char ComputeViewIdState::ID = 0;
  892. INITIALIZE_PASS_BEGIN(ComputeViewIdState, "viewid-state",
  893. "Compute information related to ViewID", true, true)
  894. INITIALIZE_PASS_END(ComputeViewIdState, "viewid-state",
  895. "Compute information related to ViewID", true, true)
  896. ComputeViewIdState::ComputeViewIdState() : ModulePass(ID) {
  897. }
  898. bool ComputeViewIdState::runOnModule(Module &M) {
  899. DxilModule &DxilModule = M.GetOrCreateDxilModule();
  900. const ShaderModel *pSM = DxilModule.GetShaderModel();
  901. if (!pSM->IsCS() && !pSM->IsLib()) {
  902. DxilViewIdState &ViewIdState = DxilModule.GetViewIdState();
  903. ViewIdState.Compute();
  904. return true;
  905. }
  906. return false;
  907. }
  908. void ComputeViewIdState::getAnalysisUsage(AnalysisUsage &AU) const {
  909. AU.setPreservesAll();
  910. }
  911. namespace llvm {
  912. ModulePass *createComputeViewIdStatePass() {
  913. return new ComputeViewIdState();
  914. }
  915. } // end of namespace llvm