Add resource link info for library profile.

This commit is contained in:
Xiang Li 2017-05-18 16:04:39 -07:00 коммит произвёл Xiang Li
Родитель b6e876bf39
Коммит c1bc9d945a
7 изменённых файлов: 295 добавлений и 3 удалений

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

@ -114,6 +114,7 @@ public:
// Resources.
static const char kDxilResourcesMDName[];
static const char kDxilResourcesLinkInfoMDName[];
static const unsigned kDxilNumResourceFields = 4;
static const unsigned kDxilResourceSRVs = 0;
static const unsigned kDxilResourceUAVs = 1;
@ -292,6 +293,13 @@ public:
llvm::MDTuple *pCBuffers, llvm::MDTuple *pSamplers);
void GetDxilResources(const llvm::MDOperand &MDO, const llvm::MDTuple *&pSRVs, const llvm::MDTuple *&pUAVs,
const llvm::MDTuple *&pCBuffers, const llvm::MDTuple *&pSamplers);
void EmitDxilResourceLinkInfoTuple(llvm::MDTuple *pSRVs, llvm::MDTuple *pUAVs,
llvm::MDTuple *pCBuffers,
llvm::MDTuple *pSamplers);
void LoadDxilResourceLinkInfoTuple(const llvm::MDTuple *&pSRVs,
const llvm::MDTuple *&pUAVs,
const llvm::MDTuple *&pCBuffers,
const llvm::MDTuple *&pSamplers);
void EmitDxilResourceBase(const DxilResourceBase &R, llvm::Metadata *ppMDVals[]);
void LoadDxilResourceBase(const llvm::MDOperand &MDO, DxilResourceBase &R);
llvm::MDTuple *EmitDxilSRV(const DxilResource &SRV);

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

@ -97,6 +97,11 @@ public:
const DxilResource &GetUAV(unsigned idx) const;
const std::vector<std::unique_ptr<DxilResource> > &GetUAVs() const;
void CreateResourceLinkInfo();
struct ResourceLinkInfo;
const ResourceLinkInfo &GetResourceLinkInfo(DXIL::ResourceClass resClass,
unsigned rangeID) const;
void LoadDxilResourceBaseFromMDNode(llvm::MDNode *MD, DxilResourceBase &R);
void LoadDxilResourceFromMDNode(llvm::MDNode *MD, DxilResource &R);
void LoadDxilSamplerFromMDNode(llvm::MDNode *MD, DxilSampler &S);
@ -330,6 +335,14 @@ public:
float GetMaxTessellationFactor() const;
void SetMaxTessellationFactor(float MaxTessellationFactor);
// Shader resource information only needed before linking.
// Use constant as rangeID and index for resource in a library.
// When link the library, replace these constants with real rangeID and index.
struct ResourceLinkInfo {
llvm::Constant *ResRangeID;
llvm::Constant *ResIndex;
};
private:
// Signatures.
std::unique_ptr<DxilSignature> m_InputSignature;
@ -343,6 +356,12 @@ private:
std::vector<std::unique_ptr<DxilCBuffer> > m_CBuffers;
std::vector<std::unique_ptr<DxilSampler> > m_Samplers;
// Save resource link for library, when link replace it with real resource ID.
std::vector<ResourceLinkInfo> m_SRVsLinkInfo;
std::vector<ResourceLinkInfo> m_UAVsLinkInfo;
std::vector<ResourceLinkInfo> m_CBuffersLinkInfo;
std::vector<ResourceLinkInfo> m_SamplersLinkInfo;
// Geometry shader.
DXIL::InputPrimitive m_InputPrimitive;
unsigned m_MaxVertexCount;
@ -389,6 +408,8 @@ private:
// DXIL metadata serialization/deserialization.
llvm::MDTuple *EmitDxilResources();
void LoadDxilResources(const llvm::MDOperand &MDO);
void EmitDxilResourcesLinkInfo();
void LoadDxilResourcesLinkInfo();
llvm::MDTuple *EmitDxilShaderProperties();
void LoadDxilShaderProperties(const llvm::MDOperand &MDO);

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

