ComputeViewIdStateBuilder.cpp 34 KB

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