ComputeViewIdState.cpp 41 KB

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