1036 строки
39 KiB
C++
1036 строки
39 KiB
C++
///////////////////////////////////////////////////////////////////////////////
|
|
// //
|
|
// 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/DXIL/DxilInstructions.h"
|
|
#include "dxc/DXIL/DxilModule.h"
|
|
#include "dxc/DXIL/DxilOperations.h"
|
|
#include "dxc/HLSL/ComputeViewIdState.h"
|
|
#include "dxc/HLSL/HLOperations.h"
|
|
#include "dxc/HlslIntrinsicOp.h"
|
|
#include "dxc/Support/Global.h"
|
|
|
|
#include "llvm/Analysis/CallGraph.h"
|
|
#include "llvm/IR/CFG.h"
|
|
#include "llvm/IR/Function.h"
|
|
#include "llvm/IR/LLVMContext.h"
|
|
#include "llvm/IR/LegacyPassManager.h"
|
|
#include "llvm/IR/Module.h"
|
|
#include "llvm/IR/Operator.h"
|
|
#include "llvm/Pass.h"
|
|
#include "llvm/Support/Debug.h"
|
|
|
|
#include <algorithm>
|
|
|
|
using namespace llvm;
|
|
using namespace llvm::legacy;
|
|
using namespace hlsl;
|
|
using llvm::legacy::FunctionPassManager;
|
|
using llvm::legacy::PassManager;
|
|
using std::unordered_map;
|
|
using std::unordered_set;
|
|
using std::vector;
|
|
|
|
#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,
|
|
bool IsForPatchConstant);
|
|
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();
|
|
// For MS, use main entry as PC entry to collect primitive outputs.
|
|
if (pSM->IsMS())
|
|
m_PCEntry.pEntryFunc = m_pModule->GetEntryFunction();
|
|
ComputeReachableFunctionsRec(CG, CG[m_Entry.pEntryFunc], m_Entry.Functions);
|
|
if (m_PCEntry.pEntryFunc) {
|
|
DXASSERT_NOMSG(pSM->IsHS() || pSM->IsMS());
|
|
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,
|
|
/*IsForPatchConstantOrPrimitive*/ false);
|
|
if (m_PCEntry.pEntryFunc)
|
|
CollectValuesContributingToOutputs(m_PCEntry,
|
|
/*IsForPatchConstantOrPrimitive*/ true);
|
|
|
|
// 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;
|
|
if (FuncSet.count(F))
|
|
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, bool IsForPatchConstantOrPrimitive) {
|
|
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)) {
|
|
if (IsForPatchConstantOrPrimitive)
|
|
continue;
|
|
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)) {
|
|
if (IsForPatchConstantOrPrimitive)
|
|
continue;
|
|
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)) {
|
|
if (!IsForPatchConstantOrPrimitive)
|
|
continue;
|
|
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)) {
|
|
if (!IsForPatchConstantOrPrimitive)
|
|
continue;
|
|
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;
|
|
|
|
void print(raw_ostream &o, const Module *M) const override {
|
|
DxilModule &DxilModule = M->GetDxilModule();
|
|
const ShaderModel *pSM = DxilModule.GetShaderModel();
|
|
if (pSM->IsCS() || pSM->IsLib())
|
|
return;
|
|
|
|
auto &SerializedViewIdState = DxilModule.GetSerializedViewIdState();
|
|
DxilViewIdState ViewIdState(&DxilModule);
|
|
ViewIdState.Deserialize(SerializedViewIdState.data(),
|
|
SerializedViewIdState.size());
|
|
ViewIdState.PrintSets(errs());
|
|
}
|
|
};
|
|
} // 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
|