Add CB Usage to metadata, compute in hlsl-dxil-lower-handle-for-lib

This commit is contained in:
Tex Riddell 2019-08-12 15:32:17 -07:00
Родитель eea0c94c08
Коммит 4234a9ae53
5 изменённых файлов: 162 добавлений и 2 удалений

Просмотреть файл

@ -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;