Add CB Usage to metadata, compute in hlsl-dxil-lower-handle-for-lib
This commit is contained in:
Родитель
eea0c94c08
Коммит
4234a9ae53
|
@ -193,6 +193,7 @@ public:
|
||||||
static const unsigned kDxilFieldAnnotationFieldNameTag = 6;
|
static const unsigned kDxilFieldAnnotationFieldNameTag = 6;
|
||||||
static const unsigned kDxilFieldAnnotationCompTypeTag = 7;
|
static const unsigned kDxilFieldAnnotationCompTypeTag = 7;
|
||||||
static const unsigned kDxilFieldAnnotationPreciseTag = 8;
|
static const unsigned kDxilFieldAnnotationPreciseTag = 8;
|
||||||
|
static const unsigned kDxilFieldAnnotationCBUsedTag = 9;
|
||||||
|
|
||||||
// StructAnnotation extended property tags (DXIL 1.5+ only, appended)
|
// StructAnnotation extended property tags (DXIL 1.5+ only, appended)
|
||||||
static const unsigned kDxilTemplateArgumentsTag = 0; // Name for name-value list of extended struct properties
|
static const unsigned kDxilTemplateArgumentsTag = 0; // Name for name-value list of extended struct properties
|
||||||
|
|
|
@ -79,6 +79,9 @@ public:
|
||||||
const std::string &GetFieldName() const;
|
const std::string &GetFieldName() const;
|
||||||
void SetFieldName(const std::string &FieldName);
|
void SetFieldName(const std::string &FieldName);
|
||||||
|
|
||||||
|
bool IsCBVarUsed() const;
|
||||||
|
void SetCBVarUsed(bool used);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
bool m_bPrecise;
|
bool m_bPrecise;
|
||||||
CompType m_CompType;
|
CompType m_CompType;
|
||||||
|
@ -88,6 +91,7 @@ private:
|
||||||
std::string m_Semantic;
|
std::string m_Semantic;
|
||||||
InterpolationMode m_InterpMode;
|
InterpolationMode m_InterpMode;
|
||||||
std::string m_FieldName;
|
std::string m_FieldName;
|
||||||
|
bool m_bCBufferVarUsed; // true if this field represents a top level variable in CB structure, and it is used.
|
||||||
};
|
};
|
||||||
|
|
||||||
class DxilTemplateArgAnnotation : DxilFieldAnnotation {
|
class DxilTemplateArgAnnotation : DxilFieldAnnotation {
|
||||||
|
|
|
@ -986,6 +986,11 @@ Metadata *DxilMDHelper::EmitDxilFieldAnnotation(const DxilFieldAnnotation &FA) {
|
||||||
MDVals.emplace_back(Uint32ToConstMD(kDxilFieldAnnotationCompTypeTag));
|
MDVals.emplace_back(Uint32ToConstMD(kDxilFieldAnnotationCompTypeTag));
|
||||||
MDVals.emplace_back(Uint32ToConstMD((unsigned)FA.GetCompType().GetKind()));
|
MDVals.emplace_back(Uint32ToConstMD((unsigned)FA.GetCompType().GetKind()));
|
||||||
}
|
}
|
||||||
|
if (FA.IsCBVarUsed() &&
|
||||||
|
DXIL::CompareVersions(m_ValMajor, m_ValMinor, 1, 5) >= 0) {
|
||||||
|
MDVals.emplace_back(Uint32ToConstMD(kDxilFieldAnnotationCBUsedTag));
|
||||||
|
MDVals.emplace_back(BoolToConstMD(true));
|
||||||
|
}
|
||||||
|
|
||||||
return MDNode::get(m_Ctx, MDVals);
|
return MDNode::get(m_Ctx, MDVals);
|
||||||
}
|
}
|
||||||
|
@ -1030,6 +1035,9 @@ void DxilMDHelper::LoadDxilFieldAnnotation(const MDOperand &MDO, DxilFieldAnnota
|
||||||
case kDxilFieldAnnotationCompTypeTag:
|
case kDxilFieldAnnotationCompTypeTag:
|
||||||
FA.SetCompType((CompType::Kind)ConstMDToUint32(MDO));
|
FA.SetCompType((CompType::Kind)ConstMDToUint32(MDO));
|
||||||
break;
|
break;
|
||||||
|
case kDxilFieldAnnotationCBUsedTag:
|
||||||
|
FA.SetCBVarUsed(ConstMDToBool(MDO));
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
// TODO: I don't think we should be failing unrecognized extended tags.
|
// TODO: I don't think we should be failing unrecognized extended tags.
|
||||||
// Perhaps we can flag this case in the module and fail validation
|
// Perhaps we can flag this case in the module and fail validation
|
||||||
|
|
|
@ -43,8 +43,9 @@ DxilMatrixAnnotation::DxilMatrixAnnotation()
|
||||||
DxilFieldAnnotation::DxilFieldAnnotation()
|
DxilFieldAnnotation::DxilFieldAnnotation()
|
||||||
: m_bPrecise(false)
|
: m_bPrecise(false)
|
||||||
, m_ResourceAttribute(nullptr)
|
, m_ResourceAttribute(nullptr)
|
||||||
, m_CBufferOffset(UINT_MAX) {
|
, m_CBufferOffset(UINT_MAX)
|
||||||
}
|
, m_bCBufferVarUsed(false)
|
||||||
|
{}
|
||||||
|
|
||||||
bool DxilFieldAnnotation::IsPrecise() const { return m_bPrecise; }
|
bool DxilFieldAnnotation::IsPrecise() const { return m_bPrecise; }
|
||||||
void DxilFieldAnnotation::SetPrecise(bool b) { m_bPrecise = b; }
|
void DxilFieldAnnotation::SetPrecise(bool b) { m_bPrecise = b; }
|
||||||
|
@ -76,6 +77,9 @@ void DxilFieldAnnotation::SetInterpolationMode(const InterpolationMode &IM) { m_
|
||||||
bool DxilFieldAnnotation::HasFieldName() const { return !m_FieldName.empty(); }
|
bool DxilFieldAnnotation::HasFieldName() const { return !m_FieldName.empty(); }
|
||||||
const std::string &DxilFieldAnnotation::GetFieldName() const { return m_FieldName; }
|
const std::string &DxilFieldAnnotation::GetFieldName() const { return m_FieldName; }
|
||||||
void DxilFieldAnnotation::SetFieldName(const std::string &FieldName) { m_FieldName = FieldName; }
|
void DxilFieldAnnotation::SetFieldName(const std::string &FieldName) { m_FieldName = FieldName; }
|
||||||
|
bool DxilFieldAnnotation::IsCBVarUsed() const { return m_bCBufferVarUsed; }
|
||||||
|
void DxilFieldAnnotation::SetCBVarUsed(bool used) { m_bCBufferVarUsed = used; }
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
//------------------------------------------------------------------------------
|
//------------------------------------------------------------------------------
|
||||||
|
|
|
@ -477,6 +477,9 @@ public:
|
||||||
|
|
||||||
bChanged |= ResourceRegisterAllocator.AllocateRegisters(DM);
|
bChanged |= ResourceRegisterAllocator.AllocateRegisters(DM);
|
||||||
|
|
||||||
|
// Fill in top-level CBuffer variable usage bit
|
||||||
|
UpdateCBufferUsage();
|
||||||
|
|
||||||
if (m_bIsLib && DM.GetShaderModel()->GetMinor() == ShaderModel::kOfflineMinor)
|
if (m_bIsLib && DM.GetShaderModel()->GetMinor() == ShaderModel::kOfflineMinor)
|
||||||
return bChanged;
|
return bChanged;
|
||||||
|
|
||||||
|
@ -516,6 +519,7 @@ private:
|
||||||
// Switch CBuffer for SRV for TBuffers.
|
// Switch CBuffer for SRV for TBuffers.
|
||||||
bool PatchTBuffers(DxilModule &DM);
|
bool PatchTBuffers(DxilModule &DM);
|
||||||
void PatchTBufferUse(Value *V, DxilModule &DM);
|
void PatchTBufferUse(Value *V, DxilModule &DM);
|
||||||
|
void UpdateCBufferUsage();
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace
|
} // namespace
|
||||||
|
@ -2093,6 +2097,145 @@ bool DxilLowerCreateHandleForLib::PatchTBuffers(DxilModule &DM) {
|
||||||
return bChanged;
|
return bChanged;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Find the imm offset part from a value.
|
||||||
|
// It must exist unless offset is 0.
|
||||||
|
static unsigned GetCBOffset(Value *V) {
|
||||||
|
if (ConstantInt *Imm = dyn_cast<ConstantInt>(V))
|
||||||
|
return Imm->getLimitedValue();
|
||||||
|
else if (UnaryInstruction *UI = dyn_cast<UnaryInstruction>(V)) {
|
||||||
|
return 0;
|
||||||
|
} else if (BinaryOperator *BO = dyn_cast<BinaryOperator>(V)) {
|
||||||
|
switch (BO->getOpcode()) {
|
||||||
|
case Instruction::Add: {
|
||||||
|
unsigned left = GetCBOffset(BO->getOperand(0));
|
||||||
|
unsigned right = GetCBOffset(BO->getOperand(1));
|
||||||
|
return left + right;
|
||||||
|
} break;
|
||||||
|
case Instruction::Or: {
|
||||||
|
unsigned left = GetCBOffset(BO->getOperand(0));
|
||||||
|
unsigned right = GetCBOffset(BO->getOperand(1));
|
||||||
|
return left | right;
|
||||||
|
} break;
|
||||||
|
default:
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
typedef std::map<unsigned, DxilFieldAnnotation*> FieldAnnotationByOffsetMap;
|
||||||
|
|
||||||
|
static void MarkCBUse(unsigned offset, FieldAnnotationByOffsetMap &fieldMap) {
|
||||||
|
auto it = fieldMap.upper_bound(offset);
|
||||||
|
it--;
|
||||||
|
if (it != fieldMap.end())
|
||||||
|
it->second->SetCBVarUsed(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
static unsigned GetOffsetForCBExtractValue(ExtractValueInst *EV, bool bMinPrecision) {
|
||||||
|
DXASSERT(EV->getNumIndices() == 1, "otherwise, unexpected indices/type for extractvalue");
|
||||||
|
unsigned typeSize = 4;
|
||||||
|
unsigned bits = EV->getType()->getScalarSizeInBits();
|
||||||
|
if (bits == 64)
|
||||||
|
typeSize = 8;
|
||||||
|
else if (bits == 16 && bMinPrecision)
|
||||||
|
typeSize = 2;
|
||||||
|
return (EV->getIndices().front() * typeSize);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void CollectInPhiChain(PHINode *cbUser, unsigned offset,
|
||||||
|
std::unordered_set<Value *> &userSet,
|
||||||
|
FieldAnnotationByOffsetMap &fieldMap,
|
||||||
|
bool bMinPrecision) {
|
||||||
|
if (userSet.count(cbUser) > 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
userSet.insert(cbUser);
|
||||||
|
for (User *cbU : cbUser->users()) {
|
||||||
|
if (ExtractValueInst *EV = dyn_cast<ExtractValueInst>(cbU)) {
|
||||||
|
MarkCBUse(offset + GetOffsetForCBExtractValue(EV, bMinPrecision), fieldMap);
|
||||||
|
} else {
|
||||||
|
PHINode *phi = cast<PHINode>(cbU);
|
||||||
|
CollectInPhiChain(phi, offset, userSet, fieldMap, bMinPrecision);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void CollectCBufferMemberUsage(Value *V,
|
||||||
|
FieldAnnotationByOffsetMap &legacyFieldMap,
|
||||||
|
FieldAnnotationByOffsetMap &newFieldMap,
|
||||||
|
hlsl::OP *hlslOP, bool bMinPrecision) {
|
||||||
|
for (auto U : V->users()) {
|
||||||
|
if (Constant *C = dyn_cast<Constant>(U)) {
|
||||||
|
CollectCBufferMemberUsage(C, legacyFieldMap, newFieldMap, hlslOP, bMinPrecision);
|
||||||
|
} else if (LoadInst *LI = dyn_cast<LoadInst>(U)) {
|
||||||
|
CollectCBufferMemberUsage(U, legacyFieldMap, newFieldMap, hlslOP, bMinPrecision);
|
||||||
|
} else if (CallInst *CI = dyn_cast<CallInst>(U)) {
|
||||||
|
if (hlslOP->IsDxilOpFuncCallInst(CI)) {
|
||||||
|
hlsl::OP::OpCode op = hlslOP->GetDxilOpFuncCallInst(CI);
|
||||||
|
if (op == DXIL::OpCode::CreateHandleForLib) {
|
||||||
|
CollectCBufferMemberUsage(U, legacyFieldMap, newFieldMap, hlslOP, bMinPrecision);
|
||||||
|
} else if (op == DXIL::OpCode::CBufferLoadLegacy) {
|
||||||
|
DxilInst_CBufferLoadLegacy cbload(CI);
|
||||||
|
Value *resIndex = cbload.get_regIndex();
|
||||||
|
unsigned offset = GetCBOffset(resIndex);
|
||||||
|
offset <<= 4; // translate 16-byte vector index to byte offset
|
||||||
|
for (User *cbU : U->users()) {
|
||||||
|
if (ExtractValueInst *EV = dyn_cast<ExtractValueInst>(cbU)) {
|
||||||
|
MarkCBUse(offset + GetOffsetForCBExtractValue(EV, bMinPrecision), legacyFieldMap);
|
||||||
|
} else {
|
||||||
|
PHINode *phi = cast<PHINode>(cbU);
|
||||||
|
std::unordered_set<Value *> userSet;
|
||||||
|
CollectInPhiChain(phi, offset, userSet, legacyFieldMap, bMinPrecision);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if (op == DXIL::OpCode::CBufferLoad) {
|
||||||
|
DxilInst_CBufferLoad cbload(CI);
|
||||||
|
Value *byteOffset = cbload.get_byteOffset();
|
||||||
|
unsigned offset = GetCBOffset(byteOffset);
|
||||||
|
MarkCBUse(offset, newFieldMap);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void DxilLowerCreateHandleForLib::UpdateCBufferUsage() {
|
||||||
|
DxilTypeSystem &TypeSys = m_DM->GetTypeSystem();
|
||||||
|
hlsl::OP *hlslOP = m_DM->GetOP();
|
||||||
|
const DataLayout &DL = m_DM->GetModule()->getDataLayout();
|
||||||
|
const auto &CBuffers = m_DM->GetCBuffers();
|
||||||
|
for (auto it = CBuffers.begin(); it != CBuffers.end(); it++) {
|
||||||
|
DxilCBuffer *CB = it->get();
|
||||||
|
GlobalVariable *GV = dyn_cast<GlobalVariable>(CB->GetGlobalSymbol());
|
||||||
|
if (GV == nullptr)
|
||||||
|
continue;
|
||||||
|
Type *ElemTy = GV->getType()->getPointerElementType();
|
||||||
|
ElemTy = dxilutil::StripArrayTypes(ElemTy, nullptr);
|
||||||
|
StructType *ST = cast<StructType>(ElemTy);
|
||||||
|
DxilStructAnnotation *SA = TypeSys.GetStructAnnotation(ST);
|
||||||
|
if (SA == nullptr)
|
||||||
|
continue;
|
||||||
|
// If elements < 2, it's used if it exists.
|
||||||
|
// Only old-style cbuffer { ... } will have more than one member, and
|
||||||
|
// old-style cbuffers are the only ones that report usage per member.
|
||||||
|
if (ST->getStructNumElements() < 2) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create offset maps for legacy layout and new compact layout, while resetting usage flags
|
||||||
|
const StructLayout *SL = DL.getStructLayout(ST);
|
||||||
|
FieldAnnotationByOffsetMap legacyFieldMap, newFieldMap;
|
||||||
|
for (unsigned i = 0; i < SA->GetNumFields(); ++i) {
|
||||||
|
DxilFieldAnnotation &FA = SA->GetFieldAnnotation(i);
|
||||||
|
FA.SetCBVarUsed(false);
|
||||||
|
legacyFieldMap[FA.GetCBufferOffset()] = &FA;
|
||||||
|
newFieldMap[(unsigned)SL->getElementOffset(i)] = &FA;
|
||||||
|
}
|
||||||
|
CollectCBufferMemberUsage(GV, legacyFieldMap, newFieldMap, hlslOP, m_DM->GetUseMinPrecision());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
char DxilLowerCreateHandleForLib::ID = 0;
|
char DxilLowerCreateHandleForLib::ID = 0;
|
||||||
|
|
Загрузка…
Ссылка в новой задаче