@ -82,8 +82,12 @@ public:
DM.GetUAVs().size() || DM.GetSRVs().size() || DM.GetSamplers().size();
if (hasResource) {
AllocateDxilResources(DM);
PatchCreateHandle(DM);
if (!DM.GetShaderModel()->IsLib()) {
AllocateDxilResources(DM);
PatchCreateHandle(DM);
} else {
PatchCreateHandleForLib(DM);
}
}
return true;
}
@ -101,6 +105,8 @@ private:
void AllocateDxilResources(DxilModule &DM);
// Add lowbound to create handle range index.
void PatchCreateHandle(DxilModule &DM);
// Add lowbound to create handle range index for library.
void PatchCreateHandleForLib(DxilModule &DM);
// Switch CBuffer for SRV for TBuffers.
void PatchTBuffers(DxilModule &DM);
};
@ -244,7 +250,8 @@ void PatchLowerBoundOfCreateHandle(CallInst *handle, DxilModule &DM) {
DXIL::ResourceClass ResClass =
static_cast<DXIL::ResourceClass>(createHandle.get_resourceClass_val());
// Not support case dynamic rangeId yet.
// Dynamic rangeId is not supported - skip and let validation report the
// error.
if (!isa<ConstantInt>(createHandle.get_rangeId()))
return;
@ -449,6 +456,51 @@ void DxilCondenseResources::PatchCreateHandle(DxilModule &DM) {
}
}
void DxilCondenseResources::PatchCreateHandleForLib(DxilModule &DM) {
Function *createHandle = DM.GetOP()->GetOpFunc(DXIL::OpCode::CreateHandle,
Type::getVoidTy(DM.GetCtx()));
DM.CreateResourceLinkInfo();
Value *zeroIndex = ConstantInt::get(Type::getInt32Ty(DM.GetCtx()), 0);
for (User *U : createHandle->users()) {
CallInst *handle = cast<CallInst>(U);
DxilInst_CreateHandle createHandle(handle);
DXASSERT_NOMSG(createHandle);
DXIL::ResourceClass ResClass =
static_cast<DXIL::ResourceClass>(createHandle.get_resourceClass_val());
// Dynamic rangeId is not supported - skip and let validation report the
// error.
if (!isa<ConstantInt>(createHandle.get_rangeId()))
continue;
unsigned rangeId =
cast<ConstantInt>(createHandle.get_rangeId())->getLimitedValue();
const DxilModule::ResourceLinkInfo &linkInfo =
DM.GetResourceLinkInfo(ResClass, rangeId);
IRBuilder<> Builder(handle);
Value *linkRangeID = Builder.CreateLoad(linkInfo.ResRangeID);
// Update rangeID to linkinfo rangeID.
handle->setArgOperand(DXIL::OperandIndex::kCreateHandleResIDOpIdx,
linkRangeID);
Value *Index = createHandle.get_index();
Value *linkIndex = Builder.CreateLoad(linkInfo.ResIndex);
if (Index == zeroIndex) {
// Update index to linkinfo index.
handle->setArgOperand(DXIL::OperandIndex::kCreateHandleResIndexOpIdx,
linkIndex);
} else {
// Add linkinfo index to index.
Value *newIdx = Builder.CreateAdd(Index, linkIndex);
handle->setArgOperand(DXIL::OperandIndex::kCreateHandleResIndexOpIdx,
newIdx);
}
}
}
char DxilCondenseResources::ID = 0;
bool llvm::AreDxilResourcesDense(llvm::Module *M, hlsl::DxilResourceBase **ppNonDense) {

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

@ -42,6 +42,7 @@ const char DxilMDHelper::kDxilVersionMDName[] = "dx.vers
const char DxilMDHelper::kDxilShaderModelMDName[] = "dx.shaderModel";
const char DxilMDHelper::kDxilEntryPointsMDName[] = "dx.entryPoints";
const char DxilMDHelper::kDxilResourcesMDName[] = "dx.resources";
const char DxilMDHelper::kDxilResourcesLinkInfoMDName[] = "dx.resources.link.info";
const char DxilMDHelper::kDxilTypeSystemMDName[] = "dx.typeAnnotations";
const char DxilMDHelper::kDxilTypeSystemHelperVariablePrefix[] = "dx.typevar.";
const char DxilMDHelper::kDxilControlFlowHintMDName[] = "dx.controlflow.hints";
@ -442,6 +443,52 @@ MDTuple *DxilMDHelper::EmitDxilResourceTuple(MDTuple *pSRVs, MDTuple *pUAVs,
return pTupleMD;
}
void DxilMDHelper::EmitDxilResourceLinkInfoTuple(MDTuple *pSRVs, MDTuple *pUAVs,
MDTuple *pCBuffers,
MDTuple *pSamplers) {
DXASSERT(pSRVs != nullptr || pUAVs != nullptr || pCBuffers != nullptr ||
pSamplers != nullptr,
"resource tuple should not be emitted if there are no resources");
Metadata *MDVals[kDxilNumResourceFields];
MDVals[kDxilResourceSRVs] = pSRVs;
MDVals[kDxilResourceUAVs] = pUAVs;
MDVals[kDxilResourceCBuffers] = pCBuffers;
MDVals[kDxilResourceSamplers] = pSamplers;
MDTuple *pTupleMD = MDNode::get(m_Ctx, MDVals);
NamedMDNode *pResourcesNamedMD =
m_pModule->getNamedMetadata(kDxilResourcesLinkInfoMDName);
IFTBOOL(pResourcesNamedMD == nullptr, DXC_E_INCORRECT_DXIL_METADATA);
pResourcesNamedMD =
m_pModule->getOrInsertNamedMetadata(kDxilResourcesLinkInfoMDName);
pResourcesNamedMD->addOperand(pTupleMD);
}
void DxilMDHelper::LoadDxilResourceLinkInfoTuple(const llvm::MDTuple *&pSRVs,
const llvm::MDTuple *&pUAVs,
const llvm::MDTuple *&pCBuffers,
const llvm::MDTuple *&pSamplers) {
NamedMDNode *pResourcesNamedMD =
m_pModule->getNamedMetadata(kDxilResourcesLinkInfoMDName);
if (!pResourcesNamedMD) {
pSRVs = pUAVs = pCBuffers = pSamplers = nullptr;
return;
}
IFTBOOL(pResourcesNamedMD->getNumOperands() == 1,
DXC_E_INCORRECT_DXIL_METADATA);
const MDTuple *pTupleMD = dyn_cast<MDTuple>(pResourcesNamedMD->getOperand(0));
IFTBOOL(pTupleMD != nullptr, DXC_E_INCORRECT_DXIL_METADATA);
IFTBOOL(pTupleMD->getNumOperands() == kDxilNumResourceFields,
DXC_E_INCORRECT_DXIL_METADATA);
pSRVs = CastToTupleOrNull(pTupleMD->getOperand(kDxilResourceSRVs));
pUAVs = CastToTupleOrNull(pTupleMD->getOperand(kDxilResourceUAVs));
pCBuffers = CastToTupleOrNull(pTupleMD->getOperand(kDxilResourceCBuffers));
pSamplers = CastToTupleOrNull(pTupleMD->getOperand(kDxilResourceSamplers));
}
void DxilMDHelper::GetDxilResources(const MDOperand &MDO, const MDTuple *&pSRVs,
const MDTuple *&pUAVs, const MDTuple *&pCBuffers,
const MDTuple *&pSamplers) {

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

@ -801,6 +801,58 @@ const vector<unique_ptr<DxilResource> > &DxilModule::GetUAVs() const {
return m_UAVs;
}
static void CreateResourceLinkConstant(Module &M, DxilResourceBase *pRes,
std::vector<DxilModule::ResourceLinkInfo> &resLinkInfo) {
Type *i32Ty = Type::getInt32Ty(M.getContext());
const bool IsConstantTrue = true;
Constant *NullInitVal = nullptr;
GlobalVariable *rangeID = new GlobalVariable(
M, i32Ty, IsConstantTrue, llvm::GlobalValue::ExternalLinkage, NullInitVal,
pRes->GetGlobalName() + "_rangeID");
GlobalVariable *index = new GlobalVariable(
M, i32Ty, IsConstantTrue, llvm::GlobalValue::ExternalLinkage, NullInitVal,
pRes->GetGlobalName() + "_index");
resLinkInfo.emplace_back(DxilModule::ResourceLinkInfo{rangeID, index});
}
void DxilModule::CreateResourceLinkInfo() {
DXASSERT(GetShaderModel()->IsLib(), "only for library profile");
DXASSERT(m_SRVsLinkInfo.empty() && m_UAVsLinkInfo.empty() &&
m_CBuffersLinkInfo.empty() && m_SamplersLinkInfo.empty(),
"else resource link info was already created");
Module &M = *m_pModule;
for (auto &SRV : m_SRVs) {
CreateResourceLinkConstant(M, SRV.get(), m_SRVsLinkInfo);
}
for (auto &UAV : m_UAVs) {
CreateResourceLinkConstant(M, UAV.get(), m_UAVsLinkInfo);
}
for (auto &CBuffer : m_CBuffers) {
CreateResourceLinkConstant(M, CBuffer.get(), m_CBuffersLinkInfo);
}
for (auto &Sampler : m_Samplers) {
CreateResourceLinkConstant(M, Sampler.get(), m_SamplersLinkInfo);
}
}
const DxilModule::ResourceLinkInfo &
DxilModule::GetResourceLinkInfo(DXIL::ResourceClass resClass,
unsigned rangeID) const {
switch (resClass) {
case DXIL::ResourceClass::UAV:
return m_UAVsLinkInfo[rangeID];
case DXIL::ResourceClass::CBuffer:
return m_CBuffersLinkInfo[rangeID];
case DXIL::ResourceClass::Sampler:
return m_SamplersLinkInfo[rangeID];
default:
DXASSERT(DXIL::ResourceClass::SRV == resClass,
"else invalid resource class");
return m_SRVsLinkInfo[rangeID];
}
}
void DxilModule::LoadDxilResourceBaseFromMDNode(MDNode *MD, DxilResourceBase &R) {
return m_pMDHelper->LoadDxilResourceBaseFromMDNode(MD, R);
}
@ -1068,6 +1120,8 @@ void DxilModule::EmitDxilMetadata() {
if (!m_RootSignature->IsEmpty()) {
m_pMDHelper->EmitRootSignature(*m_RootSignature.get());
}
if (m_pSM->IsLib())
EmitDxilResourcesLinkInfo();
}
bool DxilModule::IsKnownNamedMetaData(llvm::NamedMDNode &Node) {
@ -1104,6 +1158,9 @@ void DxilModule::LoadDxilMetadata() {
m_pMDHelper->LoadRootSignature(*m_RootSignature.get());
m_pMDHelper->LoadDxilViewIdState(*m_pViewIdState.get());
if (loadedModule->IsLib())
LoadDxilResourcesLinkInfo();
}
MDTuple *DxilModule::EmitDxilResources() {
@ -1198,6 +1255,85 @@ void DxilModule::LoadDxilResources(const llvm::MDOperand &MDO) {
}
}
static MDTuple *CreateResourcesLinkInfo(std::vector<DxilModule::ResourceLinkInfo> &LinkInfoList,
unsigned size, LLVMContext &Ctx) {
DXASSERT(size == LinkInfoList.size(), "link info size must match resource size");
if (LinkInfoList.empty())
return nullptr;
vector<Metadata *> MDVals;
for (size_t i = 0; i < size; i++) {
MDVals.emplace_back(ValueAsMetadata::get(LinkInfoList[i].ResRangeID));
MDVals.emplace_back(ValueAsMetadata::get(LinkInfoList[i].ResIndex));
}
return MDNode::get(Ctx, MDVals);
}
void DxilModule::EmitDxilResourcesLinkInfo() {
// Emit SRV base records.
MDTuple *pTupleSRVs =
CreateResourcesLinkInfo(m_SRVsLinkInfo, m_SRVs.size(), m_Ctx);
// Emit UAV base records.
MDTuple *pTupleUAVs =
CreateResourcesLinkInfo(m_UAVsLinkInfo, m_UAVs.size(), m_Ctx);
// Emit CBuffer base records.
MDTuple *pTupleCBuffers =
CreateResourcesLinkInfo(m_CBuffersLinkInfo, m_CBuffers.size(), m_Ctx);
// Emit Sampler records.
MDTuple *pTupleSamplers =
CreateResourcesLinkInfo(m_SamplersLinkInfo, m_Samplers.size(), m_Ctx);
if (pTupleSRVs != nullptr || pTupleUAVs != nullptr ||
pTupleCBuffers != nullptr || pTupleSamplers != nullptr) {
m_pMDHelper->EmitDxilResourceLinkInfoTuple(pTupleSRVs, pTupleUAVs,
pTupleCBuffers, pTupleSamplers);
}
}
static void
LoadResourcesLinkInfo(const llvm::MDTuple *pMD,
std::vector<DxilModule::ResourceLinkInfo> &LinkInfoList,
unsigned size, DxilMDHelper *pMDHelper) {
if (!pMD) {
IFTBOOL(size == 0, DXC_E_INCORRECT_DXIL_METADATA);
return;
}
unsigned operandSize = pMD->getNumOperands();
IFTBOOL(operandSize == (2 * size), DXC_E_INCORRECT_DXIL_METADATA);
for (unsigned i = 0; i < operandSize; i += 2) {
Constant *rangeID =
dyn_cast<Constant>(pMDHelper->ValueMDToValue(pMD->getOperand(i)));
Constant *index =
dyn_cast<Constant>(pMDHelper->ValueMDToValue(pMD->getOperand(i + 1)));
LinkInfoList.emplace_back(DxilModule::ResourceLinkInfo{rangeID, index});
}
}
void DxilModule::LoadDxilResourcesLinkInfo() {
const llvm::MDTuple *pSRVs, *pUAVs, *pCBuffers, *pSamplers;
m_pMDHelper->LoadDxilResourceLinkInfoTuple(pSRVs, pUAVs, pCBuffers,
pSamplers);
// Load SRV base records.
LoadResourcesLinkInfo(pSRVs, m_SRVsLinkInfo, m_SRVs.size(),
m_pMDHelper.get());
// Load UAV base records.
LoadResourcesLinkInfo(pUAVs, m_UAVsLinkInfo, m_UAVs.size(),
m_pMDHelper.get());
// Load CBuffer records.
LoadResourcesLinkInfo(pCBuffers, m_CBuffersLinkInfo, m_CBuffers.size(),
m_pMDHelper.get());
// Load Sampler records.
LoadResourcesLinkInfo(pSamplers, m_SamplersLinkInfo, m_Samplers.size(),
m_pMDHelper.get());
}
MDTuple *DxilModule::EmitDxilShaderProperties() {
vector<Metadata *> MDVals;

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

@ -0,0 +1,23 @@
// RUN: %dxc -T lib_6_1 %s | FileCheck %s
// Make sure globals for link info exist.
// CHECK: g_txDiffuse_rangeID
// CHECK: g_txDiffuse_index
// CHECK: g_samLinear_rangeID
// CHECK: g_samLinear_index
// Make sure link info metadata exist.
// CHECK: dx.resources.link.info
// CHECK: !{i32* @g_txDiffuse_rangeID, i32* @g_txDiffuse_index}
// CHECK: !{i32* @g_samLinear_rangeID, i32* @g_samLinear_index}
Texture2D g_txDiffuse;
SamplerState g_samLinear;
float4 test(float2 c : C) : SV_TARGET
{
float4 x = g_txDiffuse.Sample( g_samLinear, c );
return x;
}

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

@ -501,6 +501,7 @@ public:
TEST_METHOD(CodeGenIntrinsic5)
TEST_METHOD(CodeGenInvalidInputOutputTypes)
TEST_METHOD(CodeGenLegacyStruct)
TEST_METHOD(CodeGenLibResource)
TEST_METHOD(CodeGenLibUnusedFunc)
TEST_METHOD(CodeGenLitInParen)
TEST_METHOD(CodeGenLiteralShift)
@ -2772,6 +2773,10 @@ TEST_F(CompilerTest, CodeGenLegacyStruct) {
CodeGenTestCheck(L"..\\CodeGenHLSL\\legacy_struct.hlsl");
}
TEST_F(CompilerTest, CodeGenLibResource) {
CodeGenTestCheck(L"..\\CodeGenHLSL\\lib_resource.hlsl");
}
TEST_F(CompilerTest, CodeGenLibUnusedFunc) {
CodeGenTestCheck(L"..\\CodeGenHLSL\\lib_unused_func.hlsl");
}