123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927 |
- ///////////////////////////////////////////////////////////////////////////////
- // //
- // ComputeViewIdStateBuilder.cpp //
- // Copyright (C) Microsoft Corporation. All rights reserved. //
- // This file is distributed under the University of Illinois Open Source //
- // License. See LICENSE.TXT for details. //
- // //
- ///////////////////////////////////////////////////////////////////////////////
- #include "dxc/HlslIntrinsicOp.h"
- #include "dxc/HLSL/ComputeViewIdState.h"
- #include "dxc/HLSL/HLOperations.h"
- #include "dxc/Support/Global.h"
- #include "dxc/DXIL/DxilModule.h"
- #include "dxc/DXIL/DxilOperations.h"
- #include "dxc/DXIL/DxilInstructions.h"
- #include "llvm/IR/LLVMContext.h"
- #include "llvm/IR/Module.h"
- #include "llvm/IR/Function.h"
- #include "llvm/IR/Operator.h"
- #include "llvm/Pass.h"
- #include "llvm/IR/LegacyPassManager.h"
- #include "llvm/Support/Debug.h"
- #include "llvm/IR/CFG.h"
- #include "llvm/Analysis/CallGraph.h"
- #include <algorithm>
- using namespace llvm;
- using namespace llvm::legacy;
- using namespace hlsl;
- using llvm::legacy::PassManager;
- using llvm::legacy::FunctionPassManager;
- using std::vector;
- using std::unordered_set;
- using std::unordered_map;
- #define DXILVIEWID_DBG 0
- #define DEBUG_TYPE "viewid_builder"
- namespace {
- class DxilViewIdStateBuilder {
- static const unsigned kNumComps = 4;
- static const unsigned kMaxSigScalars = 32 * 4;
- public:
- using OutputsDependentOnViewIdType = DxilViewIdStateData::OutputsDependentOnViewIdType;
- using InputsContributingToOutputType = DxilViewIdStateData::InputsContributingToOutputType;
- DxilViewIdStateBuilder(DxilViewIdStateData &state, DxilModule *pDxilModule)
- : m_pModule(pDxilModule),
- m_NumInputSigScalars(state.m_NumInputSigScalars),
- m_NumOutputSigScalars(state.m_NumOutputSigScalars,
- DxilViewIdStateData::kNumStreams),
- m_NumPCOrPrimSigScalars(state.m_NumPCOrPrimSigScalars),
- m_OutputsDependentOnViewId(state.m_OutputsDependentOnViewId,
- DxilViewIdStateData::kNumStreams),
- m_PCOrPrimOutputsDependentOnViewId(state.m_PCOrPrimOutputsDependentOnViewId),
- m_InputsContributingToOutputs(state.m_InputsContributingToOutputs,
- DxilViewIdStateData::kNumStreams),
- m_InputsContributingToPCOrPrimOutputs(state.m_InputsContributingToPCOrPrimOutputs),
- m_PCInputsContributingToOutputs(state.m_PCInputsContributingToOutputs),
- m_bUsesViewId(state.m_bUsesViewId) {}
- void Compute();
- private:
- static const unsigned kNumStreams = 4;
- DxilModule *m_pModule;
- unsigned &m_NumInputSigScalars;
- MutableArrayRef<unsigned> m_NumOutputSigScalars;
- unsigned &m_NumPCOrPrimSigScalars;
- // Set of scalar outputs dependent on ViewID.
- MutableArrayRef<OutputsDependentOnViewIdType> m_OutputsDependentOnViewId;
- OutputsDependentOnViewIdType &m_PCOrPrimOutputsDependentOnViewId;
- // Set of scalar inputs contributing to computation of scalar outputs.
- MutableArrayRef<InputsContributingToOutputType> m_InputsContributingToOutputs;
- InputsContributingToOutputType &m_InputsContributingToPCOrPrimOutputs; // HS PC and MS Prim only.
- InputsContributingToOutputType &m_PCInputsContributingToOutputs; // DS only.
- bool &m_bUsesViewId;
- // Members for build ViewIdState.
- // Dynamically indexed components of signature elements.
- using DynamicallyIndexedElemsType = std::unordered_map<unsigned, unsigned>;
- DynamicallyIndexedElemsType m_InpSigDynIdxElems;
- DynamicallyIndexedElemsType m_OutSigDynIdxElems;
- DynamicallyIndexedElemsType m_PCSigDynIdxElems;
- // Information per entry point.
- using FunctionSetType = std::unordered_set<llvm::Function *>;
- using InstructionSetType = std::unordered_set<llvm::Instruction *>;
- struct EntryInfo {
- llvm::Function *pEntryFunc = nullptr;
- // Sets of functions that may be reachable from an entry.
- FunctionSetType Functions;
- // Outputs to analyze.
- InstructionSetType Outputs;
- // Contributing instructions per output.
- std::unordered_map<unsigned, InstructionSetType>
- ContributingInstructions[kNumStreams];
- void Clear();
- };
- EntryInfo m_Entry;
- EntryInfo m_PCEntry;
- // Information per function.
- using FunctionReturnSet = std::unordered_set<llvm::ReturnInst *>;
- struct FuncInfo {
- FunctionReturnSet Returns;
- ControlDependence CtrlDep;
- std::unique_ptr<llvm::DominatorTreeBase<llvm::BasicBlock>> pDomTree;
- void Clear();
- };
- std::unordered_map<llvm::Function *, std::unique_ptr<FuncInfo>> m_FuncInfo;
- // Cache of decls (global/alloca) reaching a pointer value.
- using ValueSetType = std::unordered_set<llvm::Value *>;
- std::unordered_map<llvm::Value *, ValueSetType> m_ReachingDeclsCache;
- // Cache of stores for each decl.
- std::unordered_map<llvm::Value *, ValueSetType> m_StoresPerDeclCache;
- void Clear();
- void DetermineMaxPackedLocation(DxilSignature &DxilSig, unsigned *pMaxSigLoc,
- unsigned NumStreams);
- void ComputeReachableFunctionsRec(llvm::CallGraph &CG,
- llvm::CallGraphNode *pNode,
- FunctionSetType &FuncSet);
- void AnalyzeFunctions(EntryInfo &Entry);
- void CollectValuesContributingToOutputs(EntryInfo &Entry);
- void CollectValuesContributingToOutputRec(
- EntryInfo &Entry, llvm::Value *pContributingValue,
- InstructionSetType &ContributingInstructions);
- void CollectPhiCFValuesContributingToOutputRec(
- llvm::PHINode *pPhi, EntryInfo &Entry,
- InstructionSetType &ContributingInstructions);
- const ValueSetType &CollectReachingDecls(llvm::Value *pValue);
- void CollectReachingDeclsRec(llvm::Value *pValue, ValueSetType &ReachingDecls,
- ValueSetType &Visited);
- const ValueSetType &CollectStores(llvm::Value *pValue);
- void CollectStoresRec(llvm::Value *pValue, ValueSetType &Stores,
- ValueSetType &Visited);
- void UpdateDynamicIndexUsageState() const;
- void
- CreateViewIdSets(const std::unordered_map<unsigned, InstructionSetType>
- &ContributingInstructions,
- OutputsDependentOnViewIdType &OutputsDependentOnViewId,
- InputsContributingToOutputType &InputsContributingToOutputs,
- bool bPC);
- void UpdateDynamicIndexUsageStateForSig(
- DxilSignature &Sig, const DynamicallyIndexedElemsType &DynIdxElems) const;
- unsigned GetLinearIndex(DxilSignatureElement &SigElem, int row,
- unsigned col) const;
- };
- } // namespace
- void DxilViewIdStateBuilder::Compute() {
- Clear();
- const ShaderModel *pSM = m_pModule->GetShaderModel();
- m_bUsesViewId = m_pModule->m_ShaderFlags.GetViewID();
- // 1. Traverse signature MD to determine max packed location.
- DetermineMaxPackedLocation(m_pModule->GetInputSignature(), &m_NumInputSigScalars, 1);
- DetermineMaxPackedLocation(m_pModule->GetOutputSignature(), &m_NumOutputSigScalars[0], pSM->IsGS() ? kNumStreams : 1);
- DetermineMaxPackedLocation(m_pModule->GetPatchConstOrPrimSignature(), &m_NumPCOrPrimSigScalars, 1);
- // 2. Collect sets of functions reachable from main and pc entries.
- CallGraphAnalysis CGA;
- CallGraph CG = CGA.run(m_pModule->GetModule());
- m_Entry.pEntryFunc = m_pModule->GetEntryFunction();
- m_PCEntry.pEntryFunc = m_pModule->GetPatchConstantFunction();
- ComputeReachableFunctionsRec(CG, CG[m_Entry.pEntryFunc], m_Entry.Functions);
- if (m_PCEntry.pEntryFunc) {
- DXASSERT_NOMSG(pSM->IsHS());
- ComputeReachableFunctionsRec(CG, CG[m_PCEntry.pEntryFunc], m_PCEntry.Functions);
- }
- // 3. Determine shape components that are dynamically accesses and collect all sig outputs.
- AnalyzeFunctions(m_Entry);
- if (m_PCEntry.pEntryFunc) {
- AnalyzeFunctions(m_PCEntry);
- }
- // 4. Collect sets of values contributing to outputs.
- CollectValuesContributingToOutputs(m_Entry);
- if (m_PCEntry.pEntryFunc) {
- CollectValuesContributingToOutputs(m_PCEntry);
- }
- // 5. Construct dependency sets.
- for (unsigned StreamId = 0; StreamId < (pSM->IsGS() ? kNumStreams : 1u); StreamId++) {
- CreateViewIdSets(m_Entry.ContributingInstructions[StreamId],
- m_OutputsDependentOnViewId[StreamId],
- m_InputsContributingToOutputs[StreamId], false);
- }
- if (pSM->IsHS() || pSM->IsMS()) {
- CreateViewIdSets(m_PCEntry.ContributingInstructions[0],
- m_PCOrPrimOutputsDependentOnViewId,
- m_InputsContributingToPCOrPrimOutputs, true);
- } else if (pSM->IsDS()) {
- OutputsDependentOnViewIdType OutputsDependentOnViewId;
- CreateViewIdSets(m_Entry.ContributingInstructions[0],
- OutputsDependentOnViewId,
- m_PCInputsContributingToOutputs, true);
- DXASSERT_NOMSG(OutputsDependentOnViewId == m_OutputsDependentOnViewId[0]);
- }
- // 6. Update dynamically indexed input/output component masks.
- UpdateDynamicIndexUsageState();
- #if DXILVIEWID_DBG
- PrintSets(dbgs());
- #endif
- }
- void DxilViewIdStateBuilder::Clear() {
- m_bUsesViewId = false;
- m_NumInputSigScalars = 0;
- for (unsigned i = 0; i < kNumStreams; i++) {
- m_NumOutputSigScalars[i] = 0;
- m_OutputsDependentOnViewId[i].reset();
- m_InputsContributingToOutputs[i].clear();
- }
- m_NumPCOrPrimSigScalars = 0;
- m_InpSigDynIdxElems.clear();
- m_OutSigDynIdxElems.clear();
- m_PCSigDynIdxElems.clear();
- m_PCOrPrimOutputsDependentOnViewId.reset();
- m_InputsContributingToPCOrPrimOutputs.clear();
- m_PCInputsContributingToOutputs.clear();
- m_Entry.Clear();
- m_PCEntry.Clear();
- m_FuncInfo.clear();
- m_ReachingDeclsCache.clear();
- }
- void DxilViewIdStateBuilder::EntryInfo::Clear() {
- pEntryFunc = nullptr;
- Functions.clear();
- Outputs.clear();
- for (unsigned i = 0; i < kNumStreams; i++)
- ContributingInstructions[i].clear();
- }
- void DxilViewIdStateBuilder::FuncInfo::Clear() {
- Returns.clear();
- CtrlDep.Clear();
- pDomTree.reset();
- }
- void DxilViewIdStateBuilder::DetermineMaxPackedLocation(DxilSignature &DxilSig,
- unsigned *pMaxSigLoc,
- unsigned NumStreams) {
- DXASSERT_NOMSG(NumStreams == 1 || NumStreams == kNumStreams);
- for (unsigned i = 0; i < NumStreams; i++) {
- pMaxSigLoc[i] = 0;
- }
- for (auto &E : DxilSig.GetElements()) {
- if (E->GetStartRow() == Semantic::kUndefinedRow) continue;
- unsigned StreamId = E->GetOutputStream();
- unsigned endLoc = GetLinearIndex(*E, E->GetRows() - 1, E->GetCols() - 1);
- pMaxSigLoc[StreamId] = std::max(pMaxSigLoc[StreamId], endLoc + 1);
- E->GetCols();
- }
- }
- void DxilViewIdStateBuilder::ComputeReachableFunctionsRec(CallGraph &CG, CallGraphNode *pNode, FunctionSetType &FuncSet) {
- Function *F = pNode->getFunction();
- // Accumulate only functions with bodies.
- if (F->empty()) return;
- auto itIns = FuncSet.emplace(F);
- DXASSERT_NOMSG(itIns.second);
- (void)itIns;
- for (auto it = pNode->begin(), itEnd = pNode->end(); it != itEnd; ++it) {
- CallGraphNode *pSuccNode = it->second;
- ComputeReachableFunctionsRec(CG, pSuccNode, FuncSet);
- }
- }
- static bool GetUnsignedVal(Value *V, uint32_t *pValue) {
- ConstantInt *CI = dyn_cast<ConstantInt>(V);
- if (!CI) return false;
- uint64_t u = CI->getZExtValue();
- if (u > UINT32_MAX) return false;
- *pValue = (uint32_t)u;
- return true;
- }
- void DxilViewIdStateBuilder::AnalyzeFunctions(EntryInfo &Entry) {
- for (auto *F : Entry.Functions) {
- DXASSERT_NOMSG(!F->empty());
- auto itFI = m_FuncInfo.find(F);
- FuncInfo *pFuncInfo = nullptr;
- if (itFI != m_FuncInfo.end()) {
- pFuncInfo = itFI->second.get();
- } else {
- m_FuncInfo[F] = make_unique<FuncInfo>();
- pFuncInfo = m_FuncInfo[F].get();
- }
- for (auto itBB = F->begin(), endBB = F->end(); itBB != endBB; ++itBB) {
- BasicBlock *BB = itBB;
- for (auto itInst = BB->begin(), endInst = BB->end(); itInst != endInst; ++itInst) {
- if (ReturnInst *RI = dyn_cast<ReturnInst>(itInst)) {
- pFuncInfo->Returns.emplace(RI);
- continue;
- }
- CallInst *CI = dyn_cast<CallInst>(itInst);
- if (!CI) continue;
- DynamicallyIndexedElemsType *pDynIdxElems = nullptr;
- int row = Semantic::kUndefinedRow;
- unsigned id, col;
- if (DxilInst_LoadInput LI = DxilInst_LoadInput(CI)) {
- pDynIdxElems = &m_InpSigDynIdxElems;
- IFTBOOL(GetUnsignedVal(LI.get_inputSigId(), &id), DXC_E_GENERAL_INTERNAL_ERROR);
- GetUnsignedVal(LI.get_rowIndex(), (uint32_t*)&row);
- IFTBOOL(GetUnsignedVal(LI.get_colIndex(), &col), DXC_E_GENERAL_INTERNAL_ERROR);
- } else if (DxilInst_StoreOutput SO = DxilInst_StoreOutput(CI)) {
- pDynIdxElems = &m_OutSigDynIdxElems;
- IFTBOOL(GetUnsignedVal(SO.get_outputSigId(), &id), DXC_E_GENERAL_INTERNAL_ERROR);
- GetUnsignedVal(SO.get_rowIndex(), (uint32_t*)&row);
- IFTBOOL(GetUnsignedVal(SO.get_colIndex(), &col), DXC_E_GENERAL_INTERNAL_ERROR);
- Entry.Outputs.emplace(CI);
- } else if (DxilInst_StoreVertexOutput SVO = DxilInst_StoreVertexOutput(CI)) {
- pDynIdxElems = &m_OutSigDynIdxElems;
- IFTBOOL(GetUnsignedVal(SVO.get_outputSigId(), &id), DXC_E_GENERAL_INTERNAL_ERROR);
- GetUnsignedVal(SVO.get_rowIndex(), (uint32_t*)&row);
- IFTBOOL(GetUnsignedVal(SVO.get_colIndex(), &col), DXC_E_GENERAL_INTERNAL_ERROR);
- Entry.Outputs.emplace(CI);
- } else if (DxilInst_StorePrimitiveOutput SPO = DxilInst_StorePrimitiveOutput(CI)) {
- pDynIdxElems = &m_PCSigDynIdxElems;
- IFTBOOL(GetUnsignedVal(SPO.get_outputSigId(), &id), DXC_E_GENERAL_INTERNAL_ERROR);
- GetUnsignedVal(SPO.get_rowIndex(), (uint32_t*)&row);
- IFTBOOL(GetUnsignedVal(SPO.get_colIndex(), &col), DXC_E_GENERAL_INTERNAL_ERROR);
- Entry.Outputs.emplace(CI);
- } else if (DxilInst_LoadPatchConstant LPC = DxilInst_LoadPatchConstant(CI)) {
- if (m_pModule->GetShaderModel()->IsDS()) {
- pDynIdxElems = &m_PCSigDynIdxElems;
- IFTBOOL(GetUnsignedVal(LPC.get_inputSigId(), &id), DXC_E_GENERAL_INTERNAL_ERROR);
- GetUnsignedVal(LPC.get_row(), (uint32_t*)&row);
- IFTBOOL(GetUnsignedVal(LPC.get_col(), &col), DXC_E_GENERAL_INTERNAL_ERROR);
- } else {
- // Do nothing. This is an internal helper function for DXBC-2-DXIL converter.
- DXASSERT_NOMSG(m_pModule->GetShaderModel()->IsHS());
- }
- } else if (DxilInst_StorePatchConstant SPC = DxilInst_StorePatchConstant(CI)) {
- pDynIdxElems = &m_PCSigDynIdxElems;
- IFTBOOL(GetUnsignedVal(SPC.get_outputSigID(), &id), DXC_E_GENERAL_INTERNAL_ERROR);
- GetUnsignedVal(SPC.get_row(), (uint32_t*)&row);
- IFTBOOL(GetUnsignedVal(SPC.get_col(), &col), DXC_E_GENERAL_INTERNAL_ERROR);
- Entry.Outputs.emplace(CI);
- } else if (DxilInst_LoadOutputControlPoint LOCP = DxilInst_LoadOutputControlPoint(CI)) {
- if (m_pModule->GetShaderModel()->IsDS()) {
- pDynIdxElems = &m_InpSigDynIdxElems;
- IFTBOOL(GetUnsignedVal(LOCP.get_inputSigId(), &id), DXC_E_GENERAL_INTERNAL_ERROR);
- GetUnsignedVal(LOCP.get_row(), (uint32_t*)&row);
- IFTBOOL(GetUnsignedVal(LOCP.get_col(), &col), DXC_E_GENERAL_INTERNAL_ERROR);
- } else if (m_pModule->GetShaderModel()->IsHS()) {
- // Do nothings, as the information has been captured by the output signature of CP entry.
- } else {
- DXASSERT_NOMSG(false);
- }
- } else {
- continue;
- }
- // Record dynamic index usage.
- if (pDynIdxElems && row == Semantic::kUndefinedRow) {
- (*pDynIdxElems)[id] |= (1 << col);
- }
- }
- }
- // Compute dominator relation.
- pFuncInfo->pDomTree = make_unique<DominatorTreeBase<BasicBlock> >(false);
- pFuncInfo->pDomTree->recalculate(*F);
- #if DXILVIEWID_DBG
- pFuncInfo->pDomTree->print(dbgs());
- #endif
- // Compute postdominator relation.
- DominatorTreeBase<BasicBlock> PDR(true);
- PDR.recalculate(*F);
- #if DXILVIEWID_DBG
- PDR.print(dbgs());
- #endif
- // Compute control dependence.
- pFuncInfo->CtrlDep.Compute(F, PDR);
- #if DXILVIEWID_DBG
- pFuncInfo->CtrlDep.print(dbgs());
- #endif
- }
- }
- void DxilViewIdStateBuilder::CollectValuesContributingToOutputs(EntryInfo &Entry) {
- for (auto *CI : Entry.Outputs) { // CI = call instruction
- DxilSignature *pDxilSig = nullptr;
- Value *pContributingValue = nullptr;
- unsigned id = (unsigned)-1;
- int startRow = Semantic::kUndefinedRow, endRow = Semantic::kUndefinedRow;
- unsigned col = (unsigned)-1;
- if (DxilInst_StoreOutput SO = DxilInst_StoreOutput(CI)) {
- pDxilSig = &m_pModule->GetOutputSignature();
- pContributingValue = SO.get_value();
- GetUnsignedVal(SO.get_outputSigId(), &id);
- GetUnsignedVal(SO.get_colIndex(), &col);
- GetUnsignedVal(SO.get_rowIndex(), (uint32_t*)&startRow);
- } else if (DxilInst_StoreVertexOutput SVO = DxilInst_StoreVertexOutput(CI)) {
- pDxilSig = &m_pModule->GetOutputSignature();
- pContributingValue = SVO.get_value();
- GetUnsignedVal(SVO.get_outputSigId(), &id);
- GetUnsignedVal(SVO.get_colIndex(), &col);
- GetUnsignedVal(SVO.get_rowIndex(), (uint32_t*)&startRow);
- } else if (DxilInst_StorePrimitiveOutput SPO = DxilInst_StorePrimitiveOutput(CI)) {
- pDxilSig = &m_pModule->GetPatchConstOrPrimSignature();
- pContributingValue = SPO.get_value();
- GetUnsignedVal(SPO.get_outputSigId(), &id);
- GetUnsignedVal(SPO.get_colIndex(), &col);
- GetUnsignedVal(SPO.get_rowIndex(), (uint32_t*)&startRow);
- } else if (DxilInst_StorePatchConstant SPC = DxilInst_StorePatchConstant(CI)) {
- pDxilSig = &m_pModule->GetPatchConstOrPrimSignature();
- pContributingValue = SPC.get_value();
- GetUnsignedVal(SPC.get_outputSigID(), &id);
- GetUnsignedVal(SPC.get_row(), (uint32_t*)&startRow);
- GetUnsignedVal(SPC.get_col(), &col);
- } else {
- IFT(DXC_E_GENERAL_INTERNAL_ERROR);
- }
- DxilSignatureElement &SigElem = pDxilSig->GetElement(id);
- if (!SigElem.IsAllocated())
- continue;
- unsigned StreamId = SigElem.GetOutputStream();
- if (startRow != Semantic::kUndefinedRow) {
- endRow = startRow;
- } else {
- // The entire column is affected by value.
- DXASSERT_NOMSG(SigElem.GetID() == id && SigElem.GetStartRow() != Semantic::kUndefinedRow);
- startRow = 0;
- endRow = SigElem.GetRows() - 1;
- }
- InstructionSetType ContributingInstructionsAllRows;
- InstructionSetType *pContributingInstructions = &ContributingInstructionsAllRows;
- if (startRow == endRow) {
- // Scalar or indexable with known index.
- unsigned index = GetLinearIndex(SigElem, startRow, col);
- pContributingInstructions = &Entry.ContributingInstructions[StreamId][index];
- }
- CollectValuesContributingToOutputRec(Entry, pContributingValue, *pContributingInstructions);
- // Handle control dependence of this instruction BB.
- BasicBlock *pBB = CI->getParent();
- Function *F = pBB->getParent();
- FuncInfo *pFuncInfo = m_FuncInfo[F].get();
- const BasicBlockSet &CtrlDepSet = pFuncInfo->CtrlDep.GetCDBlocks(pBB);
- for (BasicBlock *B : CtrlDepSet) {
- CollectValuesContributingToOutputRec(Entry, B->getTerminator(), *pContributingInstructions);
- }
- if (pContributingInstructions == &ContributingInstructionsAllRows) {
- // Write dynamically indexed output contributions to all rows.
- for (int row = startRow; row <= endRow; row++) {
- unsigned index = GetLinearIndex(SigElem, row, col);
- Entry.ContributingInstructions[StreamId][index].insert(ContributingInstructionsAllRows.begin(), ContributingInstructionsAllRows.end());
- }
- }
- }
- }
- void DxilViewIdStateBuilder::CollectValuesContributingToOutputRec(EntryInfo &Entry,
- Value *pContributingValue,
- InstructionSetType &ContributingInstructions) {
- if (dyn_cast<Argument>(pContributingValue)) {
- // This must be a leftover signature argument of an entry function.
- DXASSERT_NOMSG(Entry.pEntryFunc == m_pModule->GetEntryFunction() ||
- Entry.pEntryFunc == m_pModule->GetPatchConstantFunction());
- return;
- }
- Instruction *pContributingInst = dyn_cast<Instruction>(pContributingValue);
- if (pContributingInst == nullptr) {
- // Can be literal constant, global decl, branch target.
- DXASSERT_NOMSG(isa<Constant>(pContributingValue) || isa<BasicBlock>(pContributingValue));
- return;
- }
- BasicBlock *pBB = pContributingInst->getParent();
- Function *F = pBB->getParent();
- auto FuncInfoIt = m_FuncInfo.find(F);
- DXASSERT_NOMSG(FuncInfoIt != m_FuncInfo.end());
- if (FuncInfoIt == m_FuncInfo.end()) {
- return;
- }
- auto itInst = ContributingInstructions.emplace(pContributingInst);
- // Already visited instruction.
- if (!itInst.second) return;
- // Handle special cases.
- if (PHINode *phi = dyn_cast<PHINode>(pContributingInst)) {
- CollectPhiCFValuesContributingToOutputRec(phi, Entry, ContributingInstructions);
- } else if (isa<LoadInst>(pContributingInst) ||
- isa<AtomicCmpXchgInst>(pContributingInst) ||
- isa<AtomicRMWInst>(pContributingInst)) {
- Value *pPtrValue = pContributingInst->getOperand(0);
- DXASSERT_NOMSG(pPtrValue->getType()->isPointerTy());
- const ValueSetType &ReachingDecls = CollectReachingDecls(pPtrValue);
- DXASSERT_NOMSG(ReachingDecls.size() > 0);
- for (Value *pDeclValue : ReachingDecls) {
- const ValueSetType &Stores = CollectStores(pDeclValue);
- for (Value *V : Stores) {
- CollectValuesContributingToOutputRec(Entry, V, ContributingInstructions);
- }
- }
- } else if (CallInst *CI = dyn_cast<CallInst>(pContributingInst)) {
- if (!hlsl::OP::IsDxilOpFuncCallInst(CI)) {
- Function *F = CI->getCalledFunction();
- if (!F->empty()) {
- // Return value of a user function.
- if (Entry.Functions.find(F) != Entry.Functions.end()) {
- const FuncInfo &FI = *m_FuncInfo[F];
- for (ReturnInst *pRetInst : FI.Returns) {
- CollectValuesContributingToOutputRec(Entry, pRetInst, ContributingInstructions);
- }
- }
- }
- }
- }
- // Handle instruction inputs.
- unsigned NumOps = pContributingInst->getNumOperands();
- for (unsigned i = 0; i < NumOps; i++) {
- Value *O = pContributingInst->getOperand(i);
- CollectValuesContributingToOutputRec(Entry, O, ContributingInstructions);
- }
- // Handle control dependence of this instruction BB.
- FuncInfo *pFuncInfo = FuncInfoIt->second.get();
- const BasicBlockSet &CtrlDepSet = pFuncInfo->CtrlDep.GetCDBlocks(pBB);
- for (BasicBlock *B : CtrlDepSet) {
- CollectValuesContributingToOutputRec(Entry, B->getTerminator(), ContributingInstructions);
- }
- }
- // Only process control-dependent basic blocks for constant operands of the phi-function.
- // An obvious "definition" point for a constant operand is the predecessor along corresponding edge.
- // However, this may be too conservative and, as such, pick up extra control dependent BBs.
- // A better "definition" point is the highest dominator where it is still legal to "insert" constant assignment.
- // In this context, "legal" means that only one value "leaves" the dominator and reaches Phi.
- void DxilViewIdStateBuilder::CollectPhiCFValuesContributingToOutputRec(PHINode *pPhi,
- EntryInfo &Entry,
- InstructionSetType &ContributingInstructions) {
- Function *F = pPhi->getParent()->getParent();
- FuncInfo *pFuncInfo = m_FuncInfo[F].get();
- unordered_map<DomTreeNodeBase<BasicBlock> *, Value *> DomTreeMarkers;
- // Mark predecessors of each value, so that there is a legal "definition" point.
- for (unsigned i = 0; i < pPhi->getNumOperands(); i++) {
- Value *pValue = pPhi->getIncomingValue(i);
- BasicBlock *pBB = pPhi->getIncomingBlock(i);
- DomTreeNodeBase<BasicBlock> *pDomNode = pFuncInfo->pDomTree->getNode(pBB);
- auto it = DomTreeMarkers.emplace(pDomNode, pValue);
- DXASSERT_NOMSG(it.second || it.first->second == pValue); (void)it;
- }
- // Mark the dominator tree with "definition" values, walking up to the parent.
- for (unsigned i = 0; i < pPhi->getNumOperands(); i++) {
- Value *pValue = pPhi->getIncomingValue(i);
- BasicBlock *pDefBB = &F->getEntryBlock();
- if (Instruction *pDefInst = dyn_cast<Instruction>(pValue)) {
- pDefBB = pDefInst->getParent();
- }
- BasicBlock *pBB = pPhi->getIncomingBlock(i);
- if (pBB == pDefBB) {
- continue; // we already handled the predecessor.
- }
- DomTreeNodeBase<BasicBlock> *pDomNode = pFuncInfo->pDomTree->getNode(pBB);
- pDomNode = pDomNode->getIDom();
- while (pDomNode) {
- auto it = DomTreeMarkers.emplace(pDomNode, pValue);
- if (!it.second) {
- if (it.first->second != pValue && it.first->second != nullptr) {
- if (!isa<Constant>(it.first->second) || !isa<Constant>(pValue)) {
- // Unless both are different constants, mark the "definition" point as illegal.
- it.first->second = nullptr;
- // If both are constants, leave the marker of the first one.
- }
- }
- break;
- }
- // Do not go higher than a legal definition point.
- pBB = pDomNode->getBlock();
- if (pBB == pDefBB)
- break;
- pDomNode = pDomNode->getIDom();
- }
- }
- // Handle control dependence for Constant arguments of Phi.
- for (unsigned i = 0; i < pPhi->getNumOperands(); i++) {
- Value *pValue = pPhi->getIncomingValue(i);
- if (!isa<Constant>(pValue))
- continue;
- // Determine the higher legal "definition" point.
- BasicBlock *pBB = pPhi->getIncomingBlock(i);
- DomTreeNodeBase<BasicBlock> *pDomNode = pFuncInfo->pDomTree->getNode(pBB);
- DomTreeNodeBase<BasicBlock> *pDefDomNode = pDomNode;
- while (pDomNode) {
- auto it = DomTreeMarkers.find(pDomNode);
- DXASSERT_NOMSG(it != DomTreeMarkers.end());
- if (it->second != pValue) {
- DXASSERT_NOMSG(it->second == nullptr || isa<Constant>(it->second));
- break;
- }
- pDefDomNode = pDomNode;
- pDomNode = pDomNode->getIDom();
- }
- // Handle control dependence of this constant argument highest legal "definition" point.
- pBB = pDefDomNode->getBlock();
- const BasicBlockSet &CtrlDepSet = pFuncInfo->CtrlDep.GetCDBlocks(pBB);
- for (BasicBlock *B : CtrlDepSet) {
- CollectValuesContributingToOutputRec(Entry, B->getTerminator(), ContributingInstructions);
- }
- }
- }
- const DxilViewIdStateBuilder::ValueSetType &DxilViewIdStateBuilder::CollectReachingDecls(Value *pValue) {
- auto it = m_ReachingDeclsCache.emplace(pValue, ValueSetType());
- if (it.second) {
- // We have not seen this value before.
- ValueSetType Visited;
- CollectReachingDeclsRec(pValue, it.first->second, Visited);
- }
- return it.first->second;
- }
- void DxilViewIdStateBuilder::CollectReachingDeclsRec(Value *pValue, ValueSetType &ReachingDecls, ValueSetType &Visited) {
- if (Visited.find(pValue) != Visited.end())
- return;
- bool bInitialValue = Visited.size() == 0;
- Visited.emplace(pValue);
- if (!bInitialValue) {
- auto it = m_ReachingDeclsCache.find(pValue);
- if (it != m_ReachingDeclsCache.end()) {
- ReachingDecls.insert(it->second.begin(), it->second.end());
- return;
- }
- }
- if (dyn_cast<GlobalVariable>(pValue)) {
- ReachingDecls.emplace(pValue);
- return;
- }
- if (GetElementPtrInst *pGepInst = dyn_cast<GetElementPtrInst>(pValue)) {
- Value *pPtrValue = pGepInst->getPointerOperand();
- CollectReachingDeclsRec(pPtrValue, ReachingDecls, Visited);
- } else if (GEPOperator *pGepOp = dyn_cast<GEPOperator>(pValue)) {
- Value *pPtrValue = pGepOp->getPointerOperand();
- CollectReachingDeclsRec(pPtrValue, ReachingDecls, Visited);
- } else if (isa<ConstantExpr>(pValue) && cast<ConstantExpr>(pValue)->getOpcode() == Instruction::AddrSpaceCast) {
- CollectReachingDeclsRec(cast<ConstantExpr>(pValue)->getOperand(0), ReachingDecls, Visited);
- } else if (AddrSpaceCastInst *pCI = dyn_cast<AddrSpaceCastInst>(pValue)) {
- CollectReachingDeclsRec(pCI->getOperand(0), ReachingDecls, Visited);
- } else if (BitCastInst *pCI = dyn_cast<BitCastInst>(pValue)) {
- CollectReachingDeclsRec(pCI->getOperand(0), ReachingDecls, Visited);
- } else if (dyn_cast<AllocaInst>(pValue)) {
- ReachingDecls.emplace(pValue);
- } else if (PHINode *phi = dyn_cast<PHINode>(pValue)) {
- for (Value *pPtrValue : phi->operands()) {
- CollectReachingDeclsRec(pPtrValue, ReachingDecls, Visited);
- }
- } else if (SelectInst *SelI = dyn_cast<SelectInst>(pValue)) {
- CollectReachingDeclsRec(SelI->getTrueValue(), ReachingDecls, Visited);
- CollectReachingDeclsRec(SelI->getFalseValue(), ReachingDecls, Visited);
- } else if (dyn_cast<Argument>(pValue)) {
- ReachingDecls.emplace(pValue);
- } else if (CallInst *call = dyn_cast<CallInst>(pValue)) {
- DXASSERT(OP::GetDxilOpFuncCallInst(call) == DXIL::OpCode::GetMeshPayload,
- "the function must be @dx.op.getMeshPayload here.");
- ReachingDecls.emplace(pValue);
- } else {
- IFT(DXC_E_GENERAL_INTERNAL_ERROR);
- }
- }
- const DxilViewIdStateBuilder::ValueSetType &DxilViewIdStateBuilder::CollectStores(llvm::Value *pValue) {
- auto it = m_StoresPerDeclCache.emplace(pValue, ValueSetType());
- if (it.second) {
- // We have not seen this value before.
- ValueSetType Visited;
- CollectStoresRec(pValue, it.first->second, Visited);
- }
- return it.first->second;
- }
- void DxilViewIdStateBuilder::CollectStoresRec(llvm::Value *pValue, ValueSetType &Stores, ValueSetType &Visited) {
- if (Visited.find(pValue) != Visited.end())
- return;
- bool bInitialValue = Visited.size() == 0;
- Visited.emplace(pValue);
- if (!bInitialValue) {
- auto it = m_StoresPerDeclCache.find(pValue);
- if (it != m_StoresPerDeclCache.end()) {
- Stores.insert(it->second.begin(), it->second.end());
- return;
- }
- }
- if (isa<LoadInst>(pValue)) {
- return;
- } else if (isa<StoreInst>(pValue) ||
- isa<AtomicCmpXchgInst>(pValue) ||
- isa<AtomicRMWInst>(pValue)) {
- Stores.emplace(pValue);
- return;
- }
- for (auto *U : pValue->users()) {
- CollectStoresRec(U, Stores, Visited);
- }
- }
- void DxilViewIdStateBuilder::CreateViewIdSets(const std::unordered_map<unsigned, InstructionSetType> &ContributingInstructions,
- OutputsDependentOnViewIdType &OutputsDependentOnViewId,
- InputsContributingToOutputType &InputsContributingToOutputs,
- bool bPC) {
- const ShaderModel *pSM = m_pModule->GetShaderModel();
- for (auto &itOut : ContributingInstructions) {
- unsigned outIdx = itOut.first;
- for (Instruction *pInst : itOut.second) {
- // Set output dependence on ViewId.
- if (DxilInst_ViewID VID = DxilInst_ViewID(pInst)) {
- DXASSERT(m_bUsesViewId, "otherwise, DxilModule flag not set properly");
- OutputsDependentOnViewId[outIdx] = true;
- continue;
- }
- // Start setting output dependence on inputs.
- DxilSignatureElement *pSigElem = nullptr;
- bool bLoadOutputCPInHS = false;
- unsigned inpId = (unsigned)-1;
- int startRow = Semantic::kUndefinedRow, endRow = Semantic::kUndefinedRow;
- unsigned col = (unsigned)-1;
- if (DxilInst_LoadInput LI = DxilInst_LoadInput(pInst)) {
- GetUnsignedVal(LI.get_inputSigId(), &inpId);
- GetUnsignedVal(LI.get_colIndex(), &col);
- GetUnsignedVal(LI.get_rowIndex(), (uint32_t*)&startRow);
- pSigElem = &m_pModule->GetInputSignature().GetElement(inpId);
- if (pSM->IsDS() && bPC) {
- pSigElem = nullptr;
- }
- } else if (DxilInst_LoadOutputControlPoint LOCP = DxilInst_LoadOutputControlPoint(pInst)) {
- GetUnsignedVal(LOCP.get_inputSigId(), &inpId);
- GetUnsignedVal(LOCP.get_col(), &col);
- GetUnsignedVal(LOCP.get_row(), (uint32_t*)&startRow);
- if (pSM->IsHS()) {
- pSigElem = &m_pModule->GetOutputSignature().GetElement(inpId);
- bLoadOutputCPInHS = true;
- } else if (pSM->IsDS()) {
- if (!bPC) {
- pSigElem = &m_pModule->GetInputSignature().GetElement(inpId);
- }
- } else {
- DXASSERT_NOMSG(false);
- }
- } else if (DxilInst_LoadPatchConstant LPC = DxilInst_LoadPatchConstant(pInst)) {
- if (pSM->IsDS() && bPC) {
- GetUnsignedVal(LPC.get_inputSigId(), &inpId);
- GetUnsignedVal(LPC.get_col(), &col);
- GetUnsignedVal(LPC.get_row(), (uint32_t*)&startRow);
- pSigElem = &m_pModule->GetPatchConstOrPrimSignature().GetElement(inpId);
- }
- } else {
- continue;
- }
- // Finalize setting output dependence on inputs.
- if (pSigElem && pSigElem->IsAllocated()) {
- if (startRow != Semantic::kUndefinedRow) {
- endRow = startRow;
- } else {
- // The entire column contributes to output.
- startRow = 0;
- endRow = pSigElem->GetRows() - 1;
- }
- auto &ContributingInputs = InputsContributingToOutputs[outIdx];
- for (int row = startRow; row <= endRow; row++) {
- unsigned index = GetLinearIndex(*pSigElem, row, col);
- if (!bLoadOutputCPInHS) {
- ContributingInputs.emplace(index);
- } else {
- // This HS patch-constant output depends on an input value of LoadOutputControlPoint
- // that is the output value of the HS main (control-point) function.
- // Transitively update this (patch-constant) output dependence on main (control-point) output.
- DXASSERT_NOMSG(&OutputsDependentOnViewId == &m_PCOrPrimOutputsDependentOnViewId);
- OutputsDependentOnViewId[outIdx] = OutputsDependentOnViewId[outIdx] || m_OutputsDependentOnViewId[0][index];
- const auto it = m_InputsContributingToOutputs[0].find(index);
- if (it != m_InputsContributingToOutputs[0].end()) {
- const std::set<unsigned> &LoadOutputCPInputsContributingToOutputs = it->second;
- ContributingInputs.insert(LoadOutputCPInputsContributingToOutputs.begin(),
- LoadOutputCPInputsContributingToOutputs.end());
- }
- }
- }
- }
- }
- }
- }
- unsigned DxilViewIdStateBuilder::GetLinearIndex(DxilSignatureElement &SigElem, int row, unsigned col) const {
- DXASSERT_NOMSG(row >= 0 && col < kNumComps && SigElem.GetStartRow() != Semantic::kUndefinedRow);
- unsigned idx = (((unsigned)row) + SigElem.GetStartRow())*kNumComps + col + SigElem.GetStartCol();
- DXASSERT_NOMSG(idx < kMaxSigScalars); (void)kMaxSigScalars;
- return idx;
- }
- void DxilViewIdStateBuilder::UpdateDynamicIndexUsageState() const {
- UpdateDynamicIndexUsageStateForSig(m_pModule->GetInputSignature(), m_InpSigDynIdxElems);
- UpdateDynamicIndexUsageStateForSig(m_pModule->GetOutputSignature(), m_OutSigDynIdxElems);
- UpdateDynamicIndexUsageStateForSig(m_pModule->GetPatchConstOrPrimSignature(), m_PCSigDynIdxElems);
- }
- void DxilViewIdStateBuilder::UpdateDynamicIndexUsageStateForSig(DxilSignature &Sig,
- const DynamicallyIndexedElemsType &DynIdxElems) const {
- for (auto it : DynIdxElems) {
- unsigned id = it.first;
- unsigned mask = it.second;
- DxilSignatureElement &E = Sig.GetElement(id);
- E.SetDynIdxCompMask(mask);
- }
- }
- namespace {
- class ComputeViewIdState : public ModulePass {
- public:
- static char ID; // Pass ID, replacement for typeid
- ComputeViewIdState();
- bool runOnModule(Module &M) override;
- void getAnalysisUsage(AnalysisUsage &AU) const override;
- };
- } // namespace
- char ComputeViewIdState::ID = 0;
- INITIALIZE_PASS_BEGIN(ComputeViewIdState, "viewid-state",
- "Compute information related to ViewID", true, true)
- INITIALIZE_PASS_END(ComputeViewIdState, "viewid-state",
- "Compute information related to ViewID", true, true)
- ComputeViewIdState::ComputeViewIdState() : ModulePass(ID) {
- }
- bool ComputeViewIdState::runOnModule(Module &M) {
- DxilModule &DxilModule = M.GetOrCreateDxilModule();
- const ShaderModel *pSM = DxilModule.GetShaderModel();
- if (!pSM->IsCS() && !pSM->IsLib()) {
- DxilViewIdState ViewIdState(&DxilModule);
- DxilViewIdStateBuilder Builder(ViewIdState, &DxilModule);
- Builder.Compute();
- // Serialize viewidstate.
- ViewIdState.Serialize();
- auto &TmpSerialized = ViewIdState.GetSerialized();
- // Copy serilized viewidstate.
- auto &SerializedViewIdState = DxilModule.GetSerializedViewIdState();
- SerializedViewIdState.clear();
- SerializedViewIdState.resize(TmpSerialized.size());
- SerializedViewIdState.assign(TmpSerialized.begin(), TmpSerialized.end());
- return true;
- }
- return false;
- }
- void ComputeViewIdState::getAnalysisUsage(AnalysisUsage &AU) const {
- AU.setPreservesAll();
- }
- namespace llvm {
- ModulePass *createComputeViewIdStatePass() {
- return new ComputeViewIdState();
- }
- } // end of namespace llvm
|