ComputeViewIdStateBuilder.cpp 37 KB

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