| /////////////////////////////////////////////////////////////////////////////// |
| // // |
| // DxilMetadataHelper.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/Support/Global.h" |
| #include "dxc/DXIL/DxilMetadataHelper.h" |
| #include "dxc/DXIL/DxilShaderModel.h" |
| #include "dxc/DXIL/DxilCBuffer.h" |
| #include "dxc/DXIL/DxilResource.h" |
| #include "dxc/DXIL/DxilSampler.h" |
| #include "dxc/DXIL/DxilSignatureElement.h" |
| #include "dxc/DXIL/DxilSignature.h" |
| #include "dxc/DXIL/DxilTypeSystem.h" |
| #include "dxc/DXIL/DxilFunctionProps.h" |
| #include "dxc/DXIL/DxilShaderFlags.h" |
| #include "dxc/DXIL/DxilSubobject.h" |
| |
| #include "llvm/IR/Constants.h" |
| #include "llvm/IR/Function.h" |
| #include "llvm/IR/IntrinsicInst.h" |
| #include "llvm/IR/LLVMContext.h" |
| #include "llvm/IR/Metadata.h" |
| #include "llvm/IR/Module.h" |
| #include "llvm/Support/raw_ostream.h" |
| #include "llvm/ADT/DenseSet.h" |
| #include <array> |
| #include <algorithm> |
| |
| #include "dxc/Support/WinIncludes.h" |
| #include "dxc/Support/WinFunctions.h" |
| |
| using namespace llvm; |
| using std::string; |
| using std::vector; |
| using std::unique_ptr; |
| |
| |
| namespace hlsl { |
| |
| const char DxilMDHelper::kDxilVersionMDName[] = "dx.version"; |
| const char DxilMDHelper::kDxilShaderModelMDName[] = "dx.shaderModel"; |
| const char DxilMDHelper::kDxilEntryPointsMDName[] = "dx.entryPoints"; |
| const char DxilMDHelper::kDxilResourcesMDName[] = "dx.resources"; |
| const char DxilMDHelper::kDxilTypeSystemMDName[] = "dx.typeAnnotations"; |
| const char DxilMDHelper::kDxilTypeSystemHelperVariablePrefix[] = "dx.typevar."; |
| const char DxilMDHelper::kDxilControlFlowHintMDName[] = "dx.controlflow.hints"; |
| const char DxilMDHelper::kDxilPreciseAttributeMDName[] = "dx.precise"; |
| const char DxilMDHelper::kDxilVariableDebugLayoutMDName[] = "dx.dbg.varlayout"; |
| const char DxilMDHelper::kDxilTempAllocaMDName[] = "dx.temp"; |
| const char DxilMDHelper::kDxilNonUniformAttributeMDName[] = "dx.nonuniform"; |
| const char DxilMDHelper::kHLDxilResourceAttributeMDName[] = "dx.hl.resource.attribute"; |
| const char DxilMDHelper::kDxilValidatorVersionMDName[] = "dx.valver"; |
| |
| // This named metadata is not valid in final module (should be moved to DxilContainer) |
| const char DxilMDHelper::kDxilRootSignatureMDName[] = "dx.rootSignature"; |
| const char DxilMDHelper::kDxilIntermediateOptionsMDName[] = "dx.intermediateOptions"; |
| const char DxilMDHelper::kDxilViewIdStateMDName[] = "dx.viewIdState"; |
| const char DxilMDHelper::kDxilSubobjectsMDName[] = "dx.subobjects"; |
| |
| const char DxilMDHelper::kDxilSourceContentsMDName[] = "dx.source.contents"; |
| const char DxilMDHelper::kDxilSourceDefinesMDName[] = "dx.source.defines"; |
| const char DxilMDHelper::kDxilSourceMainFileNameMDName[] = "dx.source.mainFileName"; |
| const char DxilMDHelper::kDxilSourceArgsMDName[] = "dx.source.args"; |
| |
| static std::array<const char *, 7> DxilMDNames = { { |
| DxilMDHelper::kDxilVersionMDName, |
| DxilMDHelper::kDxilShaderModelMDName, |
| DxilMDHelper::kDxilEntryPointsMDName, |
| DxilMDHelper::kDxilResourcesMDName, |
| DxilMDHelper::kDxilTypeSystemMDName, |
| DxilMDHelper::kDxilValidatorVersionMDName, |
| DxilMDHelper::kDxilViewIdStateMDName, |
| }}; |
| |
| DxilMDHelper::DxilMDHelper(Module *pModule, std::unique_ptr<ExtraPropertyHelper> EPH) |
| : m_Ctx(pModule->getContext()) |
| , m_pModule(pModule) |
| , m_pSM(nullptr) |
| , m_ExtraPropertyHelper(std::move(EPH)) |
| , m_ValMajor(1) |
| , m_ValMinor(0) |
| , m_MinValMajor(1) |
| , m_MinValMinor(0) |
| , m_bExtraMetadata(false) |
| { |
| } |
| |
| DxilMDHelper::~DxilMDHelper() { |
| } |
| |
| void DxilMDHelper::SetShaderModel(const ShaderModel *pSM) { |
| m_pSM = pSM; |
| m_pSM->GetMinValidatorVersion(m_MinValMajor, m_MinValMinor); |
| if (DXIL::CompareVersions(m_ValMajor, m_ValMinor, m_MinValMajor, m_MinValMinor) < 0) { |
| m_ValMajor = m_MinValMajor; |
| m_ValMinor = m_MinValMinor; |
| } |
| // Validator version 0.0 is not meant for validation or retail driver consumption, |
| // and is used for separate reflection. |
| // MinVal version drives metadata decisions for compatilbility, so snap this to |
| // latest for reflection/no validation case. |
| if (DXIL::CompareVersions(m_ValMajor, m_ValMinor, 0, 0) == 0) { |
| m_MinValMajor = 0; |
| m_MinValMinor = 0; |
| } |
| if (m_ExtraPropertyHelper) { |
| m_ExtraPropertyHelper->m_ValMajor = m_ValMajor; |
| m_ExtraPropertyHelper->m_ValMinor = m_ValMinor; |
| m_ExtraPropertyHelper->m_MinValMajor = m_MinValMajor; |
| m_ExtraPropertyHelper->m_MinValMinor = m_MinValMinor; |
| } |
| } |
| |
| const ShaderModel *DxilMDHelper::GetShaderModel() const { |
| return m_pSM; |
| } |
| |
| // |
| // DXIL version. |
| // |
| void DxilMDHelper::EmitDxilVersion(unsigned Major, unsigned Minor) { |
| NamedMDNode *pDxilVersionMD = m_pModule->getNamedMetadata(kDxilVersionMDName); |
| IFTBOOL(pDxilVersionMD == nullptr, DXC_E_INCORRECT_DXIL_METADATA); |
| pDxilVersionMD = m_pModule->getOrInsertNamedMetadata(kDxilVersionMDName); |
| |
| Metadata *MDVals[kDxilVersionNumFields]; |
| MDVals[kDxilVersionMajorIdx] = Uint32ToConstMD(Major); |
| MDVals[kDxilVersionMinorIdx] = Uint32ToConstMD(Minor); |
| |
| pDxilVersionMD->addOperand(MDNode::get(m_Ctx, MDVals)); |
| } |
| |
| void DxilMDHelper::LoadDxilVersion(unsigned &Major, unsigned &Minor) { |
| NamedMDNode *pDxilVersionMD = m_pModule->getNamedMetadata(kDxilVersionMDName); |
| IFTBOOL(pDxilVersionMD != nullptr, DXC_E_INCORRECT_DXIL_METADATA); |
| IFTBOOL(pDxilVersionMD->getNumOperands() == 1, DXC_E_INCORRECT_DXIL_METADATA); |
| |
| MDNode *pVersionMD = pDxilVersionMD->getOperand(0); |
| IFTBOOL(pVersionMD->getNumOperands() == kDxilVersionNumFields, DXC_E_INCORRECT_DXIL_METADATA); |
| |
| Major = ConstMDToUint32(pVersionMD->getOperand(kDxilVersionMajorIdx)); |
| Minor = ConstMDToUint32(pVersionMD->getOperand(kDxilVersionMinorIdx)); |
| } |
| |
| // |
| // Validator version. |
| // |
| void DxilMDHelper::EmitValidatorVersion(unsigned Major, unsigned Minor) { |
| NamedMDNode *pDxilValidatorVersionMD = m_pModule->getNamedMetadata(kDxilValidatorVersionMDName); |
| |
| // Allow re-writing the validator version, since this can be changed at later points. |
| if (pDxilValidatorVersionMD) |
| m_pModule->eraseNamedMetadata(pDxilValidatorVersionMD); |
| |
| pDxilValidatorVersionMD = m_pModule->getOrInsertNamedMetadata(kDxilValidatorVersionMDName); |
| |
| Metadata *MDVals[kDxilVersionNumFields]; |
| MDVals[kDxilVersionMajorIdx] = Uint32ToConstMD(Major); |
| MDVals[kDxilVersionMinorIdx] = Uint32ToConstMD(Minor); |
| |
| pDxilValidatorVersionMD->addOperand(MDNode::get(m_Ctx, MDVals)); |
| |
| m_ValMajor = Major; m_ValMinor = Minor; // Keep these for later use |
| } |
| |
| void DxilMDHelper::LoadValidatorVersion(unsigned &Major, unsigned &Minor) { |
| NamedMDNode *pDxilValidatorVersionMD = m_pModule->getNamedMetadata(kDxilValidatorVersionMDName); |
| |
| if (pDxilValidatorVersionMD == nullptr) { |
| // If no validator version metadata, assume 1.0 |
| Major = 1; |
| Minor = 0; |
| m_ValMajor = Major; m_ValMinor = Minor; // Keep these for later use |
| return; |
| } |
| |
| IFTBOOL(pDxilValidatorVersionMD->getNumOperands() == 1, DXC_E_INCORRECT_DXIL_METADATA); |
| |
| MDNode *pVersionMD = pDxilValidatorVersionMD->getOperand(0); |
| IFTBOOL(pVersionMD->getNumOperands() == kDxilVersionNumFields, DXC_E_INCORRECT_DXIL_METADATA); |
| |
| Major = ConstMDToUint32(pVersionMD->getOperand(kDxilVersionMajorIdx)); |
| Minor = ConstMDToUint32(pVersionMD->getOperand(kDxilVersionMinorIdx)); |
| m_ValMajor = Major; m_ValMinor = Minor; // Keep these for later use |
| } |
| |
| // |
| // DXIL shader model. |
| // |
| void DxilMDHelper::EmitDxilShaderModel(const ShaderModel *pSM) { |
| NamedMDNode *pShaderModelNamedMD = m_pModule->getNamedMetadata(kDxilShaderModelMDName); |
| IFTBOOL(pShaderModelNamedMD == nullptr, DXC_E_INCORRECT_DXIL_METADATA); |
| pShaderModelNamedMD = m_pModule->getOrInsertNamedMetadata(kDxilShaderModelMDName); |
| |
| Metadata *MDVals[kDxilShaderModelNumFields]; |
| MDVals[kDxilShaderModelTypeIdx ] = MDString::get(m_Ctx, pSM->GetKindName()); |
| MDVals[kDxilShaderModelMajorIdx] = Uint32ToConstMD(pSM->GetMajor()); |
| MDVals[kDxilShaderModelMinorIdx] = Uint32ToConstMD(pSM->GetMinor()); |
| |
| pShaderModelNamedMD->addOperand(MDNode::get(m_Ctx, MDVals)); |
| |
| SetShaderModel(pSM); |
| } |
| |
| void DxilMDHelper::LoadDxilShaderModel(const ShaderModel *&pSM) { |
| NamedMDNode *pShaderModelNamedMD = m_pModule->getNamedMetadata(kDxilShaderModelMDName); |
| IFTBOOL(pShaderModelNamedMD != nullptr, DXC_E_INCORRECT_DXIL_METADATA); |
| IFTBOOL(pShaderModelNamedMD->getNumOperands() == 1, DXC_E_INCORRECT_DXIL_METADATA); |
| |
| MDNode *pShaderModelMD = pShaderModelNamedMD->getOperand(0); |
| IFTBOOL(pShaderModelMD->getNumOperands() == kDxilShaderModelNumFields, DXC_E_INCORRECT_DXIL_METADATA); |
| |
| MDString *pShaderTypeMD = dyn_cast<MDString>(pShaderModelMD->getOperand(kDxilShaderModelTypeIdx)); |
| IFTBOOL(pShaderTypeMD != nullptr, DXC_E_INCORRECT_DXIL_METADATA); |
| unsigned Major = ConstMDToUint32(pShaderModelMD->getOperand(kDxilShaderModelMajorIdx)); |
| unsigned Minor = ConstMDToUint32(pShaderModelMD->getOperand(kDxilShaderModelMinorIdx)); |
| string ShaderModelName = pShaderTypeMD->getString(); |
| ShaderModelName += "_" + std::to_string(Major) + "_" + |
| (Minor == ShaderModel::kOfflineMinor ? "x" : std::to_string(Minor)); |
| pSM = ShaderModel::GetByName(ShaderModelName.c_str()); |
| if (!pSM->IsValidForDxil()) { |
| char ErrorMsgTxt[40]; |
| StringCchPrintfA(ErrorMsgTxt, _countof(ErrorMsgTxt), |
| "Unknown shader model '%s'", ShaderModelName.c_str()); |
| string ErrorMsg(ErrorMsgTxt); |
| throw hlsl::Exception(DXC_E_INCORRECT_DXIL_METADATA, ErrorMsg); |
| } |
| SetShaderModel(pSM); |
| } |
| |
| // |
| // intermediate options. |
| // |
| void DxilMDHelper::EmitDxilIntermediateOptions(uint32_t flags) { |
| if (flags == 0) return; |
| |
| NamedMDNode *pIntermediateOptionsNamedMD = m_pModule->getNamedMetadata(kDxilIntermediateOptionsMDName); |
| IFTBOOL(pIntermediateOptionsNamedMD == nullptr, DXC_E_INCORRECT_DXIL_METADATA); |
| pIntermediateOptionsNamedMD = m_pModule->getOrInsertNamedMetadata(kDxilIntermediateOptionsMDName); |
| |
| pIntermediateOptionsNamedMD->addOperand( |
| MDNode::get(m_Ctx, { Uint32ToConstMD(kDxilIntermediateOptionsFlags), Uint32ToConstMD(flags) })); |
| } |
| |
| void DxilMDHelper::LoadDxilIntermediateOptions(uint32_t &flags) { |
| flags = 0; |
| |
| NamedMDNode *pIntermediateOptionsNamedMD = m_pModule->getNamedMetadata(kDxilIntermediateOptionsMDName); |
| if (pIntermediateOptionsNamedMD == nullptr) return; |
| |
| for (unsigned i = 0; i < pIntermediateOptionsNamedMD->getNumOperands(); i++) { |
| MDTuple *pEntry = dyn_cast<MDTuple>(pIntermediateOptionsNamedMD->getOperand(i)); |
| IFTBOOL(pEntry != nullptr, DXC_E_INCORRECT_DXIL_METADATA); |
| IFTBOOL(pEntry->getNumOperands() >= 1, DXC_E_INCORRECT_DXIL_METADATA); |
| |
| uint32_t id = ConstMDToUint32(pEntry->getOperand(0)); |
| switch (id) { |
| case kDxilIntermediateOptionsFlags: |
| IFTBOOL(pEntry->getNumOperands() == 2, DXC_E_INCORRECT_DXIL_METADATA); |
| flags = ConstMDToUint32(pEntry->getOperand(1)); |
| break; |
| |
| default: throw hlsl::Exception(DXC_E_INCORRECT_DXIL_METADATA, "Unrecognized intermediate options metadata"); |
| } |
| } |
| } |
| |
| // |
| // Entry points. |
| // |
| void DxilMDHelper::EmitDxilEntryPoints(vector<MDNode *> &MDEntries) { |
| DXASSERT(MDEntries.size() == 1 || GetShaderModel()->IsLib(), |
| "only one entry point is supported for now"); |
| NamedMDNode *pEntryPointsNamedMD = m_pModule->getNamedMetadata(kDxilEntryPointsMDName); |
| IFTBOOL(pEntryPointsNamedMD == nullptr, DXC_E_INCORRECT_DXIL_METADATA); |
| pEntryPointsNamedMD = m_pModule->getOrInsertNamedMetadata(kDxilEntryPointsMDName); |
| |
| for (size_t i = 0; i < MDEntries.size(); i++) { |
| pEntryPointsNamedMD->addOperand(MDEntries[i]); |
| } |
| } |
| |
| void DxilMDHelper::UpdateDxilEntryPoints(vector<MDNode *> &MDEntries) { |
| DXASSERT(MDEntries.size() == 1, "only one entry point is supported for now"); |
| NamedMDNode *pEntryPointsNamedMD = |
| m_pModule->getNamedMetadata(kDxilEntryPointsMDName); |
| IFTBOOL(pEntryPointsNamedMD != nullptr, DXC_E_INCORRECT_DXIL_METADATA); |
| |
| for (size_t i = 0; i < MDEntries.size(); i++) { |
| pEntryPointsNamedMD->setOperand(i, MDEntries[i]); |
| } |
| } |
| |
| const NamedMDNode *DxilMDHelper::GetDxilEntryPoints() { |
| NamedMDNode *pEntryPointsNamedMD = m_pModule->getNamedMetadata(kDxilEntryPointsMDName); |
| IFTBOOL(pEntryPointsNamedMD != nullptr, DXC_E_INCORRECT_DXIL_METADATA); |
| |
| return pEntryPointsNamedMD; |
| } |
| |
| MDTuple *DxilMDHelper::EmitDxilEntryPointTuple(Function *pFunc, const string &Name, |
| MDTuple *pSignatures, MDTuple *pResources, |
| MDTuple *pProperties) { |
| Metadata *MDVals[kDxilEntryPointNumFields]; |
| MDVals[kDxilEntryPointFunction ] = pFunc ? ValueAsMetadata::get(pFunc) : nullptr; |
| MDVals[kDxilEntryPointName ] = MDString::get(m_Ctx, Name.c_str()); |
| MDVals[kDxilEntryPointSignatures] = pSignatures; |
| MDVals[kDxilEntryPointResources ] = pResources; |
| MDVals[kDxilEntryPointProperties] = pProperties; |
| return MDNode::get(m_Ctx, MDVals); |
| } |
| |
| void DxilMDHelper::GetDxilEntryPoint(const MDNode *MDO, Function *&pFunc, string &Name, |
| const MDOperand *&pSignatures, const MDOperand *&pResources, |
| const MDOperand *&pProperties) { |
| IFTBOOL(MDO != nullptr, DXC_E_INCORRECT_DXIL_METADATA); |
| const MDTuple *pTupleMD = dyn_cast<MDTuple>(MDO); |
| IFTBOOL(pTupleMD != nullptr, DXC_E_INCORRECT_DXIL_METADATA); |
| IFTBOOL(pTupleMD->getNumOperands() == kDxilEntryPointNumFields, DXC_E_INCORRECT_DXIL_METADATA); |
| |
| // Retrieve entry function symbol. |
| const MDOperand &MDOFunc = pTupleMD->getOperand(kDxilEntryPointFunction); |
| if (MDOFunc.get() != nullptr) { |
| ValueAsMetadata *pValueFunc = dyn_cast<ValueAsMetadata>(MDOFunc.get()); |
| IFTBOOL(pValueFunc != nullptr, DXC_E_INCORRECT_DXIL_METADATA); |
| pFunc = dyn_cast<Function>(pValueFunc->getValue()); |
| IFTBOOL(pFunc != nullptr, DXC_E_INCORRECT_DXIL_METADATA); |
| } else { |
| pFunc = nullptr; // pass-through CP. |
| } |
| |
| // Retrieve entry function name. |
| const MDOperand &MDOName = pTupleMD->getOperand(kDxilEntryPointName); |
| IFTBOOL(MDOName.get() != nullptr, DXC_E_INCORRECT_DXIL_METADATA); |
| MDString *pMDName = dyn_cast<MDString>(MDOName); |
| IFTBOOL(pMDName != nullptr, DXC_E_INCORRECT_DXIL_METADATA); |
| Name = pMDName->getString(); |
| |
| pSignatures = &pTupleMD->getOperand(kDxilEntryPointSignatures); |
| pResources = &pTupleMD->getOperand(kDxilEntryPointResources ); |
| pProperties = &pTupleMD->getOperand(kDxilEntryPointProperties); |
| } |
| |
| // |
| // Signatures. |
| // |
| MDTuple *DxilMDHelper::EmitDxilSignatures(const DxilEntrySignature &EntrySig) { |
| MDTuple *pSignatureTupleMD = nullptr; |
| |
| const DxilSignature &InputSig = EntrySig.InputSignature; |
| const DxilSignature &OutputSig = EntrySig.OutputSignature; |
| const DxilSignature &PCPSig = EntrySig.PatchConstOrPrimSignature; |
| |
| if (!InputSig.GetElements().empty() || !OutputSig.GetElements().empty() || !PCPSig.GetElements().empty()) { |
| Metadata *MDVals[kDxilNumSignatureFields]; |
| MDVals[kDxilInputSignature] = EmitSignatureMetadata(InputSig); |
| MDVals[kDxilOutputSignature] = EmitSignatureMetadata(OutputSig); |
| MDVals[kDxilPatchConstantSignature] = EmitSignatureMetadata(PCPSig); |
| |
| pSignatureTupleMD = MDNode::get(m_Ctx, MDVals); |
| } |
| |
| return pSignatureTupleMD; |
| } |
| |
| void DxilMDHelper::EmitRootSignature( |
| std::vector<uint8_t> &SerializedRootSignature) { |
| if (SerializedRootSignature.empty()) { |
| return; |
| } |
| |
| Constant *V = llvm::ConstantDataArray::get( |
| m_Ctx, llvm::ArrayRef<uint8_t>(SerializedRootSignature.data(), |
| SerializedRootSignature.size())); |
| |
| NamedMDNode *pRootSignatureNamedMD = m_pModule->getNamedMetadata(kDxilRootSignatureMDName); |
| IFTBOOL(pRootSignatureNamedMD == nullptr, DXC_E_INCORRECT_DXIL_METADATA); |
| pRootSignatureNamedMD = m_pModule->getOrInsertNamedMetadata(kDxilRootSignatureMDName); |
| pRootSignatureNamedMD->addOperand(MDNode::get(m_Ctx, {ConstantAsMetadata::get(V)})); |
| return ; |
| } |
| |
| void DxilMDHelper::LoadDxilSignatures(const MDOperand &MDO, DxilEntrySignature &EntrySig) { |
| if (MDO.get() == nullptr) |
| return; |
| DxilSignature &InputSig = EntrySig.InputSignature; |
| DxilSignature &OutputSig = EntrySig.OutputSignature; |
| DxilSignature &PCPSig = EntrySig.PatchConstOrPrimSignature; |
| const MDTuple *pTupleMD = dyn_cast<MDTuple>(MDO.get()); |
| IFTBOOL(pTupleMD != nullptr, DXC_E_INCORRECT_DXIL_METADATA); |
| IFTBOOL(pTupleMD->getNumOperands() == kDxilNumSignatureFields, DXC_E_INCORRECT_DXIL_METADATA); |
| |
| LoadSignatureMetadata(pTupleMD->getOperand(kDxilInputSignature), InputSig); |
| LoadSignatureMetadata(pTupleMD->getOperand(kDxilOutputSignature), OutputSig); |
| LoadSignatureMetadata(pTupleMD->getOperand(kDxilPatchConstantSignature), PCPSig); |
| } |
| |
| MDTuple *DxilMDHelper::EmitSignatureMetadata(const DxilSignature &Sig) { |
| auto &Elements = Sig.GetElements(); |
| if (Elements.empty()) |
| return nullptr; |
| |
| vector<Metadata *> MDVals; |
| for (size_t i = 0; i < Elements.size(); i++) { |
| MDVals.emplace_back(EmitSignatureElement(*Elements[i])); |
| } |
| |
| return MDNode::get(m_Ctx, MDVals); |
| } |
| |
| void DxilMDHelper::LoadSignatureMetadata(const MDOperand &MDO, DxilSignature &Sig) { |
| if (MDO.get() == nullptr) |
| return; |
| |
| const MDTuple *pTupleMD = dyn_cast<MDTuple>(MDO.get()); |
| IFTBOOL(pTupleMD != nullptr, DXC_E_INCORRECT_DXIL_METADATA); |
| |
| for (unsigned i = 0; i < pTupleMD->getNumOperands(); i++) { |
| unique_ptr<DxilSignatureElement> pSE(Sig.CreateElement()); |
| LoadSignatureElement(pTupleMD->getOperand(i), *pSE.get()); |
| Sig.AppendElement(std::move(pSE)); |
| } |
| } |
| |
| void DxilMDHelper::LoadRootSignature(std::vector<uint8_t> &SerializedRootSignature) { |
| NamedMDNode *pRootSignatureNamedMD = m_pModule->getNamedMetadata(kDxilRootSignatureMDName); |
| if(!pRootSignatureNamedMD) |
| return; |
| |
| IFTBOOL(pRootSignatureNamedMD->getNumOperands() == 1, DXC_E_INCORRECT_DXIL_METADATA); |
| |
| MDNode *pNode = pRootSignatureNamedMD->getOperand(0); |
| IFTBOOL(pNode->getNumOperands() == 1, DXC_E_INCORRECT_DXIL_METADATA); |
| const MDOperand &MDO = pNode->getOperand(0); |
| |
| const ConstantAsMetadata *pMetaData = dyn_cast<ConstantAsMetadata>(MDO.get()); |
| IFTBOOL(pMetaData != nullptr, DXC_E_INCORRECT_DXIL_METADATA); |
| const ConstantDataArray *pData = |
| dyn_cast<ConstantDataArray>(pMetaData->getValue()); |
| IFTBOOL(pData != nullptr, DXC_E_INCORRECT_DXIL_METADATA); |
| IFTBOOL(pData->getElementType() == Type::getInt8Ty(m_Ctx), |
| DXC_E_INCORRECT_DXIL_METADATA); |
| |
| SerializedRootSignature.clear(); |
| unsigned size = pData->getRawDataValues().size(); |
| SerializedRootSignature.resize(size); |
| memcpy(SerializedRootSignature.data(), |
| (const uint8_t *)pData->getRawDataValues().begin(), size); |
| } |
| |
| static const MDTuple *CastToTupleOrNull(const MDOperand &MDO) { |
| if (MDO.get() == nullptr) |
| return nullptr; |
| |
| const MDTuple *pTupleMD = dyn_cast<MDTuple>(MDO.get()); |
| IFTBOOL(pTupleMD != nullptr, DXC_E_INCORRECT_DXIL_METADATA); |
| return pTupleMD; |
| } |
| |
| MDTuple *DxilMDHelper::EmitSignatureElement(const DxilSignatureElement &SE) { |
| Metadata *MDVals[kDxilSignatureElementNumFields]; |
| |
| MDVals[kDxilSignatureElementID ] = Uint32ToConstMD(SE.GetID()); |
| MDVals[kDxilSignatureElementName ] = MDString::get(m_Ctx, SE.GetName()); |
| MDVals[kDxilSignatureElementType ] = Uint8ToConstMD((uint8_t)SE.GetCompType().GetKind()); |
| MDVals[kDxilSignatureElementSystemValue ] = Uint8ToConstMD((uint8_t)SE.GetKind()); |
| MDVals[kDxilSignatureElementIndexVector ] = Uint32VectorToConstMDTuple(SE.GetSemanticIndexVec()); |
| MDVals[kDxilSignatureElementInterpMode ] = Uint8ToConstMD((uint8_t)SE.GetInterpolationMode()->GetKind()); |
| MDVals[kDxilSignatureElementRows ] = Uint32ToConstMD(SE.GetRows()); |
| MDVals[kDxilSignatureElementCols ] = Uint8ToConstMD((uint8_t)SE.GetCols()); |
| MDVals[kDxilSignatureElementStartRow ] = Int32ToConstMD(SE.GetStartRow()); |
| MDVals[kDxilSignatureElementStartCol ] = Int8ToConstMD((int8_t)SE.GetStartCol()); |
| |
| // Name-value list of extended properties. |
| MDVals[kDxilSignatureElementNameValueList] = nullptr; |
| vector<Metadata *> MDExtraVals; |
| m_ExtraPropertyHelper->EmitSignatureElementProperties(SE, MDExtraVals); |
| if (!MDExtraVals.empty()) { |
| MDVals[kDxilSignatureElementNameValueList] = MDNode::get(m_Ctx, MDExtraVals); |
| } |
| |
| // NOTE: when extra properties for signature elements are needed, extend ExtraPropertyHelper. |
| |
| return MDNode::get(m_Ctx, MDVals); |
| } |
| |
| void DxilMDHelper::LoadSignatureElement(const MDOperand &MDO, DxilSignatureElement &SE) { |
| IFTBOOL(MDO.get() != nullptr, DXC_E_INCORRECT_DXIL_METADATA); |
| const MDTuple *pTupleMD = dyn_cast<MDTuple>(MDO.get()); |
| IFTBOOL(pTupleMD != nullptr, DXC_E_INCORRECT_DXIL_METADATA); |
| IFTBOOL(pTupleMD->getNumOperands() == kDxilSignatureElementNumFields, DXC_E_INCORRECT_DXIL_METADATA); |
| |
| unsigned ID = ConstMDToUint32( pTupleMD->getOperand(kDxilSignatureElementID)); |
| MDString *pName = dyn_cast<MDString>( pTupleMD->getOperand(kDxilSignatureElementName)); |
| CompType CT = CompType(ConstMDToUint8( pTupleMD->getOperand(kDxilSignatureElementType))); |
| DXIL::SemanticKind SemKind = |
| (DXIL::SemanticKind)ConstMDToUint8( pTupleMD->getOperand(kDxilSignatureElementSystemValue)); |
| MDTuple *pSemanticIndexVectorMD = dyn_cast<MDTuple>(pTupleMD->getOperand(kDxilSignatureElementIndexVector)); |
| InterpolationMode IM(ConstMDToUint8( pTupleMD->getOperand(kDxilSignatureElementInterpMode))); |
| unsigned NumRows = ConstMDToUint32( pTupleMD->getOperand(kDxilSignatureElementRows)); |
| uint8_t NumCols = ConstMDToUint8( pTupleMD->getOperand(kDxilSignatureElementCols)); |
| int32_t StartRow = ConstMDToInt32( pTupleMD->getOperand(kDxilSignatureElementStartRow)); |
| int8_t StartCol = ConstMDToInt8( pTupleMD->getOperand(kDxilSignatureElementStartCol)); |
| |
| IFTBOOL(pName != nullptr, DXC_E_INCORRECT_DXIL_METADATA); |
| IFTBOOL(pSemanticIndexVectorMD != nullptr, DXC_E_INCORRECT_DXIL_METADATA); |
| |
| vector<unsigned> SemanticIndexVector; |
| ConstMDTupleToUint32Vector(pSemanticIndexVectorMD, SemanticIndexVector); |
| |
| SE.Initialize(pName->getString(), CT, IM, NumRows, NumCols, StartRow, StartCol, ID, SemanticIndexVector); |
| SE.SetKind(SemKind); |
| |
| // For case a system semantic don't have index, add 0 for it. |
| if (SemanticIndexVector.empty() && !SE.IsArbitrary()) { |
| SE.SetSemanticIndexVec({0}); |
| } |
| // Name-value list of extended properties. |
| m_ExtraPropertyHelper->m_bExtraMetadata = false; |
| m_ExtraPropertyHelper->LoadSignatureElementProperties(pTupleMD->getOperand(kDxilSignatureElementNameValueList), SE); |
| m_bExtraMetadata |= m_ExtraPropertyHelper->m_bExtraMetadata; |
| } |
| |
| // |
| // Resources. |
| // |
| MDTuple *DxilMDHelper::EmitDxilResourceTuple(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); |
| |
| return pTupleMD; |
| } |
| |
| void DxilMDHelper::EmitDxilResources(llvm::MDTuple *pDxilResourceTuple) { |
| NamedMDNode *pResourcesNamedMD = m_pModule->getNamedMetadata(kDxilResourcesMDName); |
| IFTBOOL(pResourcesNamedMD == nullptr, DXC_E_INCORRECT_DXIL_METADATA); |
| pResourcesNamedMD = m_pModule->getOrInsertNamedMetadata(kDxilResourcesMDName); |
| pResourcesNamedMD->addOperand(pDxilResourceTuple); |
| } |
| |
| void DxilMDHelper::UpdateDxilResources(llvm::MDTuple *pDxilResourceTuple) { |
| NamedMDNode *pResourcesNamedMD = |
| m_pModule->getNamedMetadata(kDxilResourcesMDName); |
| if (!pResourcesNamedMD) { |
| pResourcesNamedMD = |
| m_pModule->getOrInsertNamedMetadata(kDxilResourcesMDName); |
| } |
| if (pDxilResourceTuple) { |
| if (pResourcesNamedMD->getNumOperands() != 0) { |
| pResourcesNamedMD->setOperand(0, pDxilResourceTuple); |
| } |
| else { |
| pResourcesNamedMD->addOperand(pDxilResourceTuple); |
| } |
| |
| } else { |
| m_pModule->eraseNamedMetadata(pResourcesNamedMD); |
| } |
| } |
| |
| void DxilMDHelper::GetDxilResources(const MDOperand &MDO, const MDTuple *&pSRVs, |
| const MDTuple *&pUAVs, const MDTuple *&pCBuffers, |
| const MDTuple *&pSamplers) { |
| IFTBOOL(MDO.get() != nullptr, DXC_E_INCORRECT_DXIL_METADATA); |
| const MDTuple *pTupleMD = dyn_cast<MDTuple>(MDO.get()); |
| 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::EmitDxilResourceBase(const DxilResourceBase &R, Metadata *ppMDVals[]) { |
| ppMDVals[kDxilResourceBaseID ] = Uint32ToConstMD(R.GetID()); |
| ppMDVals[kDxilResourceBaseVariable ] = ValueAsMetadata::get(R.GetGlobalSymbol()); |
| ppMDVals[kDxilResourceBaseName ] = MDString::get(m_Ctx, R.GetGlobalName()); |
| ppMDVals[kDxilResourceBaseSpaceID ] = Uint32ToConstMD(R.GetSpaceID()); |
| ppMDVals[kDxilResourceBaseLowerBound] = Uint32ToConstMD(R.GetLowerBound()); |
| ppMDVals[kDxilResourceBaseRangeSize ] = Uint32ToConstMD(R.GetRangeSize()); |
| } |
| |
| void DxilMDHelper::LoadDxilResourceBase(const MDOperand &MDO, DxilResourceBase &R) { |
| IFTBOOL(MDO.get() != nullptr, DXC_E_INCORRECT_DXIL_METADATA); |
| const MDTuple *pTupleMD = dyn_cast<MDTuple>(MDO.get()); |
| IFTBOOL(pTupleMD != nullptr, DXC_E_INCORRECT_DXIL_METADATA); |
| IFTBOOL(pTupleMD->getNumOperands() >= kDxilResourceBaseNumFields, DXC_E_INCORRECT_DXIL_METADATA); |
| |
| R.SetID(ConstMDToUint32(pTupleMD->getOperand(kDxilResourceBaseID))); |
| R.SetGlobalSymbol(dyn_cast<Constant>(ValueMDToValue(pTupleMD->getOperand(kDxilResourceBaseVariable)))); |
| R.SetGlobalName(StringMDToString(pTupleMD->getOperand(kDxilResourceBaseName))); |
| R.SetSpaceID(ConstMDToUint32(pTupleMD->getOperand(kDxilResourceBaseSpaceID))); |
| R.SetLowerBound(ConstMDToUint32(pTupleMD->getOperand(kDxilResourceBaseLowerBound))); |
| R.SetRangeSize(ConstMDToUint32(pTupleMD->getOperand(kDxilResourceBaseRangeSize))); |
| } |
| |
| MDTuple *DxilMDHelper::EmitDxilSRV(const DxilResource &SRV) { |
| Metadata *MDVals[kDxilSRVNumFields]; |
| |
| EmitDxilResourceBase(SRV, &MDVals[0]); |
| |
| // SRV-specific fields. |
| MDVals[kDxilSRVShape ] = Uint32ToConstMD((unsigned)SRV.GetKind()); |
| MDVals[kDxilSRVSampleCount ] = Uint32ToConstMD(SRV.GetSampleCount()); |
| |
| // Name-value list of extended properties. |
| MDVals[kDxilSRVNameValueList] = nullptr; |
| vector<Metadata *> MDExtraVals; |
| m_ExtraPropertyHelper->EmitSRVProperties(SRV, MDExtraVals); |
| if (!MDExtraVals.empty()) { |
| MDVals[kDxilSRVNameValueList] = MDNode::get(m_Ctx, MDExtraVals); |
| } |
| |
| return MDNode::get(m_Ctx, MDVals); |
| } |
| |
| void DxilMDHelper::LoadDxilSRV(const MDOperand &MDO, DxilResource &SRV) { |
| IFTBOOL(MDO.get() != nullptr, DXC_E_INCORRECT_DXIL_METADATA); |
| const MDTuple *pTupleMD = dyn_cast<MDTuple>(MDO.get()); |
| IFTBOOL(pTupleMD != nullptr, DXC_E_INCORRECT_DXIL_METADATA); |
| IFTBOOL(pTupleMD->getNumOperands() == kDxilSRVNumFields, DXC_E_INCORRECT_DXIL_METADATA); |
| |
| SRV.SetRW(false); |
| |
| LoadDxilResourceBase(MDO, SRV); |
| |
| // SRV-specific fields. |
| SRV.SetKind((DxilResource::Kind)ConstMDToUint32(pTupleMD->getOperand(kDxilSRVShape))); |
| SRV.SetSampleCount(ConstMDToUint32(pTupleMD->getOperand(kDxilSRVSampleCount))); |
| |
| // Name-value list of extended properties. |
| m_ExtraPropertyHelper->m_bExtraMetadata = false; |
| m_ExtraPropertyHelper->LoadSRVProperties(pTupleMD->getOperand(kDxilSRVNameValueList), SRV); |
| m_bExtraMetadata |= m_ExtraPropertyHelper->m_bExtraMetadata; |
| } |
| |
| MDTuple *DxilMDHelper::EmitDxilUAV(const DxilResource &UAV) { |
| Metadata *MDVals[kDxilUAVNumFields]; |
| |
| EmitDxilResourceBase(UAV, &MDVals[0]); |
| |
| // UAV-specific fields. |
| MDVals[kDxilUAVShape ] = Uint32ToConstMD((unsigned)UAV.GetKind()); |
| MDVals[kDxilUAVGloballyCoherent ] = BoolToConstMD(UAV.IsGloballyCoherent()); |
| MDVals[kDxilUAVCounter ] = BoolToConstMD(UAV.HasCounter()); |
| MDVals[kDxilUAVRasterizerOrderedView] = BoolToConstMD(UAV.IsROV()); |
| |
| // Name-value list of extended properties. |
| MDVals[kDxilUAVNameValueList ] = nullptr; |
| vector<Metadata *> MDExtraVals; |
| m_ExtraPropertyHelper->EmitUAVProperties(UAV, MDExtraVals); |
| if (!MDExtraVals.empty()) { |
| MDVals[kDxilUAVNameValueList] = MDNode::get(m_Ctx, MDExtraVals); |
| } |
| |
| return MDNode::get(m_Ctx, MDVals); |
| } |
| |
| void DxilMDHelper::LoadDxilUAV(const MDOperand &MDO, DxilResource &UAV) { |
| IFTBOOL(MDO.get() != nullptr, DXC_E_INCORRECT_DXIL_METADATA); |
| const MDTuple *pTupleMD = dyn_cast<MDTuple>(MDO.get()); |
| IFTBOOL(pTupleMD != nullptr, DXC_E_INCORRECT_DXIL_METADATA); |
| IFTBOOL(pTupleMD->getNumOperands() == kDxilUAVNumFields, DXC_E_INCORRECT_DXIL_METADATA); |
| |
| UAV.SetRW(true); |
| |
| LoadDxilResourceBase(MDO, UAV); |
| |
| // UAV-specific fields. |
| UAV.SetKind((DxilResource::Kind)ConstMDToUint32(pTupleMD->getOperand(kDxilUAVShape))); |
| UAV.SetGloballyCoherent(ConstMDToBool(pTupleMD->getOperand(kDxilUAVGloballyCoherent))); |
| UAV.SetHasCounter(ConstMDToBool(pTupleMD->getOperand(kDxilUAVCounter))); |
| UAV.SetROV(ConstMDToBool(pTupleMD->getOperand(kDxilUAVRasterizerOrderedView))); |
| |
| // Name-value list of extended properties. |
| m_ExtraPropertyHelper->m_bExtraMetadata = false; |
| m_ExtraPropertyHelper->LoadUAVProperties(pTupleMD->getOperand(kDxilUAVNameValueList), UAV); |
| m_bExtraMetadata |= m_ExtraPropertyHelper->m_bExtraMetadata; |
| } |
| |
| MDTuple *DxilMDHelper::EmitDxilCBuffer(const DxilCBuffer &CB) { |
| Metadata *MDVals[kDxilCBufferNumFields]; |
| |
| EmitDxilResourceBase(CB, &MDVals[0]); |
| |
| // CBuffer-specific fields. |
| // CBuffer size in bytes. |
| MDVals[kDxilCBufferSizeInBytes ] = Uint32ToConstMD(CB.GetSize()); |
| |
| // Name-value list of extended properties. |
| MDVals[kDxilCBufferNameValueList] = nullptr; |
| vector<Metadata *> MDExtraVals; |
| m_ExtraPropertyHelper->EmitCBufferProperties(CB, MDExtraVals); |
| if (!MDExtraVals.empty()) { |
| MDVals[kDxilCBufferNameValueList] = MDNode::get(m_Ctx, MDExtraVals); |
| } |
| |
| return MDNode::get(m_Ctx, MDVals); |
| } |
| |
| void DxilMDHelper::LoadDxilCBuffer(const MDOperand &MDO, DxilCBuffer &CB) { |
| IFTBOOL(MDO.get() != nullptr, DXC_E_INCORRECT_DXIL_METADATA); |
| const MDTuple *pTupleMD = dyn_cast<MDTuple>(MDO.get()); |
| IFTBOOL(pTupleMD != nullptr, DXC_E_INCORRECT_DXIL_METADATA); |
| IFTBOOL(pTupleMD->getNumOperands() == kDxilCBufferNumFields, DXC_E_INCORRECT_DXIL_METADATA); |
| |
| LoadDxilResourceBase(MDO, CB); |
| |
| // CBuffer-specific fields. |
| CB.SetSize(ConstMDToUint32(pTupleMD->getOperand(kDxilCBufferSizeInBytes))); |
| |
| // Name-value list of extended properties. |
| m_ExtraPropertyHelper->m_bExtraMetadata = false; |
| m_ExtraPropertyHelper->LoadCBufferProperties(pTupleMD->getOperand(kDxilCBufferNameValueList), CB); |
| m_bExtraMetadata |= m_ExtraPropertyHelper->m_bExtraMetadata; |
| } |
| |
| void DxilMDHelper::EmitDxilTypeSystem(DxilTypeSystem &TypeSystem, vector<GlobalVariable*> &LLVMUsed) { |
| auto &TypeMap = TypeSystem.GetStructAnnotationMap(); |
| vector<Metadata *> MDVals; |
| MDVals.emplace_back(Uint32ToConstMD(kDxilTypeSystemStructTag)); // Tag |
| unsigned GVIdx = 0; |
| for (auto it = TypeMap.begin(); it != TypeMap.end(); ++it, GVIdx++) { |
| StructType *pStructType = const_cast<StructType *>(it->first); |
| DxilStructAnnotation *pA = it->second.get(); |
| // Don't emit type annotation for empty struct. |
| if (pA->IsEmptyStruct()) |
| continue; |
| // Emit struct type field annotations. |
| Metadata *pMD = EmitDxilStructAnnotation(*pA); |
| |
| MDVals.push_back(ValueAsMetadata::get(UndefValue::get(pStructType))); |
| MDVals.push_back(pMD); |
| } |
| |
| auto &FuncMap = TypeSystem.GetFunctionAnnotationMap(); |
| vector<Metadata *> MDFuncVals; |
| MDFuncVals.emplace_back(Uint32ToConstMD(kDxilTypeSystemFunctionTag)); // Tag |
| for (auto it = FuncMap.begin(); it != FuncMap.end(); ++it) { |
| DxilFunctionAnnotation *pA = it->second.get(); |
| MDFuncVals.push_back(ValueAsMetadata::get(const_cast<Function*>(pA->GetFunction()))); |
| // Emit function annotations. |
| |
| Metadata *pMD; |
| pMD = EmitDxilFunctionAnnotation(*pA); |
| MDFuncVals.push_back(pMD); |
| } |
| |
| NamedMDNode *pDxilTypeAnnotationsMD = m_pModule->getNamedMetadata(kDxilTypeSystemMDName); |
| if (pDxilTypeAnnotationsMD != nullptr) { |
| m_pModule->eraseNamedMetadata(pDxilTypeAnnotationsMD); |
| } |
| |
| if (MDVals.size() > 1) { |
| pDxilTypeAnnotationsMD = m_pModule->getOrInsertNamedMetadata(kDxilTypeSystemMDName); |
| |
| pDxilTypeAnnotationsMD->addOperand(MDNode::get(m_Ctx, MDVals)); |
| } |
| if (MDFuncVals.size() > 1) { |
| NamedMDNode *pDxilTypeAnnotationsMD = m_pModule->getNamedMetadata(kDxilTypeSystemMDName); |
| if (pDxilTypeAnnotationsMD == nullptr) |
| pDxilTypeAnnotationsMD = m_pModule->getOrInsertNamedMetadata(kDxilTypeSystemMDName); |
| |
| pDxilTypeAnnotationsMD->addOperand(MDNode::get(m_Ctx, MDFuncVals)); |
| } |
| } |
| |
| void DxilMDHelper::LoadDxilTypeSystemNode(const llvm::MDTuple &MDT, |
| DxilTypeSystem &TypeSystem) { |
| |
| unsigned Tag = ConstMDToUint32(MDT.getOperand(0)); |
| if (Tag == kDxilTypeSystemStructTag) { |
| IFTBOOL((MDT.getNumOperands() & 0x1) == 1, DXC_E_INCORRECT_DXIL_METADATA); |
| |
| for (unsigned i = 1; i < MDT.getNumOperands(); i += 2) { |
| Constant *pGV = |
| dyn_cast<Constant>(ValueMDToValue(MDT.getOperand(i))); |
| IFTBOOL(pGV != nullptr, DXC_E_INCORRECT_DXIL_METADATA); |
| StructType *pGVType = |
| dyn_cast<StructType>(pGV->getType()); |
| IFTBOOL(pGVType != nullptr, DXC_E_INCORRECT_DXIL_METADATA); |
| |
| DxilStructAnnotation *pSA = TypeSystem.AddStructAnnotation(pGVType); |
| LoadDxilStructAnnotation(MDT.getOperand(i + 1), *pSA); |
| } |
| } else { |
| IFTBOOL((MDT.getNumOperands() & 0x1) == 1, DXC_E_INCORRECT_DXIL_METADATA); |
| for (unsigned i = 1; i < MDT.getNumOperands(); i += 2) { |
| Function *F = dyn_cast<Function>(ValueMDToValue(MDT.getOperand(i))); |
| DxilFunctionAnnotation *pFA = TypeSystem.AddFunctionAnnotation(F); |
| LoadDxilFunctionAnnotation(MDT.getOperand(i + 1), *pFA); |
| } |
| } |
| } |
| |
| void DxilMDHelper::LoadDxilTypeSystem(DxilTypeSystem &TypeSystem) { |
| NamedMDNode *pDxilTypeAnnotationsMD = m_pModule->getNamedMetadata(kDxilTypeSystemMDName); |
| if (pDxilTypeAnnotationsMD == nullptr) |
| return; |
| |
| IFTBOOL(pDxilTypeAnnotationsMD->getNumOperands() <= 2, DXC_E_INCORRECT_DXIL_METADATA); |
| for (unsigned i = 0; i < pDxilTypeAnnotationsMD->getNumOperands(); i++) { |
| const MDTuple *pTupleMD = dyn_cast<MDTuple>(pDxilTypeAnnotationsMD->getOperand(i)); |
| IFTBOOL(pTupleMD != nullptr, DXC_E_INCORRECT_DXIL_METADATA); |
| LoadDxilTypeSystemNode(*pTupleMD, TypeSystem); |
| } |
| } |
| |
| Metadata *DxilMDHelper::EmitDxilTemplateArgAnnotation(const DxilTemplateArgAnnotation &annotation) { |
| SmallVector<Metadata *, 2> MDVals; |
| if (annotation.IsType()) { |
| MDVals.emplace_back(Uint32ToConstMD(DxilMDHelper::kDxilTemplateArgTypeTag)); |
| MDVals.emplace_back(ValueAsMetadata::get(UndefValue::get(const_cast<Type*>(annotation.GetType())))); |
| } else if (annotation.IsIntegral()) { |
| MDVals.emplace_back(Uint32ToConstMD(DxilMDHelper::kDxilTemplateArgIntegralTag)); |
| MDVals.emplace_back(Uint64ToConstMD((uint64_t)annotation.GetIntegral())); |
| } |
| return MDNode::get(m_Ctx, MDVals); |
| } |
| void DxilMDHelper::LoadDxilTemplateArgAnnotation(const llvm::MDOperand &MDO, DxilTemplateArgAnnotation &annotation) { |
| IFTBOOL(MDO.get() != nullptr, DXC_E_INCORRECT_DXIL_METADATA); |
| const MDTuple *pTupleMD = dyn_cast<MDTuple>(MDO.get()); |
| IFTBOOL(pTupleMD != nullptr, DXC_E_INCORRECT_DXIL_METADATA); |
| IFTBOOL(pTupleMD->getNumOperands() >= 1, DXC_E_INCORRECT_DXIL_METADATA); |
| unsigned Tag = ConstMDToUint32(pTupleMD->getOperand(0)); |
| switch (Tag) { |
| case kDxilTemplateArgTypeTag: { |
| IFTBOOL(pTupleMD->getNumOperands() == 2, DXC_E_INCORRECT_DXIL_METADATA); |
| Constant *C = dyn_cast<Constant>(ValueMDToValue(pTupleMD->getOperand(kDxilTemplateArgValue))); |
| IFTBOOL(C != nullptr, DXC_E_INCORRECT_DXIL_METADATA); |
| annotation.SetType(C->getType()); |
| } break; |
| case kDxilTemplateArgIntegralTag: |
| IFTBOOL(pTupleMD->getNumOperands() == 2, DXC_E_INCORRECT_DXIL_METADATA); |
| annotation.SetIntegral((int64_t)ConstMDToUint64(pTupleMD->getOperand(kDxilTemplateArgValue))); |
| break; |
| default: |
| DXASSERT(false, "Unknown template argument type tag."); |
| m_bExtraMetadata = true; |
| break; |
| } |
| } |
| |
| Metadata *DxilMDHelper::EmitDxilStructAnnotation(const DxilStructAnnotation &SA) { |
| bool bSupportExtended = DXIL::CompareVersions(m_MinValMajor, m_MinValMinor, 1, 5) >= 0; |
| |
| vector<Metadata *> MDVals; |
| MDVals.reserve(SA.GetNumFields() + 2); // In case of extended 1.5 property list |
| MDVals.resize(SA.GetNumFields() + 1); |
| |
| MDVals[0] = Uint32ToConstMD(SA.GetCBufferSize()); |
| for (unsigned i = 0; i < SA.GetNumFields(); i++) { |
| MDVals[i+1] = EmitDxilFieldAnnotation(SA.GetFieldAnnotation(i)); |
| } |
| |
| // Only add template args if shader target requires validator version that supports them. |
| if (bSupportExtended && SA.GetNumTemplateArgs()) { |
| vector<Metadata *> MDTemplateArgs(SA.GetNumTemplateArgs()); |
| for (unsigned i = 0; i < SA.GetNumTemplateArgs(); ++i) { |
| MDTemplateArgs[i] = EmitDxilTemplateArgAnnotation(SA.GetTemplateArgAnnotation(i)); |
| } |
| SmallVector<Metadata *, 2> MDExtraVals; |
| MDExtraVals.emplace_back(Uint32ToConstMD(DxilMDHelper::kDxilTemplateArgumentsTag)); |
| MDExtraVals.emplace_back(MDNode::get(m_Ctx, MDTemplateArgs)); |
| MDVals.emplace_back(MDNode::get(m_Ctx, MDExtraVals)); |
| } |
| |
| return MDNode::get(m_Ctx, MDVals); |
| } |
| |
| void DxilMDHelper::LoadDxilStructAnnotation(const MDOperand &MDO, DxilStructAnnotation &SA) { |
| IFTBOOL(MDO.get() != nullptr, DXC_E_INCORRECT_DXIL_METADATA); |
| const MDTuple *pTupleMD = dyn_cast<MDTuple>(MDO.get()); |
| IFTBOOL(pTupleMD != nullptr, DXC_E_INCORRECT_DXIL_METADATA); |
| if (pTupleMD->getNumOperands() == 1) { |
| SA.MarkEmptyStruct(); |
| } |
| if (pTupleMD->getNumOperands() == SA.GetNumFields()+2) { |
| DXASSERT(DXIL::CompareVersions(m_MinValMajor, m_MinValMinor, 1, 5) >= 0, |
| "otherwise, template annotation emitted for dxil version < 1.5"); |
| // Load template args from extended operand |
| const MDOperand &MDOExtra = pTupleMD->getOperand(SA.GetNumFields()+1); |
| const MDTuple *pTupleMDExtra = dyn_cast_or_null<MDTuple>(MDOExtra.get()); |
| if(pTupleMDExtra) { |
| for (unsigned i = 0; i < pTupleMDExtra->getNumOperands(); i += 2) { |
| unsigned Tag = ConstMDToUint32(pTupleMDExtra->getOperand(i)); |
| const MDOperand &MDO = pTupleMDExtra->getOperand(i + 1); |
| IFTBOOL(MDO.get() != nullptr, DXC_E_INCORRECT_DXIL_METADATA); |
| |
| switch (Tag) { |
| case kDxilTemplateArgumentsTag: { |
| const MDTuple *pTupleTemplateArgs = dyn_cast_or_null<MDTuple>(pTupleMDExtra->getOperand(1).get()); |
| IFTBOOL(pTupleTemplateArgs, DXC_E_INCORRECT_DXIL_METADATA); |
| SA.SetNumTemplateArgs(pTupleTemplateArgs->getNumOperands()); |
| for (unsigned i = 0; i < pTupleTemplateArgs->getNumOperands(); ++i) { |
| LoadDxilTemplateArgAnnotation(pTupleTemplateArgs->getOperand(i), SA.GetTemplateArgAnnotation(i)); |
| } |
| } break; |
| default: |
| DXASSERT(false, "unknown extended tag for struct annotation."); |
| m_bExtraMetadata = true; |
| break; |
| } |
| } |
| } |
| } else { |
| IFTBOOL(pTupleMD->getNumOperands() == SA.GetNumFields()+1, DXC_E_INCORRECT_DXIL_METADATA); |
| } |
| |
| SA.SetCBufferSize(ConstMDToUint32(pTupleMD->getOperand(0))); |
| for (unsigned i = 0; i < SA.GetNumFields(); i++) { |
| const MDOperand &MDO = pTupleMD->getOperand(i+1); |
| DxilFieldAnnotation &FA = SA.GetFieldAnnotation(i); |
| LoadDxilFieldAnnotation(MDO, FA); |
| } |
| } |
| |
| Metadata * |
| DxilMDHelper::EmitDxilFunctionAnnotation(const DxilFunctionAnnotation &FA) { |
| return EmitDxilParamAnnotations(FA); |
| } |
| |
| void DxilMDHelper::LoadDxilFunctionAnnotation(const MDOperand &MDO, |
| DxilFunctionAnnotation &FA) { |
| LoadDxilParamAnnotations(MDO, FA); |
| } |
| |
| llvm::Metadata * |
| DxilMDHelper::EmitDxilParamAnnotations(const DxilFunctionAnnotation &FA) { |
| vector<Metadata *> MDParamAnnotations(FA.GetNumParameters() + 1); |
| MDParamAnnotations[0] = EmitDxilParamAnnotation(FA.GetRetTypeAnnotation()); |
| for (unsigned i = 0; i < FA.GetNumParameters(); i++) { |
| MDParamAnnotations[i + 1] = |
| EmitDxilParamAnnotation(FA.GetParameterAnnotation(i)); |
| } |
| return MDNode::get(m_Ctx, MDParamAnnotations); |
| } |
| |
| void DxilMDHelper::LoadDxilParamAnnotations(const llvm::MDOperand &MDO, |
| DxilFunctionAnnotation &FA) { |
| IFTBOOL(MDO.get() != nullptr, DXC_E_INCORRECT_DXIL_METADATA); |
| const MDTuple *pTupleMD = dyn_cast<MDTuple>(MDO.get()); |
| IFTBOOL(pTupleMD->getNumOperands() == FA.GetNumParameters() + 1, |
| DXC_E_INCORRECT_DXIL_METADATA); |
| DxilParameterAnnotation &retTyAnnotation = FA.GetRetTypeAnnotation(); |
| LoadDxilParamAnnotation(pTupleMD->getOperand(0), retTyAnnotation); |
| for (unsigned i = 0; i < FA.GetNumParameters(); i++) { |
| const MDOperand &MDO = pTupleMD->getOperand(i + 1); |
| DxilParameterAnnotation &PA = FA.GetParameterAnnotation(i); |
| LoadDxilParamAnnotation(MDO, PA); |
| } |
| } |
| |
| Metadata * |
| DxilMDHelper::EmitDxilParamAnnotation(const DxilParameterAnnotation &PA) { |
| vector<Metadata *> MDVals(3); |
| MDVals[0] = Uint32ToConstMD(static_cast<unsigned>(PA.GetParamInputQual())); |
| MDVals[1] = EmitDxilFieldAnnotation(PA); |
| MDVals[2] = Uint32VectorToConstMDTuple(PA.GetSemanticIndexVec()); |
| |
| return MDNode::get(m_Ctx, MDVals); |
| } |
| void DxilMDHelper::LoadDxilParamAnnotation(const MDOperand &MDO, |
| DxilParameterAnnotation &PA) { |
| IFTBOOL(MDO.get() != nullptr, DXC_E_INCORRECT_DXIL_METADATA); |
| const MDTuple *pTupleMD = dyn_cast<MDTuple>(MDO.get()); |
| IFTBOOL(pTupleMD != nullptr, DXC_E_INCORRECT_DXIL_METADATA); |
| IFTBOOL(pTupleMD->getNumOperands() == 3, DXC_E_INCORRECT_DXIL_METADATA); |
| PA.SetParamInputQual(static_cast<DxilParamInputQual>( |
| ConstMDToUint32(pTupleMD->getOperand(0)))); |
| LoadDxilFieldAnnotation(pTupleMD->getOperand(1), PA); |
| MDTuple *pSemanticIndexVectorMD = dyn_cast<MDTuple>(pTupleMD->getOperand(2)); |
| vector<unsigned> SemanticIndexVector; |
| ConstMDTupleToUint32Vector(pSemanticIndexVectorMD, SemanticIndexVector); |
| PA.SetSemanticIndexVec(SemanticIndexVector); |
| } |
| |
| Metadata *DxilMDHelper::EmitDxilFieldAnnotation(const DxilFieldAnnotation &FA) { |
| vector<Metadata *> MDVals; // Tag-Value list. |
| |
| if (FA.HasFieldName()) { |
| MDVals.emplace_back(Uint32ToConstMD(kDxilFieldAnnotationFieldNameTag)); |
| MDVals.emplace_back(MDString::get(m_Ctx, FA.GetFieldName())); |
| } |
| if (FA.IsPrecise()) { |
| MDVals.emplace_back(Uint32ToConstMD(kDxilFieldAnnotationPreciseTag)); // Tag |
| MDVals.emplace_back(BoolToConstMD(true)); // Value |
| } |
| if (FA.HasMatrixAnnotation()) { |
| const DxilMatrixAnnotation &MA = FA.GetMatrixAnnotation(); |
| Metadata *MatrixMD[3]; |
| MatrixMD[0] = Uint32ToConstMD(MA.Rows); |
| MatrixMD[1] = Uint32ToConstMD(MA.Cols); |
| MatrixMD[2] = Uint32ToConstMD((unsigned)MA.Orientation); |
| |
| MDVals.emplace_back(Uint32ToConstMD(kDxilFieldAnnotationMatrixTag)); |
| MDVals.emplace_back(MDNode::get(m_Ctx, MatrixMD)); |
| } |
| if (FA.HasCBufferOffset()) { |
| MDVals.emplace_back(Uint32ToConstMD(kDxilFieldAnnotationCBufferOffsetTag)); |
| MDVals.emplace_back(Uint32ToConstMD(FA.GetCBufferOffset())); |
| } |
| if (FA.HasSemanticString()) { |
| MDVals.emplace_back(Uint32ToConstMD(kDxilFieldAnnotationSemanticStringTag)); |
| MDVals.emplace_back(MDString::get(m_Ctx, FA.GetSemanticString())); |
| } |
| if (FA.HasInterpolationMode()) { |
| MDVals.emplace_back(Uint32ToConstMD(kDxilFieldAnnotationInterpolationModeTag)); |
| MDVals.emplace_back(Uint32ToConstMD((unsigned)FA.GetInterpolationMode().GetKind())); |
| } |
| if (FA.HasCompType()) { |
| MDVals.emplace_back(Uint32ToConstMD(kDxilFieldAnnotationCompTypeTag)); |
| MDVals.emplace_back(Uint32ToConstMD((unsigned)FA.GetCompType().GetKind())); |
| } |
| if (FA.IsCBVarUsed() && |
| DXIL::CompareVersions(m_MinValMajor, m_MinValMinor, 1, 5) >= 0) { |
| MDVals.emplace_back(Uint32ToConstMD(kDxilFieldAnnotationCBUsedTag)); |
| MDVals.emplace_back(BoolToConstMD(true)); |
| } |
| |
| return MDNode::get(m_Ctx, MDVals); |
| } |
| |
| void DxilMDHelper::LoadDxilFieldAnnotation(const MDOperand &MDO, DxilFieldAnnotation &FA) { |
| IFTBOOL(MDO.get() != nullptr, DXC_E_INCORRECT_DXIL_METADATA); |
| const MDTuple *pTupleMD = dyn_cast<MDTuple>(MDO.get()); |
| IFTBOOL(pTupleMD != nullptr, DXC_E_INCORRECT_DXIL_METADATA); |
| IFTBOOL((pTupleMD->getNumOperands() & 0x1) == 0, DXC_E_INCORRECT_DXIL_METADATA); |
| |
| for (unsigned i = 0; i < pTupleMD->getNumOperands(); i += 2) { |
| unsigned Tag = ConstMDToUint32(pTupleMD->getOperand(i)); |
| const MDOperand &MDO = pTupleMD->getOperand(i + 1); |
| IFTBOOL(MDO.get() != nullptr, DXC_E_INCORRECT_DXIL_METADATA); |
| |
| switch (Tag) { |
| case kDxilFieldAnnotationPreciseTag: |
| FA.SetPrecise(ConstMDToBool(MDO)); |
| break; |
| case kDxilFieldAnnotationMatrixTag: { |
| DxilMatrixAnnotation MA; |
| const MDTuple *pMATupleMD = dyn_cast<MDTuple>(MDO.get()); |
| IFTBOOL(pMATupleMD != nullptr, DXC_E_INCORRECT_DXIL_METADATA); |
| IFTBOOL(pMATupleMD->getNumOperands() == 3, DXC_E_INCORRECT_DXIL_METADATA); |
| MA.Rows = ConstMDToUint32(pMATupleMD->getOperand(0)); |
| MA.Cols = ConstMDToUint32(pMATupleMD->getOperand(1)); |
| MA.Orientation = (MatrixOrientation)ConstMDToUint32(pMATupleMD->getOperand(2)); |
| FA.SetMatrixAnnotation(MA); |
| } break; |
| case kDxilFieldAnnotationCBufferOffsetTag: |
| FA.SetCBufferOffset(ConstMDToUint32(MDO)); |
| break; |
| case kDxilFieldAnnotationSemanticStringTag: |
| FA.SetSemanticString(StringMDToString(MDO)); |
| break; |
| case kDxilFieldAnnotationInterpolationModeTag: |
| FA.SetInterpolationMode(InterpolationMode((InterpolationMode::Kind)ConstMDToUint32(MDO))); |
| break; |
| case kDxilFieldAnnotationFieldNameTag: |
| FA.SetFieldName(StringMDToString(MDO)); |
| break; |
| case kDxilFieldAnnotationCompTypeTag: |
| FA.SetCompType((CompType::Kind)ConstMDToUint32(MDO)); |
| break; |
| case kDxilFieldAnnotationCBUsedTag: |
| FA.SetCBVarUsed(ConstMDToBool(MDO)); |
| break; |
| default: |
| DXASSERT(false, "Unknown extended shader properties tag"); |
| m_bExtraMetadata = true; |
| break; |
| } |
| } |
| } |
| |
| const Function *DxilMDHelper::LoadDxilFunctionProps(const MDTuple *pProps, |
| hlsl::DxilFunctionProps *props) { |
| unsigned idx = 0; |
| const Function *F = dyn_cast<Function>( |
| dyn_cast<ValueAsMetadata>(pProps->getOperand(idx++))->getValue()); |
| DXIL::ShaderKind shaderKind = |
| static_cast<DXIL::ShaderKind>(ConstMDToUint32(pProps->getOperand(idx++))); |
| |
| bool bRayAttributes = false; |
| props->shaderKind = shaderKind; |
| switch (shaderKind) { |
| case DXIL::ShaderKind::Compute: |
| props->ShaderProps.CS.numThreads[0] = |
| ConstMDToUint32(pProps->getOperand(idx++)); |
| props->ShaderProps.CS.numThreads[1] = |
| ConstMDToUint32(pProps->getOperand(idx++)); |
| props->ShaderProps.CS.numThreads[2] = |
| ConstMDToUint32(pProps->getOperand(idx++)); |
| break; |
| case DXIL::ShaderKind::Geometry: |
| props->ShaderProps.GS.inputPrimitive = |
| (DXIL::InputPrimitive)ConstMDToUint32(pProps->getOperand(idx++)); |
| props->ShaderProps.GS.maxVertexCount = |
| ConstMDToUint32(pProps->getOperand(idx++)); |
| props->ShaderProps.GS.instanceCount = |
| ConstMDToUint32(pProps->getOperand(idx++)); |
| for (size_t i = 0; |
| i < _countof(props->ShaderProps.GS.streamPrimitiveTopologies); ++i) |
| props->ShaderProps.GS.streamPrimitiveTopologies[i] = |
| (DXIL::PrimitiveTopology)ConstMDToUint32(pProps->getOperand(idx++)); |
| break; |
| case DXIL::ShaderKind::Hull: |
| props->ShaderProps.HS.patchConstantFunc = dyn_cast<Function>( |
| dyn_cast<ValueAsMetadata>(pProps->getOperand(idx++))->getValue()); |
| props->ShaderProps.HS.domain = |
| (DXIL::TessellatorDomain)ConstMDToUint32(pProps->getOperand(idx++)); |
| props->ShaderProps.HS.partition = |
| (DXIL::TessellatorPartitioning)ConstMDToUint32( |
| pProps->getOperand(idx++)); |
| props->ShaderProps.HS.outputPrimitive = |
| (DXIL::TessellatorOutputPrimitive)ConstMDToUint32( |
| pProps->getOperand(idx++)); |
| props->ShaderProps.HS.inputControlPoints = |
| ConstMDToUint32(pProps->getOperand(idx++)); |
| props->ShaderProps.HS.outputControlPoints = |
| ConstMDToUint32(pProps->getOperand(idx++)); |
| props->ShaderProps.HS.maxTessFactor = |
| ConstMDToFloat(pProps->getOperand(idx++)); |
| break; |
| case DXIL::ShaderKind::Domain: |
| props->ShaderProps.DS.domain = |
| (DXIL::TessellatorDomain)ConstMDToUint32(pProps->getOperand(idx++)); |
| props->ShaderProps.DS.inputControlPoints = |
| ConstMDToUint32(pProps->getOperand(idx++)); |
| break; |
| case DXIL::ShaderKind::Pixel: |
| props->ShaderProps.PS.EarlyDepthStencil = |
| ConstMDToUint32(pProps->getOperand(idx++)); |
| break; |
| case DXIL::ShaderKind::AnyHit: |
| case DXIL::ShaderKind::ClosestHit: |
| bRayAttributes = true; |
| case DXIL::ShaderKind::Miss: |
| case DXIL::ShaderKind::Callable: |
| // payload/params unioned and first: |
| props->ShaderProps.Ray.payloadSizeInBytes = |
| ConstMDToUint32(pProps->getOperand(idx++)); |
| if (bRayAttributes) |
| props->ShaderProps.Ray.attributeSizeInBytes = |
| ConstMDToUint32(pProps->getOperand(idx++)); |
| break; |
| case DXIL::ShaderKind::Mesh: |
| props->ShaderProps.MS.numThreads[0] = |
| ConstMDToUint32(pProps->getOperand(idx++)); |
| props->ShaderProps.MS.numThreads[1] = |
| ConstMDToUint32(pProps->getOperand(idx++)); |
| props->ShaderProps.MS.numThreads[2] = |
| ConstMDToUint32(pProps->getOperand(idx++)); |
| props->ShaderProps.MS.maxVertexCount = |
| ConstMDToUint32(pProps->getOperand(idx++)); |
| props->ShaderProps.MS.maxPrimitiveCount = |
| ConstMDToUint32(pProps->getOperand(idx++)); |
| props->ShaderProps.MS.outputTopology = |
| (DXIL::MeshOutputTopology)ConstMDToUint32(pProps->getOperand(idx++)); |
| props->ShaderProps.MS.payloadSizeInBytes = |
| ConstMDToUint32(pProps->getOperand(idx++)); |
| break; |
| case DXIL::ShaderKind::Amplification: |
| props->ShaderProps.AS.numThreads[0] = |
| ConstMDToUint32(pProps->getOperand(idx++)); |
| props->ShaderProps.AS.numThreads[1] = |
| ConstMDToUint32(pProps->getOperand(idx++)); |
| props->ShaderProps.AS.numThreads[2] = |
| ConstMDToUint32(pProps->getOperand(idx++)); |
| props->ShaderProps.AS.payloadSizeInBytes = |
| ConstMDToUint32(pProps->getOperand(idx++)); |
| break; |
| default: |
| break; |
| } |
| return F; |
| } |
| |
| MDTuple *DxilMDHelper::EmitDxilEntryProperties(uint64_t rawShaderFlag, |
| const DxilFunctionProps &props, |
| unsigned autoBindingSpace) { |
| vector<Metadata *> MDVals; |
| |
| // DXIL shader flags. |
| if (props.IsPS()) { |
| if (props.ShaderProps.PS.EarlyDepthStencil) { |
| ShaderFlags flags; |
| flags.SetShaderFlagsRaw(rawShaderFlag); |
| flags.SetForceEarlyDepthStencil(true); |
| rawShaderFlag = flags.GetShaderFlagsRaw(); |
| } |
| } |
| if (rawShaderFlag != 0) { |
| MDVals.emplace_back(Uint32ToConstMD(kDxilShaderFlagsTag)); |
| MDVals.emplace_back(Uint64ToConstMD(rawShaderFlag)); |
| } |
| |
| // Add shader kind for lib entrys. |
| if (m_pSM->IsLib() && props.shaderKind != DXIL::ShaderKind::Library) { |
| MDVals.emplace_back(Uint32ToConstMD(kDxilShaderKindTag)); |
| MDVals.emplace_back( |
| Uint32ToConstMD(static_cast<unsigned>(props.shaderKind))); |
| } |
| |
| switch (props.shaderKind) { |
| // Compute shader. |
| case DXIL::ShaderKind::Compute: { |
| auto &CS = props.ShaderProps.CS; |
| MDVals.emplace_back(Uint32ToConstMD(DxilMDHelper::kDxilNumThreadsTag)); |
| vector<Metadata *> NumThreadVals; |
| NumThreadVals.emplace_back(Uint32ToConstMD(CS.numThreads[0])); |
| NumThreadVals.emplace_back(Uint32ToConstMD(CS.numThreads[1])); |
| NumThreadVals.emplace_back(Uint32ToConstMD(CS.numThreads[2])); |
| MDVals.emplace_back(MDNode::get(m_Ctx, NumThreadVals)); |
| } break; |
| // Geometry shader. |
| case DXIL::ShaderKind::Geometry: { |
| MDVals.emplace_back(Uint32ToConstMD(DxilMDHelper::kDxilGSStateTag)); |
| DXIL::PrimitiveTopology topo = DXIL::PrimitiveTopology::Undefined; |
| unsigned activeStreamMask = 0; |
| for (size_t i = 0; |
| i < _countof(props.ShaderProps.GS.streamPrimitiveTopologies); ++i) { |
| if (props.ShaderProps.GS.streamPrimitiveTopologies[i] != |
| DXIL::PrimitiveTopology::Undefined) { |
| activeStreamMask |= 1 << i; |
| DXASSERT_NOMSG(topo == DXIL::PrimitiveTopology::Undefined || |
| topo == |
| props.ShaderProps.GS.streamPrimitiveTopologies[i]); |
| topo = props.ShaderProps.GS.streamPrimitiveTopologies[i]; |
| } |
| } |
| MDTuple *pMDTuple = |
| EmitDxilGSState(props.ShaderProps.GS.inputPrimitive, |
| props.ShaderProps.GS.maxVertexCount, activeStreamMask, |
| topo, props.ShaderProps.GS.instanceCount); |
| MDVals.emplace_back(pMDTuple); |
| } break; |
| // Domain shader. |
| case DXIL::ShaderKind::Domain: { |
| auto &DS = props.ShaderProps.DS; |
| MDVals.emplace_back(Uint32ToConstMD(DxilMDHelper::kDxilDSStateTag)); |
| MDTuple *pMDTuple = EmitDxilDSState(DS.domain, DS.inputControlPoints); |
| MDVals.emplace_back(pMDTuple); |
| } break; |
| // Hull shader. |
| case DXIL::ShaderKind::Hull: { |
| auto &HS = props.ShaderProps.HS; |
| MDVals.emplace_back(Uint32ToConstMD(DxilMDHelper::kDxilHSStateTag)); |
| MDTuple *pMDTuple = EmitDxilHSState( |
| HS.patchConstantFunc, HS.inputControlPoints, HS.outputControlPoints, |
| HS.domain, HS.partition, HS.outputPrimitive, HS.maxTessFactor); |
| MDVals.emplace_back(pMDTuple); |
| } break; |
| // Raytracing. |
| case DXIL::ShaderKind::AnyHit: |
| case DXIL::ShaderKind::ClosestHit: { |
| MDVals.emplace_back(Uint32ToConstMD(kDxilRayPayloadSizeTag)); |
| MDVals.emplace_back( |
| Uint32ToConstMD(props.ShaderProps.Ray.payloadSizeInBytes)); |
| |
| MDVals.emplace_back(Uint32ToConstMD(kDxilRayAttribSizeTag)); |
| MDVals.emplace_back( |
| Uint32ToConstMD(props.ShaderProps.Ray.attributeSizeInBytes)); |
| } break; |
| case DXIL::ShaderKind::Miss: |
| case DXIL::ShaderKind::Callable: { |
| MDVals.emplace_back(Uint32ToConstMD(kDxilRayPayloadSizeTag)); |
| |
| MDVals.emplace_back( |
| Uint32ToConstMD(props.ShaderProps.Ray.payloadSizeInBytes)); |
| } break; |
| case DXIL::ShaderKind::Mesh: { |
| auto &MS = props.ShaderProps.MS; |
| MDVals.emplace_back(Uint32ToConstMD(DxilMDHelper::kDxilMSStateTag)); |
| MDTuple *pMDTuple = EmitDxilMSState(MS.numThreads, |
| MS.maxVertexCount, |
| MS.maxPrimitiveCount, |
| MS.outputTopology, |
| MS.payloadSizeInBytes); |
| MDVals.emplace_back(pMDTuple); |
| } break; |
| case DXIL::ShaderKind::Amplification: { |
| auto &AS = props.ShaderProps.AS; |
| MDVals.emplace_back(Uint32ToConstMD(DxilMDHelper::kDxilASStateTag)); |
| MDTuple *pMDTuple = EmitDxilASState(AS.numThreads, AS.payloadSizeInBytes); |
| MDVals.emplace_back(pMDTuple); |
| } break; |
| default: |
| break; |
| } |
| |
| if (autoBindingSpace != UINT_MAX && m_pSM->IsSMAtLeast(6, 3)) { |
| MDVals.emplace_back(Uint32ToConstMD(kDxilAutoBindingSpaceTag)); |
| MDVals.emplace_back( |
| MDNode::get(m_Ctx, {Uint32ToConstMD(autoBindingSpace)})); |
| } |
| |
| if (!MDVals.empty()) |
| return MDNode::get(m_Ctx, MDVals); |
| else |
| return nullptr; |
| } |
| |
| void DxilMDHelper::LoadDxilEntryProperties(const MDOperand &MDO, |
| uint64_t &rawShaderFlag, |
| DxilFunctionProps &props, |
| uint32_t &autoBindingSpace) { |
| if (MDO.get() == nullptr) |
| return; |
| |
| const MDTuple *pTupleMD = dyn_cast<MDTuple>(MDO.get()); |
| IFTBOOL(pTupleMD != nullptr, DXC_E_INCORRECT_DXIL_METADATA); |
| IFTBOOL((pTupleMD->getNumOperands() & 0x1) == 0, |
| DXC_E_INCORRECT_DXIL_METADATA); |
| bool bEarlyDepth = false; |
| |
| if (!m_pSM->IsLib()) { |
| props.shaderKind = m_pSM->GetKind(); |
| } else { |
| props.shaderKind = DXIL::ShaderKind::Library; |
| } |
| |
| for (unsigned iNode = 0; iNode < pTupleMD->getNumOperands(); iNode += 2) { |
| unsigned Tag = DxilMDHelper::ConstMDToUint32(pTupleMD->getOperand(iNode)); |
| const MDOperand &MDO = pTupleMD->getOperand(iNode + 1); |
| IFTBOOL(MDO.get() != nullptr, DXC_E_INCORRECT_DXIL_METADATA); |
| |
| switch (Tag) { |
| case DxilMDHelper::kDxilShaderFlagsTag: { |
| rawShaderFlag = ConstMDToUint64(MDO); |
| ShaderFlags flags; |
| flags.SetShaderFlagsRaw(rawShaderFlag); |
| bEarlyDepth = flags.GetForceEarlyDepthStencil(); |
| } break; |
| |
| case DxilMDHelper::kDxilNumThreadsTag: { |
| DXASSERT(props.IsCS(), "else invalid shader kind"); |
| auto &CS = props.ShaderProps.CS; |
| MDNode *pNode = cast<MDNode>(MDO.get()); |
| CS.numThreads[0] = ConstMDToUint32(pNode->getOperand(0)); |
| CS.numThreads[1] = ConstMDToUint32(pNode->getOperand(1)); |
| CS.numThreads[2] = ConstMDToUint32(pNode->getOperand(2)); |
| } break; |
| |
| case DxilMDHelper::kDxilGSStateTag: { |
| DXASSERT(props.IsGS(), "else invalid shader kind"); |
| auto &GS = props.ShaderProps.GS; |
| DXIL::PrimitiveTopology topo = DXIL::PrimitiveTopology::Undefined; |
| unsigned activeStreamMask; |
| LoadDxilGSState(MDO, GS.inputPrimitive, GS.maxVertexCount, |
| activeStreamMask, topo, GS.instanceCount); |
| if (topo != DXIL::PrimitiveTopology::Undefined) { |
| for (size_t i = 0; i < _countof(GS.streamPrimitiveTopologies); ++i) { |
| unsigned mask = 1 << i; |
| if (activeStreamMask & mask) { |
| GS.streamPrimitiveTopologies[i] = topo; |
| } else { |
| GS.streamPrimitiveTopologies[i] = |
| DXIL::PrimitiveTopology::Undefined; |
| } |
| } |
| } |
| } break; |
| |
| case DxilMDHelper::kDxilDSStateTag: { |
| DXASSERT(props.IsDS(), "else invalid shader kind"); |
| auto &DS = props.ShaderProps.DS; |
| LoadDxilDSState(MDO, DS.domain, DS.inputControlPoints); |
| } break; |
| |
| case DxilMDHelper::kDxilHSStateTag: { |
| DXASSERT(props.IsHS(), "else invalid shader kind"); |
| auto &HS = props.ShaderProps.HS; |
| LoadDxilHSState(MDO, HS.patchConstantFunc, HS.inputControlPoints, |
| HS.outputControlPoints, HS.domain, HS.partition, |
| HS.outputPrimitive, HS.maxTessFactor); |
| } break; |
| |
| case DxilMDHelper::kDxilAutoBindingSpaceTag: { |
| MDNode *pNode = cast<MDNode>(MDO.get()); |
| autoBindingSpace = ConstMDToUint32(pNode->getOperand(0)); |
| break; |
| } |
| case DxilMDHelper::kDxilRayPayloadSizeTag: { |
| DXASSERT(props.IsAnyHit() || props.IsClosestHit() || props.IsMiss() || |
| props.IsCallable(), |
| "else invalid shader kind"); |
| props.ShaderProps.Ray.payloadSizeInBytes = |
| ConstMDToUint32(MDO); |
| } break; |
| case DxilMDHelper::kDxilRayAttribSizeTag: { |
| DXASSERT(props.IsAnyHit() || props.IsClosestHit(), |
| "else invalid shader kind"); |
| props.ShaderProps.Ray.attributeSizeInBytes = |
| ConstMDToUint32(MDO); |
| } break; |
| case DxilMDHelper::kDxilShaderKindTag: { |
| DXIL::ShaderKind kind = |
| static_cast<DXIL::ShaderKind>(ConstMDToUint32(MDO)); |
| DXASSERT(props.shaderKind == DXIL::ShaderKind::Library, |
| "else invalid shader kind"); |
| props.shaderKind = kind; |
| } break; |
| case DxilMDHelper::kDxilMSStateTag: { |
| DXASSERT(props.IsMS(), "else invalid shader kind"); |
| auto &MS = props.ShaderProps.MS; |
| LoadDxilMSState(MDO, MS.numThreads, MS.maxVertexCount, |
| MS.maxPrimitiveCount, MS.outputTopology, |
| MS.payloadSizeInBytes); |
| } break; |
| case DxilMDHelper::kDxilASStateTag: { |
| DXASSERT(props.IsAS(), "else invalid shader kind"); |
| auto &AS = props.ShaderProps.AS; |
| LoadDxilASState(MDO, AS.numThreads, AS.payloadSizeInBytes); |
| } break; |
| default: |
| DXASSERT(false, "Unknown extended shader properties tag"); |
| m_bExtraMetadata = true; |
| break; |
| } |
| } |
| |
| if (bEarlyDepth) { |
| DXASSERT(props.IsPS(), "else invalid shader kind"); |
| props.ShaderProps.PS.EarlyDepthStencil = true; |
| } |
| } |
| |
| MDTuple * |
| DxilMDHelper::EmitDxilFunctionProps(const hlsl::DxilFunctionProps *props, |
| const Function *F) { |
| bool bRayAttributes = false; |
| Metadata *MDVals[30]; |
| std::fill(MDVals, MDVals + _countof(MDVals), nullptr); |
| unsigned valIdx = 0; |
| MDVals[valIdx++] = ValueAsMetadata::get(const_cast<Function*>(F)); |
| MDVals[valIdx++] = Uint32ToConstMD(static_cast<unsigned>(props->shaderKind)); |
| switch (props->shaderKind) { |
| case DXIL::ShaderKind::Compute: |
| MDVals[valIdx++] = Uint32ToConstMD(props->ShaderProps.CS.numThreads[0]); |
| MDVals[valIdx++] = Uint32ToConstMD(props->ShaderProps.CS.numThreads[1]); |
| MDVals[valIdx++] = Uint32ToConstMD(props->ShaderProps.CS.numThreads[2]); |
| break; |
| case DXIL::ShaderKind::Geometry: |
| MDVals[valIdx++] = |
| Uint8ToConstMD((uint8_t)props->ShaderProps.GS.inputPrimitive); |
| MDVals[valIdx++] = Uint32ToConstMD(props->ShaderProps.GS.maxVertexCount); |
| MDVals[valIdx++] = Uint32ToConstMD(props->ShaderProps.GS.instanceCount); |
| for (size_t i = 0; |
| i < _countof(props->ShaderProps.GS.streamPrimitiveTopologies); ++i) |
| MDVals[valIdx++] = Uint8ToConstMD( |
| (uint8_t)props->ShaderProps.GS.streamPrimitiveTopologies[i]); |
| break; |
| case DXIL::ShaderKind::Hull: |
| MDVals[valIdx++] = |
| ValueAsMetadata::get(props->ShaderProps.HS.patchConstantFunc); |
| MDVals[valIdx++] = Uint8ToConstMD((uint8_t)props->ShaderProps.HS.domain); |
| MDVals[valIdx++] = Uint8ToConstMD((uint8_t)props->ShaderProps.HS.partition); |
| MDVals[valIdx++] = |
| Uint8ToConstMD((uint8_t)props->ShaderProps.HS.outputPrimitive); |
| MDVals[valIdx++] = |
| Uint32ToConstMD(props->ShaderProps.HS.inputControlPoints); |
| MDVals[valIdx++] = |
| Uint32ToConstMD(props->ShaderProps.HS.outputControlPoints); |
| MDVals[valIdx++] = FloatToConstMD(props->ShaderProps.HS.maxTessFactor); |
| break; |
| case DXIL::ShaderKind::Domain: |
| MDVals[valIdx++] = Uint8ToConstMD((uint8_t)props->ShaderProps.DS.domain); |
| MDVals[valIdx++] = |
| Uint32ToConstMD(props->ShaderProps.DS.inputControlPoints); |
| break; |
| case DXIL::ShaderKind::Pixel: |
| MDVals[valIdx++] = BoolToConstMD(props->ShaderProps.PS.EarlyDepthStencil); |
| break; |
| case DXIL::ShaderKind::AnyHit: |
| case DXIL::ShaderKind::ClosestHit: |
| bRayAttributes = true; |
| case DXIL::ShaderKind::Miss: |
| case DXIL::ShaderKind::Callable: |
| // payload/params unioned and first: |
| MDVals[valIdx++] = Uint32ToConstMD(props->ShaderProps.Ray.payloadSizeInBytes); |
| if (bRayAttributes) |
| MDVals[valIdx++] = Uint32ToConstMD(props->ShaderProps.Ray.attributeSizeInBytes); |
| break; |
| case DXIL::ShaderKind::Mesh: |
| MDVals[valIdx++] = Uint32ToConstMD(props->ShaderProps.MS.numThreads[0]); |
| MDVals[valIdx++] = Uint32ToConstMD(props->ShaderProps.MS.numThreads[1]); |
| MDVals[valIdx++] = Uint32ToConstMD(props->ShaderProps.MS.numThreads[2]); |
| MDVals[valIdx++] = Uint32ToConstMD(props->ShaderProps.MS.maxVertexCount); |
| MDVals[valIdx++] = Uint32ToConstMD(props->ShaderProps.MS.maxPrimitiveCount); |
| MDVals[valIdx++] = Uint8ToConstMD((uint8_t)props->ShaderProps.MS.outputTopology); |
| MDVals[valIdx++] = Uint32ToConstMD(props->ShaderProps.MS.payloadSizeInBytes); |
| break; |
| case DXIL::ShaderKind::Amplification: |
| MDVals[valIdx++] = Uint32ToConstMD(props->ShaderProps.AS.numThreads[0]); |
| MDVals[valIdx++] = Uint32ToConstMD(props->ShaderProps.AS.numThreads[1]); |
| MDVals[valIdx++] = Uint32ToConstMD(props->ShaderProps.AS.numThreads[2]); |
| MDVals[valIdx++] = Uint32ToConstMD(props->ShaderProps.AS.payloadSizeInBytes); |
| break; |
| default: |
| break; |
| } |
| return MDTuple::get(m_Ctx, ArrayRef<llvm::Metadata *>(MDVals, valIdx)); |
| } |
| |
| void DxilMDHelper::EmitDxilViewIdState(std::vector<unsigned> &SerializedState) { |
| const vector<unsigned> &Data = SerializedState; |
| // If all UINTs are zero, do not emit ViewIdState. |
| if (!std::any_of(Data.begin(), Data.end(), [](unsigned e){return e!=0;})) |
| return; |
| |
| Constant *V = ConstantDataArray::get(m_Ctx, ArrayRef<uint32_t>(Data)); |
| NamedMDNode *pViewIdNamedMD = m_pModule->getNamedMetadata(kDxilViewIdStateMDName); |
| IFTBOOL(pViewIdNamedMD == nullptr, DXC_E_INCORRECT_DXIL_METADATA); |
| pViewIdNamedMD = m_pModule->getOrInsertNamedMetadata(kDxilViewIdStateMDName); |
| pViewIdNamedMD->addOperand(MDNode::get(m_Ctx, {ConstantAsMetadata::get(V)})); |
| } |
| |
| void DxilMDHelper::LoadDxilViewIdState(std::vector<unsigned> &SerializedState) { |
| NamedMDNode *pViewIdStateNamedMD = m_pModule->getNamedMetadata(kDxilViewIdStateMDName); |
| if(!pViewIdStateNamedMD) |
| return; |
| |
| IFTBOOL(pViewIdStateNamedMD->getNumOperands() == 1, DXC_E_INCORRECT_DXIL_METADATA); |
| |
| MDNode *pNode = pViewIdStateNamedMD->getOperand(0); |
| IFTBOOL(pNode->getNumOperands() == 1, DXC_E_INCORRECT_DXIL_METADATA); |
| const MDOperand &MDO = pNode->getOperand(0); |
| |
| const ConstantAsMetadata *pMetaData = dyn_cast<ConstantAsMetadata>(MDO.get()); |
| IFTBOOL(pMetaData != nullptr, DXC_E_INCORRECT_DXIL_METADATA); |
| if (isa<ConstantAggregateZero>(pMetaData->getValue())) |
| return; |
| const ConstantDataArray *pData = dyn_cast<ConstantDataArray>(pMetaData->getValue()); |
| IFTBOOL(pData != nullptr, DXC_E_INCORRECT_DXIL_METADATA); |
| IFTBOOL(pData->getElementType() == Type::getInt32Ty(m_Ctx), DXC_E_INCORRECT_DXIL_METADATA); |
| IFTBOOL(pData->getRawDataValues().size() < UINT_MAX && |
| (pData->getRawDataValues().size() & 3) == 0, DXC_E_INCORRECT_DXIL_METADATA); |
| |
| SerializedState.clear(); |
| unsigned size = (unsigned)pData->getRawDataValues().size() / 4; |
| SerializedState.resize(size); |
| const unsigned *Ptr = (const unsigned *)pData->getRawDataValues().begin(); |
| memcpy(SerializedState.data(), Ptr, size * sizeof(unsigned)); |
| } |
| |
| MDNode *DxilMDHelper::EmitControlFlowHints(llvm::LLVMContext &Ctx, std::vector<DXIL::ControlFlowHint> &hints) { |
| SmallVector<Metadata *, 4> Args; |
| // Reserve operand 0 for self reference. |
| auto TempNode = MDNode::getTemporary(Ctx, None); |
| Args.emplace_back(TempNode.get()); |
| Args.emplace_back(MDString::get(Ctx, kDxilControlFlowHintMDName)); |
| for (DXIL::ControlFlowHint &hint : hints) |
| Args.emplace_back(Uint32ToConstMD(static_cast<unsigned>(hint), Ctx)); |
| |
| MDNode *hintsNode = MDNode::get(Ctx, Args); |
| // Set the first operand to itself. |
| hintsNode->replaceOperandWith(0, hintsNode); |
| return hintsNode; |
| } |
| |
| unsigned DxilMDHelper::GetControlFlowHintMask(const Instruction *I) { |
| // Check that there are control hint to use |
| // branch. |
| MDNode *MD = I->getMetadata(hlsl::DxilMDHelper::kDxilControlFlowHintMDName); |
| if (!MD) |
| return 0; |
| |
| if (MD->getNumOperands() < 3) |
| return 0; |
| unsigned mask = 0; |
| for (unsigned i = 2; i < MD->getNumOperands(); i++) { |
| Metadata *Op = MD->getOperand(2).get(); |
| auto ConstOp = cast<ConstantAsMetadata>(Op); |
| unsigned hint = ConstOp->getValue()->getUniqueInteger().getLimitedValue(); |
| mask |= 1 << hint; |
| } |
| return mask; |
| } |
| |
| bool DxilMDHelper::HasControlFlowHintToPreventFlatten( |
| const llvm::Instruction *I) { |
| unsigned mask = GetControlFlowHintMask(I); |
| const unsigned BranchMask = |
| 1 << (unsigned)(DXIL::ControlFlowHint::Branch) | |
| 1 << (unsigned)(DXIL::ControlFlowHint::Call) | |
| 1 << (unsigned)(DXIL::ControlFlowHint::ForceCase); |
| return mask & BranchMask; |
| } |
| |
| void DxilMDHelper::EmitSubobjects(const DxilSubobjects &Subobjects) { |
| NamedMDNode *pSubobjectsNamedMD = m_pModule->getNamedMetadata(kDxilSubobjectsMDName); |
| IFTBOOL(pSubobjectsNamedMD == nullptr, DXC_E_INCORRECT_DXIL_METADATA); |
| pSubobjectsNamedMD = m_pModule->getOrInsertNamedMetadata(kDxilSubobjectsMDName); |
| |
| const auto &objMap = Subobjects.GetSubobjects(); |
| for (auto &it : objMap) |
| pSubobjectsNamedMD->addOperand(cast<MDNode>(EmitSubobject(*it.second))); |
| } |
| |
| void DxilMDHelper::LoadSubobjects(DxilSubobjects &Subobjects) { |
| NamedMDNode *pSubobjectsNamedMD = m_pModule->getNamedMetadata(kDxilSubobjectsMDName); |
| if (!pSubobjectsNamedMD) |
| return; |
| |
| for (unsigned i = 0; i < pSubobjectsNamedMD->getNumOperands(); ++i) |
| LoadSubobject(*pSubobjectsNamedMD->getOperand(i), Subobjects); |
| } |
| |
| Metadata *DxilMDHelper::EmitSubobject(const DxilSubobject &obj) { |
| SmallVector<Metadata *, 6> Args; |
| Args.emplace_back(MDString::get(m_Ctx, obj.GetName())); |
| Args.emplace_back(Uint32ToConstMD((unsigned)obj.GetKind())); |
| bool bLocalRS = false; |
| IFTBOOL(DXIL::IsValidSubobjectKind(obj.GetKind()), DXC_E_INCORRECT_DXIL_METADATA); |
| switch (obj.GetKind()) { |
| case DXIL::SubobjectKind::StateObjectConfig: { |
| uint32_t Flags; |
| IFTBOOL(obj.GetStateObjectConfig(Flags), |
| DXC_E_INCORRECT_DXIL_METADATA); |
| Args.emplace_back(Uint32ToConstMD((unsigned)Flags)); |
| break; |
| } |
| case DXIL::SubobjectKind::LocalRootSignature: |
| bLocalRS = true; |
| __fallthrough; |
| case DXIL::SubobjectKind::GlobalRootSignature: { |
| const char * Text; |
| const void * Data; |
| uint32_t Size; |
| IFTBOOL(obj.GetRootSignature(bLocalRS, Data, Size, &Text), |
| DXC_E_INCORRECT_DXIL_METADATA); |
| Constant *V = ConstantDataArray::get(m_Ctx, |
| ArrayRef<uint8_t>((const uint8_t *)Data, Size)); |
| Args.emplace_back(MDNode::get(m_Ctx, { ConstantAsMetadata::get(V) })); |
| Args.emplace_back(MDString::get(m_Ctx, Text)); |
| break; |
| } |
| case DXIL::SubobjectKind::SubobjectToExportsAssociation: { |
| StringRef Subobj; |
| const char * const * Exports; |
| uint32_t NumExports; |
| IFTBOOL(obj.GetSubobjectToExportsAssociation(Subobj, Exports, NumExports), |
| DXC_E_INCORRECT_DXIL_METADATA); |
| SmallVector<Metadata *, 4> strArgs; |
| for (unsigned i = 0; i < NumExports; ++i) { |
| strArgs.emplace_back(MDString::get(m_Ctx, Exports[i])); |
| } |
| Args.emplace_back(MDString::get(m_Ctx, Subobj)); |
| Args.emplace_back(MDNode::get(m_Ctx, strArgs)); |
| break; |
| } |
| case DXIL::SubobjectKind::RaytracingShaderConfig: { |
| uint32_t MaxPayloadSizeInBytes; |
| uint32_t MaxAttributeSizeInBytes; |
| IFTBOOL(obj.GetRaytracingShaderConfig(MaxPayloadSizeInBytes, |
| MaxAttributeSizeInBytes), |
| DXC_E_INCORRECT_DXIL_METADATA); |
| Args.emplace_back(Uint32ToConstMD(MaxPayloadSizeInBytes)); |
| Args.emplace_back(Uint32ToConstMD(MaxAttributeSizeInBytes)); |
| break; |
| } |
| case DXIL::SubobjectKind::RaytracingPipelineConfig: { |
| uint32_t MaxTraceRecursionDepth; |
| IFTBOOL(obj.GetRaytracingPipelineConfig(MaxTraceRecursionDepth), |
| DXC_E_INCORRECT_DXIL_METADATA); |
| Args.emplace_back(Uint32ToConstMD(MaxTraceRecursionDepth)); |
| break; |
| } |
| case DXIL::SubobjectKind::HitGroup: { |
| llvm::StringRef Intersection, AnyHit, ClosestHit; |
| DXIL::HitGroupType hgType; |
| IFTBOOL(obj.GetHitGroup(hgType, Intersection, AnyHit, ClosestHit), |
| DXC_E_INCORRECT_DXIL_METADATA); |
| Args.emplace_back(Uint32ToConstMD((uint32_t)hgType)); |
| Args.emplace_back(MDString::get(m_Ctx, Intersection)); |
| Args.emplace_back(MDString::get(m_Ctx, AnyHit)); |
| Args.emplace_back(MDString::get(m_Ctx, ClosestHit)); |
| break; |
| } |
| case DXIL::SubobjectKind::RaytracingPipelineConfig1: { |
| uint32_t MaxTraceRecursionDepth; |
| uint32_t Flags; |
| IFTBOOL(obj.GetRaytracingPipelineConfig1(MaxTraceRecursionDepth, Flags), |
| DXC_E_INCORRECT_DXIL_METADATA); |
| Args.emplace_back(Uint32ToConstMD(MaxTraceRecursionDepth)); |
| Args.emplace_back(Uint32ToConstMD(Flags)); |
| break; |
| } |
| default: |
| DXASSERT(false, "otherwise, we didn't handle a valid subobject kind"); |
| m_bExtraMetadata = true; |
| break; |
| } |
| return MDNode::get(m_Ctx, Args); |
| } |
| void DxilMDHelper::LoadSubobject(const llvm::MDNode &MD, DxilSubobjects &Subobjects) { |
| IFTBOOL(MD.getNumOperands() >= 2, DXC_E_INCORRECT_DXIL_METADATA); |
| unsigned i = 0; |
| StringRef name(StringMDToStringRef(MD.getOperand(i++))); |
| DXIL::SubobjectKind kind = (DXIL::SubobjectKind)ConstMDToUint32(MD.getOperand(i++)); |
| IFTBOOL(DXIL::IsValidSubobjectKind(kind), DXC_E_INCORRECT_DXIL_METADATA); |
| bool bLocalRS = false; |
| switch (kind) { |
| case DXIL::SubobjectKind::StateObjectConfig: { |
| uint32_t Flags = ConstMDToUint32(MD.getOperand(i++)); |
| IFTBOOL(0 == ((~(uint32_t)DXIL::StateObjectFlags::ValidMask) & Flags), |
| DXC_E_INCORRECT_DXIL_METADATA); |
| Subobjects.CreateStateObjectConfig(name, Flags); |
| break; |
| } |
| case DXIL::SubobjectKind::LocalRootSignature: |
| bLocalRS = true; |
| __fallthrough; |
| case DXIL::SubobjectKind::GlobalRootSignature: { |
| const MDNode *pDataMDWrapper = dyn_cast<MDNode>(MD.getOperand(i++)); |
| IFTBOOL(pDataMDWrapper != nullptr, DXC_E_INCORRECT_DXIL_METADATA); |
| IFTBOOL(pDataMDWrapper->getNumOperands() == 1, DXC_E_INCORRECT_DXIL_METADATA); |
| const ConstantAsMetadata *pDataMD = dyn_cast<ConstantAsMetadata>(pDataMDWrapper->getOperand(0)); |
| const ConstantDataArray *pData = dyn_cast<ConstantDataArray>(pDataMD->getValue()); |
| IFTBOOL(pData != nullptr, DXC_E_INCORRECT_DXIL_METADATA); |
| IFTBOOL(pData->getElementType() == Type::getInt8Ty(m_Ctx), DXC_E_INCORRECT_DXIL_METADATA); |
| IFTBOOL(pData->getRawDataValues().size() < UINT_MAX && |
| (pData->getRawDataValues().size() & 3) == 0, DXC_E_INCORRECT_DXIL_METADATA); |
| const void *Data = pData->getRawDataValues().begin(); |
| uint32_t Size = pData->getRawDataValues().size(); |
| StringRef Text(StringMDToStringRef(MD.getOperand(i++))); |
| Subobjects.CreateRootSignature(name, bLocalRS, Data, Size, Text.size() ? &Text : nullptr); |
| break; |
| } |
| case DXIL::SubobjectKind::SubobjectToExportsAssociation: { |
| StringRef Subobj(StringMDToStringRef(MD.getOperand(i++))); |
| const MDNode *exportMD = dyn_cast<MDNode>(MD.getOperand(i++)); |
| SmallVector<StringRef, 4> Exports; |
| for (unsigned iExport = 0; iExport < exportMD->getNumOperands(); iExport++) { |
| Exports.push_back(StringMDToStringRef(exportMD->getOperand(iExport))); |
| } |
| Subobjects.CreateSubobjectToExportsAssociation(name, Subobj, Exports.data(), Exports.size()); |
| break; |
| } |
| case DXIL::SubobjectKind::RaytracingShaderConfig: { |
| uint32_t MaxPayloadSizeInBytes = ConstMDToUint32(MD.getOperand(i++));; |
| uint32_t MaxAttributeSizeInBytes = ConstMDToUint32(MD.getOperand(i++));; |
| Subobjects.CreateRaytracingShaderConfig(name, MaxPayloadSizeInBytes, MaxAttributeSizeInBytes); |
| break; |
| } |
| case DXIL::SubobjectKind::RaytracingPipelineConfig: { |
| uint32_t MaxTraceRecursionDepth = ConstMDToUint32(MD.getOperand(i++));; |
| Subobjects.CreateRaytracingPipelineConfig(name, MaxTraceRecursionDepth); |
| break; |
| } |
| case DXIL::SubobjectKind::HitGroup: { |
| uint32_t hgType = ConstMDToUint32(MD.getOperand(i++)); |
| StringRef Intersection(StringMDToStringRef(MD.getOperand(i++))); |
| StringRef AnyHit(StringMDToStringRef(MD.getOperand(i++))); |
| StringRef ClosestHit(StringMDToStringRef(MD.getOperand(i++))); |
| Subobjects.CreateHitGroup(name, (DXIL::HitGroupType)hgType, AnyHit, ClosestHit, Intersection); |
| break; |
| } |
| case DXIL::SubobjectKind::RaytracingPipelineConfig1: { |
| uint32_t MaxTraceRecursionDepth = ConstMDToUint32(MD.getOperand(i++)); |
| uint32_t Flags = ConstMDToUint32(MD.getOperand(i++)); |
| IFTBOOL(0 == |
| ((~(uint32_t)DXIL::RaytracingPipelineFlags::ValidMask) & Flags), |
| DXC_E_INCORRECT_DXIL_METADATA); |
| Subobjects.CreateRaytracingPipelineConfig1(name, MaxTraceRecursionDepth, |
| Flags); |
| break; |
| } |
| default: |
| DXASSERT(false, "otherwise, we didn't handle a valid subobject kind"); |
| m_bExtraMetadata = true; |
| break; |
| } |
| } |
| |
| MDTuple *DxilMDHelper::EmitDxilSampler(const DxilSampler &S) { |
| Metadata *MDVals[kDxilSamplerNumFields]; |
| |
| EmitDxilResourceBase(S, &MDVals[0]); |
| |
| // Sampler-specific fields. |
| MDVals[kDxilSamplerType ] = Uint32ToConstMD((unsigned)S.GetSamplerKind()); |
| |
| // Name-value list of extended properties. |
| MDVals[kDxilSamplerNameValueList] = nullptr; |
| vector<Metadata *> MDExtraVals; |
| m_ExtraPropertyHelper->EmitSamplerProperties(S, MDExtraVals); |
| if (!MDExtraVals.empty()) { |
| MDVals[kDxilSamplerNameValueList] = MDNode::get(m_Ctx, MDExtraVals); |
| } |
| |
| return MDNode::get(m_Ctx, MDVals); |
| } |
| |
| void DxilMDHelper::LoadDxilSampler(const MDOperand &MDO, DxilSampler &S) { |
| IFTBOOL(MDO.get() != nullptr, DXC_E_INCORRECT_DXIL_METADATA); |
| const MDTuple *pTupleMD = dyn_cast<MDTuple>(MDO.get()); |
| IFTBOOL(pTupleMD != nullptr, DXC_E_INCORRECT_DXIL_METADATA); |
| IFTBOOL(pTupleMD->getNumOperands() == kDxilSamplerNumFields, DXC_E_INCORRECT_DXIL_METADATA); |
| |
| LoadDxilResourceBase(MDO, S); |
| |
| // Sampler-specific fields. |
| S.SetSamplerKind((DxilSampler::SamplerKind)ConstMDToUint32(pTupleMD->getOperand(kDxilSamplerType))); |
| |
| // Name-value list of extended properties. |
| m_ExtraPropertyHelper->m_bExtraMetadata = false; |
| m_ExtraPropertyHelper->LoadSamplerProperties(pTupleMD->getOperand(kDxilSamplerNameValueList), S); |
| m_bExtraMetadata |= m_ExtraPropertyHelper->m_bExtraMetadata; |
| } |
| |
| const MDOperand &DxilMDHelper::GetResourceClass(llvm::MDNode *MD, |
| DXIL::ResourceClass &RC) { |
| IFTBOOL(MD->getNumOperands() >= |
| DxilMDHelper::kHLDxilResourceAttributeNumFields, |
| DXC_E_INCORRECT_DXIL_METADATA); |
| RC = static_cast<DxilResource::Class>(ConstMDToUint32( |
| MD->getOperand(DxilMDHelper::kHLDxilResourceAttributeClass))); |
| return MD->getOperand(DxilMDHelper::kHLDxilResourceAttributeMeta); |
| } |
| |
| void DxilMDHelper::LoadDxilResourceBaseFromMDNode(llvm::MDNode *MD, |
| DxilResourceBase &R) { |
| DxilResource::Class RC = DxilResource::Class::Invalid; |
| const MDOperand &Meta = GetResourceClass(MD, RC); |
| |
| switch (RC) { |
| case DxilResource::Class::CBuffer: { |
| DxilCBuffer CB; |
| LoadDxilCBuffer(Meta, CB); |
| R = CB; |
| } break; |
| case DxilResource::Class::Sampler: { |
| DxilSampler S; |
| LoadDxilSampler(Meta, S); |
| R = S; |
| } break; |
| case DxilResource::Class::SRV: { |
| DxilResource Res; |
| LoadDxilSRV(Meta, Res); |
| R = Res; |
| } break; |
| case DxilResource::Class::UAV: { |
| DxilResource Res; |
| LoadDxilUAV(Meta, Res); |
| R = Res; |
| } break; |
| default: |
| DXASSERT(0, "Invalid metadata"); |
| } |
| } |
| |
| void DxilMDHelper::LoadDxilResourceFromMDNode(llvm::MDNode *MD, |
| DxilResource &R) { |
| DxilResource::Class RC = DxilResource::Class::Invalid; |
| const MDOperand &Meta = GetResourceClass(MD, RC); |
| |
| switch (RC) { |
| case DxilResource::Class::SRV: { |
| LoadDxilSRV(Meta, R); |
| } break; |
| case DxilResource::Class::UAV: { |
| LoadDxilUAV(Meta, R); |
| } break; |
| default: |
| DXASSERT(0, "Invalid metadata"); |
| } |
| } |
| |
| void DxilMDHelper::LoadDxilSamplerFromMDNode(llvm::MDNode *MD, DxilSampler &S) { |
| DxilResource::Class RC = DxilResource::Class::Invalid; |
| const MDOperand &Meta = GetResourceClass(MD, RC); |
| |
| switch (RC) { |
| case DxilResource::Class::Sampler: { |
| LoadDxilSampler(Meta, S); |
| } break; |
| default: |
| DXASSERT(0, "Invalid metadata"); |
| } |
| } |
| |
| // |
| // DxilExtraPropertyHelper shader-specific methods. |
| // |
| MDTuple *DxilMDHelper::EmitDxilGSState(DXIL::InputPrimitive Primitive, |
| unsigned MaxVertexCount, |
| unsigned ActiveStreamMask, |
| DXIL::PrimitiveTopology StreamPrimitiveTopology, |
| unsigned GSInstanceCount) { |
| Metadata *MDVals[kDxilGSStateNumFields]; |
| |
| MDVals[kDxilGSStateInputPrimitive ] = Uint32ToConstMD((unsigned)Primitive); |
| MDVals[kDxilGSStateMaxVertexCount ] = Uint32ToConstMD(MaxVertexCount); |
| MDVals[kDxilGSStateActiveStreamMask ] = Uint32ToConstMD(ActiveStreamMask); |
| MDVals[kDxilGSStateOutputStreamTopology] = Uint32ToConstMD((unsigned)StreamPrimitiveTopology); |
| MDVals[kDxilGSStateGSInstanceCount ] = Uint32ToConstMD(GSInstanceCount); |
| |
| return MDNode::get(m_Ctx, MDVals); |
| } |
| |
| void DxilMDHelper::LoadDxilGSState(const MDOperand &MDO, |
| DXIL::InputPrimitive &Primitive, |
| unsigned &MaxVertexCount, |
| unsigned &ActiveStreamMask, |
| DXIL::PrimitiveTopology &StreamPrimitiveTopology, |
| unsigned &GSInstanceCount) { |
| IFTBOOL(MDO.get() != nullptr, DXC_E_INCORRECT_DXIL_METADATA); |
| const MDTuple *pTupleMD = dyn_cast<MDTuple>(MDO.get()); |
| IFTBOOL(pTupleMD != nullptr, DXC_E_INCORRECT_DXIL_METADATA); |
| IFTBOOL(pTupleMD->getNumOperands() == kDxilGSStateNumFields, DXC_E_INCORRECT_DXIL_METADATA); |
| |
| Primitive = (DXIL::InputPrimitive)ConstMDToUint32(pTupleMD->getOperand(kDxilGSStateInputPrimitive)); |
| MaxVertexCount = ConstMDToUint32(pTupleMD->getOperand(kDxilGSStateMaxVertexCount)); |
| ActiveStreamMask = ConstMDToUint32(pTupleMD->getOperand(kDxilGSStateActiveStreamMask)); |
| StreamPrimitiveTopology = (DXIL::PrimitiveTopology)ConstMDToUint32(pTupleMD->getOperand(kDxilGSStateOutputStreamTopology)); |
| GSInstanceCount = ConstMDToUint32(pTupleMD->getOperand(kDxilGSStateGSInstanceCount)); |
| } |
| |
| MDTuple *DxilMDHelper::EmitDxilDSState(DXIL::TessellatorDomain Domain, unsigned InputControlPointCount) { |
| Metadata *MDVals[kDxilDSStateNumFields]; |
| |
| MDVals[kDxilDSStateTessellatorDomain ] = Uint32ToConstMD((unsigned)Domain); |
| MDVals[kDxilDSStateInputControlPointCount] = Uint32ToConstMD(InputControlPointCount); |
| |
| return MDNode::get(m_Ctx, MDVals); |
| } |
| |
| void DxilMDHelper::LoadDxilDSState(const MDOperand &MDO, |
| DXIL::TessellatorDomain &Domain, |
| unsigned &InputControlPointCount) { |
| IFTBOOL(MDO.get() != nullptr, DXC_E_INCORRECT_DXIL_METADATA); |
| const MDTuple *pTupleMD = dyn_cast<MDTuple>(MDO.get()); |
| IFTBOOL(pTupleMD != nullptr, DXC_E_INCORRECT_DXIL_METADATA); |
| IFTBOOL(pTupleMD->getNumOperands() == kDxilDSStateNumFields, DXC_E_INCORRECT_DXIL_METADATA); |
| |
| Domain = (DXIL::TessellatorDomain)ConstMDToUint32(pTupleMD->getOperand(kDxilDSStateTessellatorDomain)); |
| InputControlPointCount = ConstMDToUint32(pTupleMD->getOperand(kDxilDSStateInputControlPointCount)); |
| } |
| |
| MDTuple *DxilMDHelper::EmitDxilHSState(Function *pPatchConstantFunction, |
| unsigned InputControlPointCount, |
| unsigned OutputControlPointCount, |
| DXIL::TessellatorDomain TessDomain, |
| DXIL::TessellatorPartitioning TessPartitioning, |
| DXIL::TessellatorOutputPrimitive TessOutputPrimitive, |
| float MaxTessFactor) { |
| Metadata *MDVals[kDxilHSStateNumFields]; |
| |
| MDVals[kDxilHSStatePatchConstantFunction ] = ValueAsMetadata::get(pPatchConstantFunction); |
| MDVals[kDxilHSStateInputControlPointCount ] = Uint32ToConstMD(InputControlPointCount); |
| MDVals[kDxilHSStateOutputControlPointCount ] = Uint32ToConstMD(OutputControlPointCount); |
| MDVals[kDxilHSStateTessellatorDomain ] = Uint32ToConstMD((unsigned)TessDomain); |
| MDVals[kDxilHSStateTessellatorPartitioning ] = Uint32ToConstMD((unsigned)TessPartitioning); |
| MDVals[kDxilHSStateTessellatorOutputPrimitive] = Uint32ToConstMD((unsigned)TessOutputPrimitive); |
| MDVals[kDxilHSStateMaxTessellationFactor ] = FloatToConstMD(MaxTessFactor); |
| |
| return MDNode::get(m_Ctx, MDVals); |
| } |
| |
| void DxilMDHelper::LoadDxilHSState(const MDOperand &MDO, |
| Function *&pPatchConstantFunction, |
| unsigned &InputControlPointCount, |
| unsigned &OutputControlPointCount, |
| DXIL::TessellatorDomain &TessDomain, |
| DXIL::TessellatorPartitioning &TessPartitioning, |
| DXIL::TessellatorOutputPrimitive &TessOutputPrimitive, |
| float &MaxTessFactor) { |
| IFTBOOL(MDO.get() != nullptr, DXC_E_INCORRECT_DXIL_METADATA); |
| const MDTuple *pTupleMD = dyn_cast<MDTuple>(MDO.get()); |
| IFTBOOL(pTupleMD != nullptr, DXC_E_INCORRECT_DXIL_METADATA); |
| IFTBOOL(pTupleMD->getNumOperands() == kDxilHSStateNumFields, DXC_E_INCORRECT_DXIL_METADATA); |
| |
| pPatchConstantFunction = dyn_cast<Function>(ValueMDToValue(pTupleMD->getOperand(kDxilHSStatePatchConstantFunction))); |
| InputControlPointCount = ConstMDToUint32(pTupleMD->getOperand(kDxilHSStateInputControlPointCount)); |
| OutputControlPointCount = ConstMDToUint32(pTupleMD->getOperand(kDxilHSStateOutputControlPointCount)); |
| TessDomain = (DXIL::TessellatorDomain)ConstMDToUint32(pTupleMD->getOperand(kDxilHSStateTessellatorDomain)); |
| TessPartitioning = (DXIL::TessellatorPartitioning)ConstMDToUint32(pTupleMD->getOperand(kDxilHSStateTessellatorPartitioning)); |
| TessOutputPrimitive = (DXIL::TessellatorOutputPrimitive)ConstMDToUint32(pTupleMD->getOperand(kDxilHSStateTessellatorOutputPrimitive)); |
| MaxTessFactor = ConstMDToFloat(pTupleMD->getOperand(kDxilHSStateMaxTessellationFactor)); |
| } |
| |
| MDTuple *DxilMDHelper::EmitDxilMSState(const unsigned *NumThreads, |
| unsigned MaxVertexCount, |
| unsigned MaxPrimitiveCount, |
| DXIL::MeshOutputTopology OutputTopology, |
| unsigned payloadSizeInBytes) { |
| Metadata *MDVals[kDxilMSStateNumFields]; |
| vector<Metadata *> NumThreadVals; |
| |
| NumThreadVals.emplace_back(Uint32ToConstMD(NumThreads[0])); |
| NumThreadVals.emplace_back(Uint32ToConstMD(NumThreads[1])); |
| NumThreadVals.emplace_back(Uint32ToConstMD(NumThreads[2])); |
| MDVals[kDxilMSStateNumThreads] = MDNode::get(m_Ctx, NumThreadVals); |
| MDVals[kDxilMSStateMaxVertexCount] = Uint32ToConstMD(MaxVertexCount); |
| MDVals[kDxilMSStateMaxPrimitiveCount] = Uint32ToConstMD(MaxPrimitiveCount); |
| MDVals[kDxilMSStateOutputTopology] = Uint32ToConstMD((unsigned)OutputTopology); |
| MDVals[kDxilMSStatePayloadSizeInBytes] = Uint32ToConstMD(payloadSizeInBytes); |
| |
| return MDNode::get(m_Ctx, MDVals); |
| } |
| |
| void DxilMDHelper::LoadDxilMSState(const MDOperand &MDO, |
| unsigned *NumThreads, |
| unsigned &MaxVertexCount, |
| unsigned &MaxPrimitiveCount, |
| DXIL::MeshOutputTopology &OutputTopology, |
| unsigned &payloadSizeInBytes) { |
| IFTBOOL(MDO.get() != nullptr, DXC_E_INCORRECT_DXIL_METADATA); |
| const MDTuple *pTupleMD = dyn_cast<MDTuple>(MDO.get()); |
| IFTBOOL(pTupleMD != nullptr, DXC_E_INCORRECT_DXIL_METADATA); |
| IFTBOOL(pTupleMD->getNumOperands() == kDxilMSStateNumFields, DXC_E_INCORRECT_DXIL_METADATA); |
| |
| MDNode *pNode = cast<MDNode>(pTupleMD->getOperand(kDxilMSStateNumThreads)); |
| NumThreads[0] = ConstMDToUint32(pNode->getOperand(0)); |
| NumThreads[1] = ConstMDToUint32(pNode->getOperand(1)); |
| NumThreads[2] = ConstMDToUint32(pNode->getOperand(2)); |
| MaxVertexCount = ConstMDToUint32(pTupleMD->getOperand(kDxilMSStateMaxVertexCount)); |
| MaxPrimitiveCount = ConstMDToUint32(pTupleMD->getOperand(kDxilMSStateMaxPrimitiveCount)); |
| OutputTopology = (DXIL::MeshOutputTopology)ConstMDToUint32(pTupleMD->getOperand(kDxilMSStateOutputTopology)); |
| payloadSizeInBytes = ConstMDToUint32(pTupleMD->getOperand(kDxilMSStatePayloadSizeInBytes)); |
| } |
| |
| MDTuple *DxilMDHelper::EmitDxilASState(const unsigned *NumThreads, unsigned payloadSizeInBytes) { |
| Metadata *MDVals[kDxilASStateNumFields]; |
| vector<Metadata *> NumThreadVals; |
| |
| NumThreadVals.emplace_back(Uint32ToConstMD(NumThreads[0])); |
| NumThreadVals.emplace_back(Uint32ToConstMD(NumThreads[1])); |
| NumThreadVals.emplace_back(Uint32ToConstMD(NumThreads[2])); |
| MDVals[kDxilASStateNumThreads] = MDNode::get(m_Ctx, NumThreadVals); |
| MDVals[kDxilASStatePayloadSizeInBytes] = Uint32ToConstMD(payloadSizeInBytes); |
| |
| return MDNode::get(m_Ctx, MDVals); |
| } |
| |
| void DxilMDHelper::LoadDxilASState(const MDOperand &MDO, unsigned *NumThreads, unsigned &payloadSizeInBytes) { |
| IFTBOOL(MDO.get() != nullptr, DXC_E_INCORRECT_DXIL_METADATA); |
| const MDTuple *pTupleMD = dyn_cast<MDTuple>(MDO.get()); |
| IFTBOOL(pTupleMD != nullptr, DXC_E_INCORRECT_DXIL_METADATA); |
| IFTBOOL(pTupleMD->getNumOperands() == kDxilASStateNumFields, DXC_E_INCORRECT_DXIL_METADATA); |
| |
| MDNode *pNode = cast<MDNode>(pTupleMD->getOperand(kDxilASStateNumThreads)); |
| NumThreads[0] = ConstMDToUint32(pNode->getOperand(0)); |
| NumThreads[1] = ConstMDToUint32(pNode->getOperand(1)); |
| NumThreads[2] = ConstMDToUint32(pNode->getOperand(2)); |
| payloadSizeInBytes = ConstMDToUint32(pTupleMD->getOperand(kDxilASStatePayloadSizeInBytes)); |
| } |
| |
| // |
| // DxilExtraPropertyHelper methods. |
| // |
| DxilMDHelper::ExtraPropertyHelper::ExtraPropertyHelper(Module *pModule) |
| : m_Ctx(pModule->getContext()) |
| , m_pModule(pModule) |
| , m_bExtraMetadata(false) { |
| } |
| |
| DxilExtraPropertyHelper::DxilExtraPropertyHelper(Module *pModule) |
| : ExtraPropertyHelper(pModule) { |
| } |
| |
| void DxilExtraPropertyHelper::EmitSRVProperties(const DxilResource &SRV, std::vector<Metadata *> &MDVals) { |
| // Element type for typed resource. |
| if (!SRV.IsStructuredBuffer() && !SRV.IsRawBuffer()) { |
| MDVals.emplace_back(DxilMDHelper::Uint32ToConstMD(DxilMDHelper::kDxilTypedBufferElementTypeTag, m_Ctx)); |
| MDVals.emplace_back(DxilMDHelper::Uint32ToConstMD((unsigned)SRV.GetCompType().GetKind(), m_Ctx)); |
| } |
| // Element stride for structured buffer. |
| if (SRV.IsStructuredBuffer()) { |
| MDVals.emplace_back(DxilMDHelper::Uint32ToConstMD(DxilMDHelper::kDxilStructuredBufferElementStrideTag, m_Ctx)); |
| MDVals.emplace_back(DxilMDHelper::Uint32ToConstMD(SRV.GetElementStride(), m_Ctx)); |
| } |
| } |
| |
| void DxilExtraPropertyHelper::LoadSRVProperties(const MDOperand &MDO, DxilResource &SRV) { |
| SRV.SetElementStride(SRV.IsRawBuffer() ? 1 : 4); |
| SRV.SetCompType(CompType()); |
| |
| if (MDO.get() == nullptr) { |
| return; |
| } |
| |
| const MDTuple *pTupleMD = dyn_cast<MDTuple>(MDO.get()); |
| IFTBOOL(pTupleMD != nullptr, DXC_E_INCORRECT_DXIL_METADATA); |
| IFTBOOL((pTupleMD->getNumOperands() & 0x1) == 0, DXC_E_INCORRECT_DXIL_METADATA); |
| |
| for (unsigned i = 0; i < pTupleMD->getNumOperands(); i += 2) { |
| unsigned Tag = DxilMDHelper::ConstMDToUint32(pTupleMD->getOperand(i)); |
| const MDOperand &MDO = pTupleMD->getOperand(i + 1); |
| |
| switch (Tag) { |
| case DxilMDHelper::kDxilTypedBufferElementTypeTag: |
| DXASSERT_NOMSG(!SRV.IsStructuredBuffer() && !SRV.IsRawBuffer()); |
| SRV.SetCompType(CompType(DxilMDHelper::ConstMDToUint32(MDO))); |
| break; |
| case DxilMDHelper::kDxilStructuredBufferElementStrideTag: |
| DXASSERT_NOMSG(SRV.IsStructuredBuffer()); |
| SRV.SetElementStride(DxilMDHelper::ConstMDToUint32(MDO)); |
| break; |
| default: |
| DXASSERT(false, "Unknown resource record tag"); |
| m_bExtraMetadata = true; |
| break; |
| } |
| } |
| } |
| |
| void DxilExtraPropertyHelper::EmitUAVProperties(const DxilResource &UAV, std::vector<Metadata *> &MDVals) { |
| // Element type for typed RW resource. |
| if (!UAV.IsStructuredBuffer() && !UAV.IsRawBuffer() && !UAV.GetCompType().IsInvalid()) { |
| MDVals.emplace_back(DxilMDHelper::Uint32ToConstMD(DxilMDHelper::kDxilTypedBufferElementTypeTag, m_Ctx)); |
| MDVals.emplace_back(DxilMDHelper::Uint32ToConstMD((unsigned)UAV.GetCompType().GetKind(), m_Ctx)); |
| } |
| // Element stride for structured RW buffer. |
| if (UAV.IsStructuredBuffer()) { |
| MDVals.emplace_back(DxilMDHelper::Uint32ToConstMD(DxilMDHelper::kDxilStructuredBufferElementStrideTag, m_Ctx)); |
| MDVals.emplace_back(DxilMDHelper::Uint32ToConstMD(UAV.GetElementStride(), m_Ctx)); |
| } |
| // Sampler feedback kind |
| if (UAV.IsFeedbackTexture()) { |
| MDVals.emplace_back(DxilMDHelper::Uint32ToConstMD(DxilMDHelper::kDxilSamplerFeedbackKindTag, m_Ctx)); |
| MDVals.emplace_back(DxilMDHelper::Uint32ToConstMD((unsigned)UAV.GetSamplerFeedbackType(), m_Ctx)); |
| } |
| } |
| |
| void DxilExtraPropertyHelper::LoadUAVProperties(const MDOperand &MDO, DxilResource &UAV) { |
| UAV.SetElementStride(UAV.IsRawBuffer() ? 1 : 4); |
| UAV.SetCompType(CompType()); |
| |
| if (MDO.get() == nullptr) { |
| return; |
| } |
| |
| const MDTuple *pTupleMD = dyn_cast<MDTuple>(MDO.get()); |
| IFTBOOL(pTupleMD != nullptr, DXC_E_INCORRECT_DXIL_METADATA); |
| IFTBOOL((pTupleMD->getNumOperands() & 0x1) == 0, DXC_E_INCORRECT_DXIL_METADATA); |
| |
| for (unsigned i = 0; i < pTupleMD->getNumOperands(); i += 2) { |
| unsigned Tag = DxilMDHelper::ConstMDToUint32(pTupleMD->getOperand(i)); |
| const MDOperand &MDO = pTupleMD->getOperand(i + 1); |
| |
| switch (Tag) { |
| case DxilMDHelper::kDxilTypedBufferElementTypeTag: |
| DXASSERT_NOMSG(!UAV.IsStructuredBuffer() && !UAV.IsRawBuffer()); |
| UAV.SetCompType(CompType(DxilMDHelper::ConstMDToUint32(MDO))); |
| break; |
| case DxilMDHelper::kDxilStructuredBufferElementStrideTag: |
| DXASSERT_NOMSG(UAV.IsStructuredBuffer()); |
| UAV.SetElementStride(DxilMDHelper::ConstMDToUint32(MDO)); |
| break; |
| case DxilMDHelper::kDxilSamplerFeedbackKindTag: |
| DXASSERT_NOMSG(UAV.IsFeedbackTexture()); |
| UAV.SetSamplerFeedbackType((DXIL::SamplerFeedbackType)DxilMDHelper::ConstMDToUint32(MDO)); |
| break; |
| default: |
| DXASSERT(false, "Unknown resource record tag"); |
| m_bExtraMetadata = true; |
| break; |
| } |
| } |
| } |
| |
| void DxilExtraPropertyHelper::EmitCBufferProperties(const DxilCBuffer &CB, vector<Metadata *> &MDVals) { |
| // Emit property to preserve tbuffer kind |
| if (CB.GetKind() == DXIL::ResourceKind::TBuffer) { |
| MDVals.emplace_back(DxilMDHelper::Uint32ToConstMD(DxilMDHelper::kHLCBufferIsTBufferTag, m_Ctx)); |
| MDVals.emplace_back(DxilMDHelper::BoolToConstMD(true, m_Ctx)); |
| } |
| } |
| |
| void DxilExtraPropertyHelper::LoadCBufferProperties(const MDOperand &MDO, DxilCBuffer &CB) { |
| if (MDO.get() == nullptr) |
| return; |
| |
| const MDTuple *pTupleMD = dyn_cast<MDTuple>(MDO.get()); |
| IFTBOOL(pTupleMD != nullptr, DXC_E_INCORRECT_DXIL_METADATA); |
| IFTBOOL((pTupleMD->getNumOperands() & 0x1) == 0, DXC_E_INCORRECT_DXIL_METADATA); |
| |
| // Override kind for tbuffer that has not yet been converted to SRV. |
| CB.SetKind(DXIL::ResourceKind::CBuffer); |
| for (unsigned i = 0; i < pTupleMD->getNumOperands(); i += 2) { |
| unsigned Tag = DxilMDHelper::ConstMDToUint32(pTupleMD->getOperand(i)); |
| const MDOperand &MDO = pTupleMD->getOperand(i + 1); |
| |
| switch (Tag) { |
| case DxilMDHelper::kHLCBufferIsTBufferTag: |
| if (DxilMDHelper::ConstMDToBool(MDO)) { |
| CB.SetKind(DXIL::ResourceKind::TBuffer); |
| } |
| break; |
| default: |
| DXASSERT(false, "Unknown cbuffer tag"); |
| m_bExtraMetadata = true; |
| break; |
| } |
| } |
| } |
| |
| void DxilExtraPropertyHelper::EmitSamplerProperties(const DxilSampler &S, std::vector<Metadata *> &MDVals) { |
| // Nothing yet. |
| } |
| |
| void DxilExtraPropertyHelper::LoadSamplerProperties(const MDOperand &MDO, DxilSampler &S) { |
| // Nothing yet. |
| } |
| |
| void DxilExtraPropertyHelper::EmitSignatureElementProperties(const DxilSignatureElement &SE, |
| vector<Metadata *> &MDVals) { |
| // Output stream, if non-zero. |
| if (SE.GetOutputStream() != 0) { |
| MDVals.emplace_back(DxilMDHelper::Uint32ToConstMD(DxilMDHelper::kDxilSignatureElementOutputStreamTag, m_Ctx)); |
| MDVals.emplace_back(DxilMDHelper::Uint32ToConstMD(SE.GetOutputStream(), m_Ctx)); |
| } |
| |
| // Mask of Dynamically indexed components. |
| if (SE.GetDynIdxCompMask() != 0) { |
| MDVals.emplace_back(DxilMDHelper::Uint32ToConstMD(DxilMDHelper::kDxilSignatureElementDynIdxCompMaskTag, m_Ctx)); |
| MDVals.emplace_back(DxilMDHelper::Uint32ToConstMD(SE.GetDynIdxCompMask(), m_Ctx)); |
| } |
| |
| if (SE.GetUsageMask() != 0 && |
| DXIL::CompareVersions(m_ValMajor, m_ValMinor, 1, 5) >= 0) { |
| // Emitting this will not hurt old reatil loader (only asserts), |
| // and is required for signatures to match in validation. |
| MDVals.emplace_back(DxilMDHelper::Uint32ToConstMD(DxilMDHelper::kDxilSignatureElementUsageCompMaskTag, m_Ctx)); |
| MDVals.emplace_back(DxilMDHelper::Uint32ToConstMD(SE.GetUsageMask(), m_Ctx)); |
| } |
| } |
| |
| void DxilExtraPropertyHelper::LoadSignatureElementProperties(const MDOperand &MDO, DxilSignatureElement &SE) { |
| if (MDO.get() == nullptr) |
| return; |
| |
| const MDTuple *pTupleMD = dyn_cast<MDTuple>(MDO.get()); |
| IFTBOOL(pTupleMD != nullptr, DXC_E_INCORRECT_DXIL_METADATA); |
| IFTBOOL((pTupleMD->getNumOperands() & 0x1) == 0, DXC_E_INCORRECT_DXIL_METADATA); |
| |
| // Stream. |
| for (unsigned i = 0; i < pTupleMD->getNumOperands(); i += 2) { |
| unsigned Tag = DxilMDHelper::ConstMDToUint32(pTupleMD->getOperand(i)); |
| const MDOperand &MDO = pTupleMD->getOperand(i + 1); |
| |
| switch (Tag) { |
| case DxilMDHelper::kDxilSignatureElementOutputStreamTag: |
| SE.SetOutputStream(DxilMDHelper::ConstMDToUint32(MDO)); |
| break; |
| case DxilMDHelper::kHLSignatureElementGlobalSymbolTag: |
| break; |
| case DxilMDHelper::kDxilSignatureElementDynIdxCompMaskTag: |
| SE.SetDynIdxCompMask(DxilMDHelper::ConstMDToUint32(MDO)); |
| break; |
| case DxilMDHelper::kDxilSignatureElementUsageCompMaskTag: |
| SE.SetUsageMask(DxilMDHelper::ConstMDToUint32(MDO)); |
| break; |
| default: |
| DXASSERT(false, "Unknown signature element tag"); |
| m_bExtraMetadata = true; |
| break; |
| } |
| } |
| } |
| |
| // |
| // Utilities. |
| // |
| bool DxilMDHelper::IsKnownNamedMetaData(const llvm::NamedMDNode &Node) { |
| StringRef name = Node.getName(); |
| for (unsigned i = 0; i < DxilMDNames.size(); i++) { |
| if (name == DxilMDNames[i]) { |
| return true; |
| } |
| } |
| return false; |
| } |
| |
| void DxilMDHelper::combineDxilMetadata(llvm::Instruction *K, |
| const llvm::Instruction *J) { |
| if (IsMarkedNonUniform(J)) |
| MarkNonUniform(K); |
| if (IsMarkedPrecise(J)) |
| MarkPrecise(K); |
| } |
| |
| ConstantAsMetadata *DxilMDHelper::Int32ToConstMD(int32_t v, LLVMContext &Ctx) { |
| return ConstantAsMetadata::get(Constant::getIntegerValue(IntegerType::get(Ctx, 32), APInt(32, v))); |
| } |
| |
| ConstantAsMetadata *DxilMDHelper::Int32ToConstMD(int32_t v) { |
| return DxilMDHelper::Int32ToConstMD(v, m_Ctx); |
| } |
| |
| ConstantAsMetadata *DxilMDHelper::Uint32ToConstMD(unsigned v, LLVMContext &Ctx) { |
| return ConstantAsMetadata::get(Constant::getIntegerValue(IntegerType::get(Ctx, 32), APInt(32, v))); |
| } |
| |
| ConstantAsMetadata *DxilMDHelper::Uint32ToConstMD(unsigned v) { |
| return DxilMDHelper::Uint32ToConstMD(v, m_Ctx); |
| } |
| |
| ConstantAsMetadata *DxilMDHelper::Uint64ToConstMD(uint64_t v, LLVMContext &Ctx) { |
| return ConstantAsMetadata::get(Constant::getIntegerValue(IntegerType::get(Ctx, 64), APInt(64, v))); |
| } |
| ConstantAsMetadata *DxilMDHelper::Uint64ToConstMD(uint64_t v) { |
| return DxilMDHelper::Uint64ToConstMD(v, m_Ctx); |
| } |
| ConstantAsMetadata *DxilMDHelper::Int8ToConstMD(int8_t v) { |
| return ConstantAsMetadata::get(Constant::getIntegerValue(IntegerType::get(m_Ctx, 8), APInt(8, v))); |
| } |
| ConstantAsMetadata *DxilMDHelper::Uint8ToConstMD(uint8_t v) { |
| return ConstantAsMetadata::get(Constant::getIntegerValue(IntegerType::get(m_Ctx, 8), APInt(8, v))); |
| } |
| |
| ConstantAsMetadata *DxilMDHelper::BoolToConstMD(bool v, LLVMContext &Ctx) { |
| return ConstantAsMetadata::get(Constant::getIntegerValue(IntegerType::get(Ctx, 1), APInt(1, v ? 1 : 0))); |
| } |
| ConstantAsMetadata *DxilMDHelper::BoolToConstMD(bool v) { |
| return DxilMDHelper::BoolToConstMD(v, m_Ctx); |
| } |
| |
| ConstantAsMetadata *DxilMDHelper::FloatToConstMD(float v) { |
| return ConstantAsMetadata::get(ConstantFP::get(m_Ctx, APFloat(v))); |
| } |
| |
| int32_t DxilMDHelper::ConstMDToInt32(const MDOperand &MDO) { |
| ConstantInt *pConst = mdconst::extract<ConstantInt>(MDO); |
| IFTBOOL(pConst != nullptr, DXC_E_INCORRECT_DXIL_METADATA); |
| return (int32_t)pConst->getZExtValue(); |
| } |
| |
| unsigned DxilMDHelper::ConstMDToUint32(const MDOperand &MDO) { |
| ConstantInt *pConst = mdconst::extract<ConstantInt>(MDO); |
| IFTBOOL(pConst != nullptr, DXC_E_INCORRECT_DXIL_METADATA); |
| return (unsigned)pConst->getZExtValue(); |
| } |
| |
| uint64_t DxilMDHelper::ConstMDToUint64(const MDOperand &MDO) { |
| ConstantInt *pConst = mdconst::extract<ConstantInt>(MDO); |
| IFTBOOL(pConst != nullptr, DXC_E_INCORRECT_DXIL_METADATA); |
| return pConst->getZExtValue(); |
| } |
| |
| int8_t DxilMDHelper::ConstMDToInt8(const MDOperand &MDO) { |
| ConstantInt *pConst = mdconst::extract<ConstantInt>(MDO); |
| IFTBOOL(pConst != nullptr, DXC_E_INCORRECT_DXIL_METADATA); |
| return (int8_t)pConst->getZExtValue(); |
| } |
| |
| uint8_t DxilMDHelper::ConstMDToUint8(const MDOperand &MDO) { |
| ConstantInt *pConst = mdconst::extract<ConstantInt>(MDO); |
| IFTBOOL(pConst != nullptr, DXC_E_INCORRECT_DXIL_METADATA); |
| return (uint8_t)pConst->getZExtValue(); |
| } |
| |
| bool DxilMDHelper::ConstMDToBool(const MDOperand &MDO) { |
| ConstantInt *pConst = mdconst::extract<ConstantInt>(MDO); |
| IFTBOOL(pConst != nullptr, DXC_E_INCORRECT_DXIL_METADATA); |
| return pConst->getZExtValue() != 0; |
| } |
| |
| float DxilMDHelper::ConstMDToFloat(const MDOperand &MDO) { |
| ConstantFP *pConst = mdconst::extract<ConstantFP>(MDO); |
| IFTBOOL(pConst != nullptr, DXC_E_INCORRECT_DXIL_METADATA); |
| return pConst->getValueAPF().convertToFloat(); |
| } |
| |
| string DxilMDHelper::StringMDToString(const MDOperand &MDO) { |
| MDString *pMDString = dyn_cast<MDString>(MDO.get()); |
| IFTBOOL(pMDString != nullptr, DXC_E_INCORRECT_DXIL_METADATA); |
| return pMDString->getString(); |
| } |
| |
| StringRef DxilMDHelper::StringMDToStringRef(const MDOperand &MDO) { |
| MDString *pMDString = dyn_cast<MDString>(MDO.get()); |
| IFTBOOL(pMDString != nullptr, DXC_E_INCORRECT_DXIL_METADATA); |
| return pMDString->getString(); |
| } |
| |
| Value *DxilMDHelper::ValueMDToValue(const MDOperand &MDO) { |
| IFTBOOL(MDO.get() != nullptr, DXC_E_INCORRECT_DXIL_METADATA); |
| ValueAsMetadata *pValAsMD = dyn_cast<ValueAsMetadata>(MDO.get()); |
| IFTBOOL(pValAsMD != nullptr, DXC_E_INCORRECT_DXIL_METADATA); |
| Value *pValue = pValAsMD->getValue(); |
| IFTBOOL(pValue != nullptr, DXC_E_INCORRECT_DXIL_METADATA); |
| return pValue; |
| } |
| |
| MDTuple *DxilMDHelper::Uint32VectorToConstMDTuple(const std::vector<unsigned> &Vec) { |
| vector<Metadata *> MDVals; |
| |
| MDVals.resize(Vec.size()); |
| for (size_t i = 0; i < Vec.size(); i++) { |
| MDVals[i] = Uint32ToConstMD(Vec[i]); |
| } |
| return MDNode::get(m_Ctx, MDVals); |
| } |
| |
| void DxilMDHelper::ConstMDTupleToUint32Vector(MDTuple *pTupleMD, std::vector<unsigned> &Vec) { |
| IFTBOOL(pTupleMD != nullptr, DXC_E_INCORRECT_DXIL_METADATA); |
| |
| Vec.resize(pTupleMD->getNumOperands()); |
| for (size_t i = 0; i < pTupleMD->getNumOperands(); i++) { |
| Vec[i] = ConstMDToUint32(pTupleMD->getOperand(i)); |
| } |
| } |
| |
| bool DxilMDHelper::IsMarkedPrecise(const Instruction *inst) { |
| int32_t val = 0; |
| if (MDNode *precise = inst->getMetadata(kDxilPreciseAttributeMDName)) { |
| assert(precise->getNumOperands() == 1); |
| val = ConstMDToInt32(precise->getOperand(0)); |
| } |
| return val; |
| } |
| |
| void DxilMDHelper::MarkPrecise(Instruction *I) { |
| LLVMContext &Ctx = I->getContext(); |
| MDNode *preciseNode = MDNode::get( |
| Ctx, |
| { ConstantAsMetadata::get(ConstantInt::get(Type::getInt32Ty(Ctx), 1)) }); |
| |
| I->setMetadata(DxilMDHelper::kDxilPreciseAttributeMDName, preciseNode); |
| } |
| |
| bool DxilMDHelper::IsMarkedNonUniform(const Instruction *inst) { |
| int32_t val = 0; |
| if (MDNode *precise = inst->getMetadata(kDxilNonUniformAttributeMDName)) { |
| assert(precise->getNumOperands() == 1); |
| val = ConstMDToInt32(precise->getOperand(0)); |
| } |
| return val; |
| } |
| |
| void DxilMDHelper::MarkNonUniform(Instruction *I) { |
| LLVMContext &Ctx = I->getContext(); |
| MDNode *preciseNode = MDNode::get( |
| Ctx, |
| { ConstantAsMetadata::get(ConstantInt::get(Type::getInt32Ty(Ctx), 1)) }); |
| |
| I->setMetadata(DxilMDHelper::kDxilNonUniformAttributeMDName, preciseNode); |
| } |
| |
| bool DxilMDHelper::GetVariableDebugLayout(llvm::DbgDeclareInst *inst, |
| unsigned &StartOffsetInBits, std::vector<DxilDIArrayDim> &ArrayDims) { |
| llvm::MDTuple *Tuple = dyn_cast_or_null<MDTuple>(inst->getMetadata(DxilMDHelper::kDxilVariableDebugLayoutMDName)); |
| if (Tuple == nullptr) return false; |
| |
| IFTBOOL(Tuple->getNumOperands() % 2 == 1, DXC_E_INCORRECT_DXIL_METADATA); |
| |
| StartOffsetInBits = ConstMDToUint32(Tuple->getOperand(0)); |
| |
| for (unsigned Idx = 1; Idx < Tuple->getNumOperands(); Idx += 2) { |
| DxilDIArrayDim ArrayDim = {}; |
| ArrayDim.StrideInBits = ConstMDToUint32(Tuple->getOperand(Idx + 0)); |
| ArrayDim.NumElements = ConstMDToUint32(Tuple->getOperand(Idx + 1)); |
| ArrayDims.emplace_back(ArrayDim); |
| } |
| |
| return true; |
| } |
| |
| void DxilMDHelper::SetVariableDebugLayout(llvm::DbgDeclareInst *inst, |
| unsigned StartOffsetInBits, const std::vector<DxilDIArrayDim> &ArrayDims) { |
| LLVMContext &Ctx = inst->getContext(); |
| |
| std::vector<Metadata*> MDVals; |
| MDVals.reserve(ArrayDims.size() + 1); |
| MDVals.emplace_back(Uint32ToConstMD(StartOffsetInBits, Ctx)); |
| for (const DxilDIArrayDim &ArrayDim : ArrayDims) { |
| MDVals.emplace_back(Uint32ToConstMD(ArrayDim.StrideInBits, Ctx)); |
| MDVals.emplace_back(Uint32ToConstMD(ArrayDim.NumElements, Ctx)); |
| } |
| |
| inst->setMetadata(DxilMDHelper::kDxilVariableDebugLayoutMDName, MDNode::get(Ctx, MDVals)); |
| } |
| |
| void DxilMDHelper::CopyMetadata(Instruction &I, Instruction &SrcInst, ArrayRef<unsigned> WL) { |
| if (!SrcInst.hasMetadata()) |
| return; |
| |
| DenseSet<unsigned> WLS; |
| for (unsigned M : WL) |
| WLS.insert(M); |
| |
| // Otherwise, enumerate and copy over metadata from the old instruction to the |
| // new one. |
| SmallVector<std::pair<unsigned, MDNode *>, 4> TheMDs; |
| SrcInst.getAllMetadataOtherThanDebugLoc(TheMDs); |
| for (const auto &MD : TheMDs) { |
| if (WL.empty() || WLS.count(MD.first)) |
| I.setMetadata(MD.first, MD.second); |
| } |
| if (WL.empty() || WLS.count(LLVMContext::MD_dbg)) |
| I.setDebugLoc(SrcInst.getDebugLoc()); |
| } |
| |
| } // namespace hlsl |