ComputeViewIdStateBuilder.cpp 37 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927
  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. BasicBlock *pBB = pContributingInst->getParent();
  447. Function *F = pBB->getParent();
  448. auto FuncInfoIt = m_FuncInfo.find(F);
  449. DXASSERT_NOMSG(FuncInfoIt != m_FuncInfo.end());
  450. if (FuncInfoIt == m_FuncInfo.end()) {
  451. return;
  452. }
  453. auto itInst = ContributingInstructions.emplace(pContributingInst);
  454. // Already visited instruction.
  455. if (!itInst.second) return;
  456. // Handle special cases.
  457. if (PHINode *phi = dyn_cast<PHINode>(pContributingInst)) {
  458. CollectPhiCFValuesContributingToOutputRec(phi, Entry, ContributingInstructions);
  459. } else if (isa<LoadInst>(pContributingInst) ||
  460. isa<AtomicCmpXchgInst>(pContributingInst) ||
  461. isa<AtomicRMWInst>(pContributingInst)) {
  462. Value *pPtrValue = pContributingInst->getOperand(0);
  463. DXASSERT_NOMSG(pPtrValue->getType()->isPointerTy());
  464. const ValueSetType &ReachingDecls = CollectReachingDecls(pPtrValue);
  465. DXASSERT_NOMSG(ReachingDecls.size() > 0);
  466. for (Value *pDeclValue : ReachingDecls) {
  467. const ValueSetType &Stores = CollectStores(pDeclValue);
  468. for (Value *V : Stores) {
  469. CollectValuesContributingToOutputRec(Entry, V, ContributingInstructions);
  470. }
  471. }
  472. } else if (CallInst *CI = dyn_cast<CallInst>(pContributingInst)) {
  473. if (!hlsl::OP::IsDxilOpFuncCallInst(CI)) {
  474. Function *F = CI->getCalledFunction();
  475. if (!F->empty()) {
  476. // Return value of a user function.
  477. if (Entry.Functions.find(F) != Entry.Functions.end()) {
  478. const FuncInfo &FI = *m_FuncInfo[F];
  479. for (ReturnInst *pRetInst : FI.Returns) {
  480. CollectValuesContributingToOutputRec(Entry, pRetInst, ContributingInstructions);
  481. }
  482. }
  483. }
  484. }
  485. }
  486. // Handle instruction inputs.
  487. unsigned NumOps = pContributingInst->getNumOperands();
  488. for (unsigned i = 0; i < NumOps; i++) {
  489. Value *O = pContributingInst->getOperand(i);
  490. CollectValuesContributingToOutputRec(Entry, O, ContributingInstructions);
  491. }
  492. // Handle control dependence of this instruction BB.
  493. FuncInfo *pFuncInfo = FuncInfoIt->second.get();
  494. const BasicBlockSet &CtrlDepSet = pFuncInfo->CtrlDep.GetCDBlocks(pBB);
  495. for (BasicBlock *B : CtrlDepSet) {
  496. CollectValuesContributingToOutputRec(Entry, B->getTerminator(), ContributingInstructions);
  497. }
  498. }
  499. // Only process control-dependent basic blocks for constant operands of the phi-function.
  500. // An obvious "definition" point for a constant operand is the predecessor along corresponding edge.
  501. // However, this may be too conservative and, as such, pick up extra control dependent BBs.
  502. // A better "definition" point is the highest dominator where it is still legal to "insert" constant assignment.
  503. // In this context, "legal" means that only one value "leaves" the dominator and reaches Phi.
  504. void DxilViewIdStateBuilder::CollectPhiCFValuesContributingToOutputRec(PHINode *pPhi,
  505. EntryInfo &Entry,
  506. InstructionSetType &ContributingInstructions) {
  507. Function *F = pPhi->getParent()->getParent();
  508. FuncInfo *pFuncInfo = m_FuncInfo[F].get();
  509. unordered_map<DomTreeNodeBase<BasicBlock> *, Value *> DomTreeMarkers;
  510. // Mark predecessors of each value, so that there is a legal "definition" point.
  511. for (unsigned i = 0; i < pPhi->getNumOperands(); i++) {
  512. Value *pValue = pPhi->getIncomingValue(i);
  513. BasicBlock *pBB = pPhi->getIncomingBlock(i);
  514. DomTreeNodeBase<BasicBlock> *pDomNode = pFuncInfo->pDomTree->getNode(pBB);
  515. auto it = DomTreeMarkers.emplace(pDomNode, pValue);
  516. DXASSERT_NOMSG(it.second || it.first->second == pValue); (void)it;
  517. }
  518. // Mark the dominator tree with "definition" values, walking up to the parent.
  519. for (unsigned i = 0; i < pPhi->getNumOperands(); i++) {
  520. Value *pValue = pPhi->getIncomingValue(i);
  521. BasicBlock *pDefBB = &F->getEntryBlock();
  522. if (Instruction *pDefInst = dyn_cast<Instruction>(pValue)) {
  523. pDefBB = pDefInst->getParent();
  524. }
  525. BasicBlock *pBB = pPhi->getIncomingBlock(i);
  526. if (pBB == pDefBB) {
  527. continue; // we already handled the predecessor.
  528. }
  529. DomTreeNodeBase<BasicBlock> *pDomNode = pFuncInfo->pDomTree->getNode(pBB);
  530. pDomNode = pDomNode->getIDom();
  531. while (pDomNode) {
  532. auto it = DomTreeMarkers.emplace(pDomNode, pValue);
  533. if (!it.second) {
  534. if (it.first->second != pValue && it.first->second != nullptr) {
  535. if (!isa<Constant>(it.first->second) || !isa<Constant>(pValue)) {
  536. // Unless both are different constants, mark the "definition" point as illegal.
  537. it.first->second = nullptr;
  538. // If both are constants, leave the marker of the first one.
  539. }
  540. }
  541. break;
  542. }
  543. // Do not go higher than a legal definition point.
  544. pBB = pDomNode->getBlock();
  545. if (pBB == pDefBB)
  546. break;
  547. pDomNode = pDomNode->getIDom();
  548. }
  549. }
  550. // Handle control dependence for Constant arguments of Phi.
  551. for (unsigned i = 0; i < pPhi->getNumOperands(); i++) {
  552. Value *pValue = pPhi->getIncomingValue(i);
  553. if (!isa<Constant>(pValue))
  554. continue;
  555. // Determine the higher legal "definition" point.
  556. BasicBlock *pBB = pPhi->getIncomingBlock(i);
  557. DomTreeNodeBase<BasicBlock> *pDomNode = pFuncInfo->pDomTree->getNode(pBB);
  558. DomTreeNodeBase<BasicBlock> *pDefDomNode = pDomNode;
  559. while (pDomNode) {
  560. auto it = DomTreeMarkers.find(pDomNode);
  561. DXASSERT_NOMSG(it != DomTreeMarkers.end());
  562. if (it->second != pValue) {
  563. DXASSERT_NOMSG(it->second == nullptr || isa<Constant>(it->second));
  564. break;
  565. }
  566. pDefDomNode = pDomNode;
  567. pDomNode = pDomNode->getIDom();
  568. }
  569. // Handle control dependence of this constant argument highest legal "definition" point.
  570. pBB = pDefDomNode->getBlock();
  571. const BasicBlockSet &CtrlDepSet = pFuncInfo->CtrlDep.GetCDBlocks(pBB);
  572. for (BasicBlock *B : CtrlDepSet) {
  573. CollectValuesContributingToOutputRec(Entry, B->getTerminator(), ContributingInstructions);
  574. }
  575. }
  576. }
  577. const DxilViewIdStateBuilder::ValueSetType &DxilViewIdStateBuilder::CollectReachingDecls(Value *pValue) {
  578. auto it = m_ReachingDeclsCache.emplace(pValue, ValueSetType());
  579. if (it.second) {
  580. // We have not seen this value before.
  581. ValueSetType Visited;
  582. CollectReachingDeclsRec(pValue, it.first->second, Visited);
  583. }
  584. return it.first->second;
  585. }
  586. void DxilViewIdStateBuilder::CollectReachingDeclsRec(Value *pValue, ValueSetType &ReachingDecls, ValueSetType &Visited) {
  587. if (Visited.find(pValue) != Visited.end())
  588. return;
  589. bool bInitialValue = Visited.size() == 0;
  590. Visited.emplace(pValue);
  591. if (!bInitialValue) {
  592. auto it = m_ReachingDeclsCache.find(pValue);
  593. if (it != m_ReachingDeclsCache.end()) {
  594. ReachingDecls.insert(it->second.begin(), it->second.end());
  595. return;
  596. }
  597. }
  598. if (dyn_cast<GlobalVariable>(pValue)) {
  599. ReachingDecls.emplace(pValue);
  600. return;
  601. }
  602. if (GetElementPtrInst *pGepInst = dyn_cast<GetElementPtrInst>(pValue)) {
  603. Value *pPtrValue = pGepInst->getPointerOperand();
  604. CollectReachingDeclsRec(pPtrValue, ReachingDecls, Visited);
  605. } else if (GEPOperator *pGepOp = dyn_cast<GEPOperator>(pValue)) {
  606. Value *pPtrValue = pGepOp->getPointerOperand();
  607. CollectReachingDeclsRec(pPtrValue, ReachingDecls, Visited);
  608. } else if (isa<ConstantExpr>(pValue) && cast<ConstantExpr>(pValue)->getOpcode() == Instruction::AddrSpaceCast) {
  609. CollectReachingDeclsRec(cast<ConstantExpr>(pValue)->getOperand(0), ReachingDecls, Visited);
  610. } else if (AddrSpaceCastInst *pCI = dyn_cast<AddrSpaceCastInst>(pValue)) {
  611. CollectReachingDeclsRec(pCI->getOperand(0), ReachingDecls, Visited);
  612. } else if (BitCastInst *pCI = dyn_cast<BitCastInst>(pValue)) {
  613. CollectReachingDeclsRec(pCI->getOperand(0), ReachingDecls, Visited);
  614. } else if (dyn_cast<AllocaInst>(pValue)) {
  615. ReachingDecls.emplace(pValue);
  616. } else if (PHINode *phi = dyn_cast<PHINode>(pValue)) {
  617. for (Value *pPtrValue : phi->operands()) {
  618. CollectReachingDeclsRec(pPtrValue, ReachingDecls, Visited);
  619. }
  620. } else if (SelectInst *SelI = dyn_cast<SelectInst>(pValue)) {
  621. CollectReachingDeclsRec(SelI->getTrueValue(), ReachingDecls, Visited);
  622. CollectReachingDeclsRec(SelI->getFalseValue(), ReachingDecls, Visited);
  623. } else if (dyn_cast<Argument>(pValue)) {
  624. ReachingDecls.emplace(pValue);
  625. } else if (CallInst *call = dyn_cast<CallInst>(pValue)) {
  626. DXASSERT(OP::GetDxilOpFuncCallInst(call) == DXIL::OpCode::GetMeshPayload,
  627. "the function must be @dx.op.getMeshPayload here.");
  628. ReachingDecls.emplace(pValue);
  629. } else {
  630. IFT(DXC_E_GENERAL_INTERNAL_ERROR);
  631. }
  632. }
  633. const DxilViewIdStateBuilder::ValueSetType &DxilViewIdStateBuilder::CollectStores(llvm::Value *pValue) {
  634. auto it = m_StoresPerDeclCache.emplace(pValue, ValueSetType());
  635. if (it.second) {
  636. // We have not seen this value before.
  637. ValueSetType Visited;
  638. CollectStoresRec(pValue, it.first->second, Visited);
  639. }
  640. return it.first->second;
  641. }
  642. void DxilViewIdStateBuilder::CollectStoresRec(llvm::Value *pValue, ValueSetType &Stores, ValueSetType &Visited) {
  643. if (Visited.find(pValue) != Visited.end())
  644. return;
  645. bool bInitialValue = Visited.size() == 0;
  646. Visited.emplace(pValue);
  647. if (!bInitialValue) {
  648. auto it = m_StoresPerDeclCache.find(pValue);
  649. if (it != m_StoresPerDeclCache.end()) {
  650. Stores.insert(it->second.begin(), it->second.end());
  651. return;
  652. }
  653. }
  654. if (isa<LoadInst>(pValue)) {
  655. return;
  656. } else if (isa<StoreInst>(pValue) ||
  657. isa<AtomicCmpXchgInst>(pValue) ||
  658. isa<AtomicRMWInst>(pValue)) {
  659. Stores.emplace(pValue);
  660. return;
  661. }
  662. for (auto *U : pValue->users()) {
  663. CollectStoresRec(U, Stores, Visited);
  664. }
  665. }
  666. void DxilViewIdStateBuilder::CreateViewIdSets(const std::unordered_map<unsigned, InstructionSetType> &ContributingInstructions,
  667. OutputsDependentOnViewIdType &OutputsDependentOnViewId,
  668. InputsContributingToOutputType &InputsContributingToOutputs,
  669. bool bPC) {
  670. const ShaderModel *pSM = m_pModule->GetShaderModel();
  671. for (auto &itOut : ContributingInstructions) {
  672. unsigned outIdx = itOut.first;
  673. for (Instruction *pInst : itOut.second) {
  674. // Set output dependence on ViewId.
  675. if (DxilInst_ViewID VID = DxilInst_ViewID(pInst)) {
  676. DXASSERT(m_bUsesViewId, "otherwise, DxilModule flag not set properly");
  677. OutputsDependentOnViewId[outIdx] = true;
  678. continue;
  679. }
  680. // Start setting output dependence on inputs.
  681. DxilSignatureElement *pSigElem = nullptr;
  682. bool bLoadOutputCPInHS = false;
  683. unsigned inpId = (unsigned)-1;
  684. int startRow = Semantic::kUndefinedRow, endRow = Semantic::kUndefinedRow;
  685. unsigned col = (unsigned)-1;
  686. if (DxilInst_LoadInput LI = DxilInst_LoadInput(pInst)) {
  687. GetUnsignedVal(LI.get_inputSigId(), &inpId);
  688. GetUnsignedVal(LI.get_colIndex(), &col);
  689. GetUnsignedVal(LI.get_rowIndex(), (uint32_t*)&startRow);
  690. pSigElem = &m_pModule->GetInputSignature().GetElement(inpId);
  691. if (pSM->IsDS() && bPC) {
  692. pSigElem = nullptr;
  693. }
  694. } else if (DxilInst_LoadOutputControlPoint LOCP = DxilInst_LoadOutputControlPoint(pInst)) {
  695. GetUnsignedVal(LOCP.get_inputSigId(), &inpId);
  696. GetUnsignedVal(LOCP.get_col(), &col);
  697. GetUnsignedVal(LOCP.get_row(), (uint32_t*)&startRow);
  698. if (pSM->IsHS()) {
  699. pSigElem = &m_pModule->GetOutputSignature().GetElement(inpId);
  700. bLoadOutputCPInHS = true;
  701. } else if (pSM->IsDS()) {
  702. if (!bPC) {
  703. pSigElem = &m_pModule->GetInputSignature().GetElement(inpId);
  704. }
  705. } else {
  706. DXASSERT_NOMSG(false);
  707. }
  708. } else if (DxilInst_LoadPatchConstant LPC = DxilInst_LoadPatchConstant(pInst)) {
  709. if (pSM->IsDS() && bPC) {
  710. GetUnsignedVal(LPC.get_inputSigId(), &inpId);
  711. GetUnsignedVal(LPC.get_col(), &col);
  712. GetUnsignedVal(LPC.get_row(), (uint32_t*)&startRow);
  713. pSigElem = &m_pModule->GetPatchConstOrPrimSignature().GetElement(inpId);
  714. }
  715. } else {
  716. continue;
  717. }
  718. // Finalize setting output dependence on inputs.
  719. if (pSigElem && pSigElem->IsAllocated()) {
  720. if (startRow != Semantic::kUndefinedRow) {
  721. endRow = startRow;
  722. } else {
  723. // The entire column contributes to output.
  724. startRow = 0;
  725. endRow = pSigElem->GetRows() - 1;
  726. }
  727. auto &ContributingInputs = InputsContributingToOutputs[outIdx];
  728. for (int row = startRow; row <= endRow; row++) {
  729. unsigned index = GetLinearIndex(*pSigElem, row, col);
  730. if (!bLoadOutputCPInHS) {
  731. ContributingInputs.emplace(index);
  732. } else {
  733. // This HS patch-constant output depends on an input value of LoadOutputControlPoint
  734. // that is the output value of the HS main (control-point) function.
  735. // Transitively update this (patch-constant) output dependence on main (control-point) output.
  736. DXASSERT_NOMSG(&OutputsDependentOnViewId == &m_PCOrPrimOutputsDependentOnViewId);
  737. OutputsDependentOnViewId[outIdx] = OutputsDependentOnViewId[outIdx] || m_OutputsDependentOnViewId[0][index];
  738. const auto it = m_InputsContributingToOutputs[0].find(index);
  739. if (it != m_InputsContributingToOutputs[0].end()) {
  740. const std::set<unsigned> &LoadOutputCPInputsContributingToOutputs = it->second;
  741. ContributingInputs.insert(LoadOutputCPInputsContributingToOutputs.begin(),
  742. LoadOutputCPInputsContributingToOutputs.end());
  743. }
  744. }
  745. }
  746. }
  747. }
  748. }
  749. }
  750. unsigned DxilViewIdStateBuilder::GetLinearIndex(DxilSignatureElement &SigElem, int row, unsigned col) const {
  751. DXASSERT_NOMSG(row >= 0 && col < kNumComps && SigElem.GetStartRow() != Semantic::kUndefinedRow);
  752. unsigned idx = (((unsigned)row) + SigElem.GetStartRow())*kNumComps + col + SigElem.GetStartCol();
  753. DXASSERT_NOMSG(idx < kMaxSigScalars); (void)kMaxSigScalars;
  754. return idx;
  755. }
  756. void DxilViewIdStateBuilder::UpdateDynamicIndexUsageState() const {
  757. UpdateDynamicIndexUsageStateForSig(m_pModule->GetInputSignature(), m_InpSigDynIdxElems);
  758. UpdateDynamicIndexUsageStateForSig(m_pModule->GetOutputSignature(), m_OutSigDynIdxElems);
  759. UpdateDynamicIndexUsageStateForSig(m_pModule->GetPatchConstOrPrimSignature(), m_PCSigDynIdxElems);
  760. }
  761. void DxilViewIdStateBuilder::UpdateDynamicIndexUsageStateForSig(DxilSignature &Sig,
  762. const DynamicallyIndexedElemsType &DynIdxElems) const {
  763. for (auto it : DynIdxElems) {
  764. unsigned id = it.first;
  765. unsigned mask = it.second;
  766. DxilSignatureElement &E = Sig.GetElement(id);
  767. E.SetDynIdxCompMask(mask);
  768. }
  769. }
  770. namespace {
  771. class ComputeViewIdState : public ModulePass {
  772. public:
  773. static char ID; // Pass ID, replacement for typeid
  774. ComputeViewIdState();
  775. bool runOnModule(Module &M) override;
  776. void getAnalysisUsage(AnalysisUsage &AU) const override;
  777. };
  778. } // namespace
  779. char ComputeViewIdState::ID = 0;
  780. INITIALIZE_PASS_BEGIN(ComputeViewIdState, "viewid-state",
  781. "Compute information related to ViewID", true, true)
  782. INITIALIZE_PASS_END(ComputeViewIdState, "viewid-state",
  783. "Compute information related to ViewID", true, true)
  784. ComputeViewIdState::ComputeViewIdState() : ModulePass(ID) {
  785. }
  786. bool ComputeViewIdState::runOnModule(Module &M) {
  787. DxilModule &DxilModule = M.GetOrCreateDxilModule();
  788. const ShaderModel *pSM = DxilModule.GetShaderModel();
  789. if (!pSM->IsCS() && !pSM->IsLib()) {
  790. DxilViewIdState ViewIdState(&DxilModule);
  791. DxilViewIdStateBuilder Builder(ViewIdState, &DxilModule);
  792. Builder.Compute();
  793. // Serialize viewidstate.
  794. ViewIdState.Serialize();
  795. auto &TmpSerialized = ViewIdState.GetSerialized();
  796. // Copy serilized viewidstate.
  797. auto &SerializedViewIdState = DxilModule.GetSerializedViewIdState();
  798. SerializedViewIdState.clear();
  799. SerializedViewIdState.resize(TmpSerialized.size());
  800. SerializedViewIdState.assign(TmpSerialized.begin(), TmpSerialized.end());
  801. return true;
  802. }
  803. return false;
  804. }
  805. void ComputeViewIdState::getAnalysisUsage(AnalysisUsage &AU) const {
  806. AU.setPreservesAll();
  807. }
  808. namespace llvm {
  809. ModulePass *createComputeViewIdStatePass() {
  810. return new ComputeViewIdState();
  811. }
  812. } // end of namespace llvm