blob: fdd6d6b94686ab28970adc7094f713f9118658e7 [file] [log] [blame] [edit]
///////////////////////////////////////////////////////////////////////////////
// //
// 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/DXIL/DxilMetadataHelper.h"
#include "dxc/DXIL/DxilCBuffer.h"
#include "dxc/DXIL/DxilCounters.h"
#include "dxc/DXIL/DxilFunctionProps.h"
#include "dxc/DXIL/DxilModule.h"
#include "dxc/DXIL/DxilOperations.h"
#include "dxc/DXIL/DxilResource.h"
#include "dxc/DXIL/DxilSampler.h"
#include "dxc/DXIL/DxilShaderFlags.h"
#include "dxc/DXIL/DxilShaderModel.h"
#include "dxc/DXIL/DxilSignature.h"
#include "dxc/DXIL/DxilSignatureElement.h"
#include "dxc/DXIL/DxilSubobject.h"
#include "dxc/DXIL/DxilTypeSystem.h"
#include "dxc/Support/Global.h"
#include "llvm/ADT/DenseSet.h"
#include "llvm/IR/Constants.h"
#include "llvm/IR/Function.h"
#include "llvm/IR/IRBuilder.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 <algorithm>
#include <array>
#include "dxc/Support/WinFunctions.h"
#include "dxc/Support/WinIncludes.h"
using namespace llvm;
using std::string;
using std::unique_ptr;
using std::vector;
namespace {
void LoadSerializedRootSignature(MDNode *pNode,
std::vector<uint8_t> &SerializedRootSignature,
LLVMContext &Ctx) {
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(Ctx),
DXC_E_INCORRECT_DXIL_METADATA);
SerializedRootSignature.assign(pData->getRawDataValues().begin(),
pData->getRawDataValues().end());
}
MDNode *
EmitSerializedRootSignature(const std::vector<uint8_t> &SerializedRootSignature,
LLVMContext &Ctx) {
if (SerializedRootSignature.empty())
return nullptr;
Constant *V = llvm::ConstantDataArray::get(
Ctx, llvm::ArrayRef<uint8_t>(SerializedRootSignature.data(),
SerializedRootSignature.size()));
return MDNode::get(Ctx, {ConstantAsMetadata::get(V)});
}
} // namespace
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::kDxilValidatorVersionMDName[] = "dx.valver";
const char DxilMDHelper::kDxilDxrPayloadAnnotationsMDName[] =
"dx.dxrPayloadAnnotations";
// 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";
const char DxilMDHelper::kDxilDxcBindingTableMDName[] = "dx.binding.table";
const char DxilMDHelper::kDxilSourceContentsOldMDName[] = "llvm.dbg.contents";
const char DxilMDHelper::kDxilSourceDefinesOldMDName[] = "llvm.dbg.defines";
const char DxilMDHelper::kDxilSourceMainFileNameOldMDName[] =
"llvm.dbg.mainFileName";
const char DxilMDHelper::kDxilSourceArgsOldMDName[] = "llvm.dbg.args";
// This is reflection-only metadata
const char DxilMDHelper::kDxilCountersMDName[] = "dx.counters";
static std::array<const char *, 8> DxilMDNames = {{
DxilMDHelper::kDxilVersionMDName,
DxilMDHelper::kDxilShaderModelMDName,
DxilMDHelper::kDxilEntryPointsMDName,
DxilMDHelper::kDxilResourcesMDName,
DxilMDHelper::kDxilTypeSystemMDName,
DxilMDHelper::kDxilValidatorVersionMDName,
DxilMDHelper::kDxilViewIdStateMDName,
DxilMDHelper::kDxilDxrPayloadAnnotationsMDName,
}};
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().str();
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().str();
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;
}
MDNode *Node = EmitSerializedRootSignature(SerializedRootSignature, m_Ctx);
NamedMDNode *pRootSignatureNamedMD =
m_pModule->getNamedMetadata(kDxilRootSignatureMDName);
IFTBOOL(pRootSignatureNamedMD == nullptr, DXC_E_INCORRECT_DXIL_METADATA);
pRootSignatureNamedMD =
m_pModule->getOrInsertNamedMetadata(kDxilRootSignatureMDName);
pRootSignatureNamedMD->addOperand(Node);
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);
LoadSerializedRootSignature(pNode, SerializedRootSignature, m_Ctx);
}
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());
Constant *GlobalSymbol = R.GetGlobalSymbol();
// For sm66+, global symbol will be mutated into handle type.
// Save hlsl type by generate bitcast on global symbol.
// For sm65-, global symbol will be undef value which saves the HLSLTy
// directly.
Type *HLSLTy = R.GetHLSLType();
if (HLSLTy && HLSLTy != GlobalSymbol->getType()) {
if (isa<UndefValue>(GlobalSymbol))
GlobalSymbol = UndefValue::get(HLSLTy);
else if (m_pSM->IsSM66Plus())
GlobalSymbol = cast<Constant>(
ConstantExpr::getCast(Instruction::BitCast, GlobalSymbol, HLSLTy));
}
ppMDVals[kDxilResourceBaseVariable] = ValueAsMetadata::get(GlobalSymbol);
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)));
Constant *GlobalSymbol = dyn_cast<Constant>(
ValueMDToValue(pTupleMD->getOperand(kDxilResourceBaseVariable)));
// For sm66+, global symbol will be mutated into handle type.
// Read hlsl type and global symbol from bitcast.
if (m_pSM->IsSM66Plus()) {
// Before mutate, there's no bitcast. After GlobalSymbol changed into undef,
// there's no bitcast too. Bitcast will only exist when global symbol is
// mutated into handle and not changed into undef for lib linking.
if (BitCastOperator *BCO = dyn_cast<BitCastOperator>(GlobalSymbol)) {
GlobalSymbol = cast<Constant>(BCO->getOperand(0));
R.SetHLSLType(BCO->getType());
}
}
R.SetGlobalSymbol(GlobalSymbol);
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);
TypeSystem.FinishStructAnnotation(*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);
TypeSystem.FinishFunctionAnnotation(*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);
}
}
void DxilMDHelper::EmitDxrPayloadAnnotations(DxilTypeSystem &TypeSystem) {
auto &TypeMap = TypeSystem.GetPayloadAnnotationMap();
vector<Metadata *> MDVals;
MDVals.emplace_back(Uint32ToConstMD(kDxilPayloadAnnotationStructTag)); // Tag
unsigned GVIdx = 0;
for (auto it = TypeMap.begin(); it != TypeMap.end(); ++it, GVIdx++) {
StructType *pStructType = const_cast<StructType *>(it->first);
DxilPayloadAnnotation *pA = it->second.get();
// Emit struct type field annotations.
Metadata *pMD = EmitDxrPayloadStructAnnotation(*pA);
MDVals.push_back(ValueAsMetadata::get(UndefValue::get(pStructType)));
MDVals.push_back(pMD);
}
NamedMDNode *pDxrPayloadAnnotationsMD =
m_pModule->getNamedMetadata(kDxilDxrPayloadAnnotationsMDName);
if (pDxrPayloadAnnotationsMD != nullptr) {
m_pModule->eraseNamedMetadata(pDxrPayloadAnnotationsMD);
}
if (MDVals.size() > 1) {
pDxrPayloadAnnotationsMD =
m_pModule->getOrInsertNamedMetadata(kDxilDxrPayloadAnnotationsMDName);
pDxrPayloadAnnotationsMD->addOperand(MDNode::get(m_Ctx, MDVals));
}
}
Metadata *
DxilMDHelper::EmitDxrPayloadStructAnnotation(const DxilPayloadAnnotation &SA) {
vector<Metadata *> MDVals;
MDVals.reserve(SA.GetNumFields());
MDVals.resize(SA.GetNumFields());
const StructType *STy = SA.GetStructType();
for (unsigned i = 0; i < SA.GetNumFields(); i++) {
MDVals[i] = EmitDxrPayloadFieldAnnotation(SA.GetFieldAnnotation(i),
STy->getElementType(i));
}
return MDNode::get(m_Ctx, MDVals);
}
void DxilMDHelper::LoadDxrPayloadAccessQualifiers(
const MDOperand &MDO, DxilPayloadFieldAnnotation &FA) {
unsigned fieldBitmask = ConstMDToInt32(MDO);
if (fieldBitmask & ~DXIL::PayloadAccessQualifierValidMask) {
DXASSERT(false, "Unknown payload access qualifier bits set");
m_bExtraMetadata = true;
}
fieldBitmask &= DXIL::PayloadAccessQualifierValidMask;
FA.SetPayloadFieldQualifierMask(fieldBitmask);
}
void DxilMDHelper::LoadDxrPayloadFieldAnnoation(
const MDOperand &MDO, DxilPayloadFieldAnnotation &FA) {
IFTBOOL(MDO.get() != nullptr, DXC_E_INCORRECT_DXIL_METADATA);
const MDTuple *pTupleMD = dyn_cast<MDTuple>(MDO.get()); // Tag-Value list.
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 kDxilPayloadFieldAnnotationAccessTag:
LoadDxrPayloadAccessQualifiers(MDO, FA);
break;
default:
DXASSERT(false, "Unknown payload field annotation tag");
m_bExtraMetadata = true;
break;
}
}
}
void DxilMDHelper::LoadDxrPayloadFieldAnnoations(const MDOperand &MDO,
DxilPayloadAnnotation &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);
IFTBOOL(pTupleMD->getNumOperands() == SA.GetNumFields(),
DXC_E_INCORRECT_DXIL_METADATA);
for (unsigned i = 0; i < SA.GetNumFields(); ++i) {
LoadDxrPayloadFieldAnnoation(pTupleMD->getOperand(i),
SA.GetFieldAnnotation(i));
}
}
void DxilMDHelper::LoadDxrPayloadAnnotationNode(const llvm::MDTuple &MDT,
DxilTypeSystem &TypeSystem) {
unsigned Tag = ConstMDToUint32(MDT.getOperand(0));
IFTBOOL(Tag == kDxilPayloadAnnotationStructTag, DXC_E_INCORRECT_DXIL_METADATA)
IFTBOOL((MDT.getNumOperands() & 0x1) == 1, DXC_E_INCORRECT_DXIL_METADATA);
Constant *pGV = dyn_cast<Constant>(ValueMDToValue(MDT.getOperand(1)));
IFTBOOL(pGV != nullptr, DXC_E_INCORRECT_DXIL_METADATA);
StructType *pGVType = dyn_cast<StructType>(pGV->getType());
IFTBOOL(pGVType != nullptr, DXC_E_INCORRECT_DXIL_METADATA);
// Check if this struct is already part of the DXIL Type System
DxilPayloadAnnotation *pPA = TypeSystem.AddPayloadAnnotation(pGVType);
LoadDxrPayloadFieldAnnoations(MDT.getOperand(2), *pPA);
}
void DxilMDHelper::LoadDxrPayloadAnnotations(DxilTypeSystem &TypeSystem) {
NamedMDNode *pDxilPayloadAnnotationsMD =
m_pModule->getNamedMetadata(kDxilDxrPayloadAnnotationsMDName);
if (pDxilPayloadAnnotationsMD == nullptr)
return;
if (DXIL::CompareVersions(m_MinValMajor, m_MinValMinor, 1, 6) < 0) {
DXASSERT(false, "payload access qualifier emitted for dxil version < 1.6");
m_bExtraMetadata = true;
}
DXASSERT(pDxilPayloadAnnotationsMD->getNumOperands() != 0,
"empty metadata node?");
for (unsigned i = 0; i < pDxilPayloadAnnotationsMD->getNumOperands(); i++) {
const MDTuple *pTupleMD =
dyn_cast<MDTuple>(pDxilPayloadAnnotationsMD->getOperand(i));
IFTBOOL(pTupleMD != nullptr, DXC_E_INCORRECT_DXIL_METADATA);
LoadDxrPayloadAnnotationNode(*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));
}
if (FA.HasResourceProperties() &&
DXIL::CompareVersions(m_MinValMajor, m_MinValMinor, 1, 8) >= 0) {
MDVals.emplace_back(Uint32ToConstMD(kDxilFieldAnnotationResPropTag));
MDVals.emplace_back(ValueAsMetadata::get(resource_helper::getAsConstant(
FA.GetResourceProperties(),
m_pModule->GetDxilModule().GetOP()->GetResourcePropertiesType(),
*m_pSM)));
}
if (DXIL::CompareVersions(m_MinValMajor, m_MinValMinor, 1, 7) >= 0) {
if (FA.HasBitFields()) {
const std::vector<DxilFieldAnnotation> &BitFields = FA.GetBitFields();
vector<Metadata *> MDBitFieldVals;
for (const DxilFieldAnnotation &BitField : BitFields) {
MDBitFieldVals.emplace_back(EmitDxilFieldAnnotation(BitField));
}
auto *BitFieldsMD = MDNode::get(m_Ctx, MDBitFieldVals);
MDVals.emplace_back(Uint32ToConstMD(kDxilFieldAnnotationBitFieldsTag));
MDVals.emplace_back(BitFieldsMD);
}
if (FA.HasBitFieldWidth()) {
MDVals.emplace_back(
Uint32ToConstMD(kDxilFieldAnnotationBitFieldWidthTag));
MDVals.emplace_back(Uint32ToConstMD(FA.GetBitFieldWidth()));
}
}
if (FA.GetVectorSize() &&
DXIL::CompareVersions(m_MinValMajor, m_MinValMinor, 1, 8) >= 0) {
MDVals.emplace_back(Uint32ToConstMD(kDxilFieldAnnotationVectorSizeTag));
MDVals.emplace_back(Uint32ToConstMD(FA.GetVectorSize()));
}
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;
case kDxilFieldAnnotationResPropTag:
if (Constant *C = dyn_cast_or_null<Constant>(
dyn_cast<ValueAsMetadata>(MDO)->getValue()))
FA.SetResourceProperties(resource_helper::loadPropsFromConstant(*C));
break;
case kDxilFieldAnnotationBitFieldsTag: {
if (DXIL::CompareVersions(m_MinValMajor, m_MinValMinor, 1, 7) < 0) {
DXASSERT(false, "bitfields tag emitted for dxil version < 1.7");
}
const MDTuple *pBitFieldsTupleMD = dyn_cast<MDTuple>(MDO.get());
std::vector<DxilFieldAnnotation> BitFields(
pBitFieldsTupleMD->getNumOperands());
for (unsigned i = 0; i < pBitFieldsTupleMD->getNumOperands(); ++i) {
LoadDxilFieldAnnotation(pBitFieldsTupleMD->getOperand(i), BitFields[i]);
}
FA.SetBitFields(BitFields);
} break;
case kDxilFieldAnnotationBitFieldWidthTag:
if (DXIL::CompareVersions(m_MinValMajor, m_MinValMinor, 1, 7) < 0) {
DXASSERT(false, "bitfields width tag emitted for dxil version < 1.7");
}
FA.SetBitFieldWidth(ConstMDToUint32(MDO));
break;
case kDxilFieldAnnotationVectorSizeTag:
FA.SetVectorSize(ConstMDToUint32(MDO));
break;
default:
DXASSERT(false, "Unknown extended shader properties tag");
m_bExtraMetadata = true;
break;
}
}
}
Metadata *DxilMDHelper::EmitDxrPayloadFieldAnnotation(
const DxilPayloadFieldAnnotation &FA, Type *fieldType) {
vector<Metadata *> MDVals; // Tag-Value list.
MDVals.emplace_back(Uint32ToConstMD(kDxilPayloadFieldAnnotationAccessTag));
auto mask = FA.GetPayloadFieldQualifierMask();
MDVals.emplace_back(Uint32ToConstMD(mask));
return MDNode::get(m_Ctx, MDVals);
}
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++)));
auto DeserializeNumThreads = [&]() {
props->numThreads[0] = ConstMDToUint32(pProps->getOperand(idx++));
props->numThreads[1] = ConstMDToUint32(pProps->getOperand(idx++));
props->numThreads[2] = ConstMDToUint32(pProps->getOperand(idx++));
};
bool bRayAttributes = false;
props->shaderKind = shaderKind;
switch (shaderKind) {
case DXIL::ShaderKind::Compute:
DeserializeNumThreads();
if (props->IsNode())
DeserializeNodeProps(pProps, idx, props);
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;
LLVM_FALLTHROUGH;
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:
DeserializeNumThreads();
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:
DeserializeNumThreads();
props->ShaderProps.AS.payloadSizeInBytes =
ConstMDToUint32(pProps->getOperand(idx++));
break;
case DXIL::ShaderKind::Node:
DeserializeNumThreads();
// Node specific attributes
DeserializeNodeProps(pProps, idx, props);
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)));
}
if (props.IsNode())
EmitDxilNodeState(MDVals, props);
switch (props.shaderKind) {
// Compute shader.
case DXIL::ShaderKind::Compute: {
MDVals.emplace_back(Uint32ToConstMD(DxilMDHelper::kDxilNumThreadsTag));
vector<Metadata *> NumThreadVals;
NumThreadVals.emplace_back(Uint32ToConstMD(props.numThreads[0]));
NumThreadVals.emplace_back(Uint32ToConstMD(props.numThreads[1]));
NumThreadVals.emplace_back(Uint32ToConstMD(props.numThreads[2]));
MDVals.emplace_back(MDNode::get(m_Ctx, NumThreadVals));
if (props.WaveSize.IsDefined()) {
if (props.WaveSize.IsRange())
DXASSERT(DXIL::CompareVersions(m_MinValMajor, m_MinValMinor, 1, 8) >= 0,
"DXIL version must be > 1.8");
const hlsl::ShaderModel *SM = GetShaderModel();
MDVals.emplace_back(Uint32ToConstMD(
SM->IsSM68Plus() ? DxilMDHelper::kDxilRangedWaveSizeTag
: DxilMDHelper::kDxilWaveSizeTag));
SmallVector<Metadata *, 3> WaveSizeVal;
WaveSizeVal.emplace_back(Uint32ToConstMD(props.WaveSize.Min));
if (SM->IsSM68Plus()) {
WaveSizeVal.emplace_back(Uint32ToConstMD(props.WaveSize.Max));
WaveSizeVal.emplace_back(Uint32ToConstMD(props.WaveSize.Preferred));
}
MDVals.emplace_back(MDNode::get(m_Ctx, WaveSizeVal));
}
} 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(props.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(props.numThreads, AS.payloadSizeInBytes);
MDVals.emplace_back(pMDTuple);
} break;
case DXIL::ShaderKind::Node: {
// The Node specific properties have already been handled by
// EmitDxilNodeState function above. Here we emit the metadata for those
// Node shader attributes that are shared with other shader types (only CS
// for now)
MDVals.emplace_back(Uint32ToConstMD(DxilMDHelper::kDxilNumThreadsTag));
vector<Metadata *> NumThreadVals;
NumThreadVals.emplace_back(Uint32ToConstMD(props.numThreads[0]));
NumThreadVals.emplace_back(Uint32ToConstMD(props.numThreads[1]));
NumThreadVals.emplace_back(Uint32ToConstMD(props.numThreads[2]));
MDVals.emplace_back(MDNode::get(m_Ctx, NumThreadVals));
} 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 (!props.serializedRootSignature.empty() &&
DXIL::CompareVersions(m_MinValMajor, m_MinValMinor, 1, 6) > 0) {
MDVals.emplace_back(Uint32ToConstMD(DxilMDHelper::kDxilEntryRootSigTag));
MDVals.emplace_back(
EmitSerializedRootSignature(props.serializedRootSignature, m_Ctx));
}
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;
}
bool hasNodeTag = false;
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() || props.shaderKind == DXIL::ShaderKind::Node,
"else invalid shader kind");
MDNode *pNode = cast<MDNode>(MDO.get());
props.numThreads[0] = ConstMDToUint32(pNode->getOperand(0));
props.numThreads[1] = ConstMDToUint32(pNode->getOperand(1));
props.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, props.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, props.numThreads, AS.payloadSizeInBytes);
} break;
case DxilMDHelper::kDxilWaveSizeTag: {
MDNode *pNode = cast<MDNode>(MDO.get());
props.WaveSize.Min = ConstMDToUint32(pNode->getOperand(0));
} break;
case DxilMDHelper::kDxilRangedWaveSizeTag: {
// if we're here, we're using the range variant.
// Extra metadata is used if SM < 6.8
if (!m_pSM->IsSMAtLeast(6, 8))
m_bExtraMetadata = true;
MDNode *pNode = cast<MDNode>(MDO.get());
// TODO: Issue #6239 we need to validate that there are 3 integer
// parameters here, and emit a diagnostic if not.
DXASSERT(pNode->getNumOperands() == 3,
"else wavesize range tag has incorrect number of parameters");
props.WaveSize.Min = ConstMDToUint32(pNode->getOperand(0));
props.WaveSize.Max = ConstMDToUint32(pNode->getOperand(1));
props.WaveSize.Preferred = ConstMDToUint32(pNode->getOperand(2));
} break;
case DxilMDHelper::kDxilEntryRootSigTag: {
MDNode *pNode = cast<MDNode>(MDO.get());
LoadSerializedRootSignature(pNode, props.serializedRootSignature, m_Ctx);
} break;
case DxilMDHelper::kDxilNodeLaunchTypeTag: {
hasNodeTag = true;
auto &Node = props.Node;
Node.LaunchType = static_cast<DXIL::NodeLaunchType>(ConstMDToUint32(MDO));
} break;
case DxilMDHelper::kDxilNodeIsProgramEntryTag: {
hasNodeTag = true;
props.Node.IsProgramEntry = ConstMDToBool(MDO);
} break;
case DxilMDHelper::kDxilNodeIdTag: {
hasNodeTag = true;
MDNode *pNode = cast<MDNode>(MDO.get());
props.NodeShaderID.Name = StringMDToString(pNode->getOperand(0));
props.NodeShaderID.Index = ConstMDToUint32(pNode->getOperand(1));
} break;
case DxilMDHelper::kDxilNodeLocalRootArgumentsTableIndexTag: {
hasNodeTag = true;
auto &Node = props.Node;
Node.LocalRootArgumentsTableIndex = ConstMDToUint32(MDO);
} break;
case DxilMDHelper::kDxilShareInputOfTag: {
hasNodeTag = true;
MDNode *pNode = cast<MDNode>(MDO.get());
props.NodeShaderSharedInput.Name = StringMDToString(pNode->getOperand(0));
props.NodeShaderSharedInput.Index = ConstMDToUint32(pNode->getOperand(1));
} break;
case DxilMDHelper::kDxilNodeDispatchGridTag: {
hasNodeTag = true;
auto &Node = props.Node;
MDNode *pNode = cast<MDNode>(MDO.get());
Node.DispatchGrid[0] = ConstMDToUint32(pNode->getOperand(0));
Node.DispatchGrid[1] = ConstMDToUint32(pNode->getOperand(1));
Node.DispatchGrid[2] = ConstMDToUint32(pNode->getOperand(2));
} break;
case DxilMDHelper::kDxilNodeMaxDispatchGridTag: {
hasNodeTag = true;
auto &Node = props.Node;
MDNode *pNode = cast<MDNode>(MDO.get());
Node.MaxDispatchGrid[0] = ConstMDToUint32(pNode->getOperand(0));
Node.MaxDispatchGrid[1] = ConstMDToUint32(pNode->getOperand(1));
Node.MaxDispatchGrid[2] = ConstMDToUint32(pNode->getOperand(2));
} break;
case DxilMDHelper::kDxilNodeMaxRecursionDepthTag: {
hasNodeTag = true;
auto &Node = props.Node;
Node.MaxRecursionDepth = ConstMDToUint32(MDO);
} break;
case DxilMDHelper::kDxilNodeInputsTag: {
hasNodeTag = true;
const MDTuple *pNodeInputs = dyn_cast<MDTuple>(MDO.get());
IFTBOOL(pTupleMD != nullptr, DXC_E_INCORRECT_DXIL_METADATA);
for (unsigned i = 0; i != pNodeInputs->getNumOperands(); ++i) {
const MDOperand &NodeInput = pNodeInputs->getOperand(i);
IFTBOOL(NodeInput.get() != nullptr, DXC_E_INCORRECT_DXIL_METADATA);
props.InputNodes.push_back(LoadDxilNodeIOState(NodeInput));
}
} break;
case DxilMDHelper::kDxilNodeOutputsTag: {
hasNodeTag = true;
const MDTuple *pNodeOutputs = dyn_cast<MDTuple>(MDO.get());
IFTBOOL(pTupleMD != nullptr, DXC_E_INCORRECT_DXIL_METADATA);
for (unsigned i = 0; i != pNodeOutputs->getNumOperands(); ++i) {
const MDOperand &NodeOutput = pNodeOutputs->getOperand(i);
IFTBOOL(NodeOutput.get() != nullptr, DXC_E_INCORRECT_DXIL_METADATA);
props.OutputNodes.push_back(LoadDxilNodeIOState(NodeOutput));
}
} break;
default:
DXASSERT(false, "Unknown extended shader properties tag");
m_bExtraMetadata = true;
break;
}
}
DXASSERT(!hasNodeTag ||
props.Node.LaunchType != DXIL::NodeLaunchType::Invalid,
"else invalid shader kind");
if (bEarlyDepth) {
DXASSERT(props.IsPS(), "else invalid shader kind");
props.ShaderProps.PS.EarlyDepthStencil = true;
}
}
void DxilMDHelper::SerializeNodeProps(SmallVectorImpl<llvm::Metadata *> &MDVals,
unsigned &valIdx,
const hlsl::DxilFunctionProps *props) {
auto &NodeProps = props->Node;
MDVals.push_back(
Uint32ToConstMD(static_cast<unsigned>((NodeProps.LaunchType))));
MDVals.push_back(BoolToConstMD(NodeProps.IsProgramEntry));
MDVals.push_back(MDString::get(m_Ctx, props->NodeShaderID.Name));
MDVals.push_back(Uint32ToConstMD(props->NodeShaderID.Index));
MDVals.push_back(MDString::get(m_Ctx, props->NodeShaderSharedInput.Name));
MDVals.push_back(Uint32ToConstMD(props->NodeShaderSharedInput.Index));
MDVals.push_back(Uint32ToConstMD(NodeProps.LocalRootArgumentsTableIndex));
MDVals.push_back(Uint32ToConstMD(NodeProps.DispatchGrid[0]));
MDVals.push_back(Uint32ToConstMD(NodeProps.DispatchGrid[1]));
MDVals.push_back(Uint32ToConstMD(NodeProps.DispatchGrid[2]));
MDVals.push_back(Uint32ToConstMD(NodeProps.MaxDispatchGrid[0]));
MDVals.push_back(Uint32ToConstMD(NodeProps.MaxDispatchGrid[1]));
MDVals.push_back(Uint32ToConstMD(NodeProps.MaxDispatchGrid[2]));
MDVals.push_back(Uint32ToConstMD(NodeProps.MaxRecursionDepth));
for (auto &nodeinput : props->InputNodes) {
MDVals.push_back(Uint32ToConstMD(nodeinput.Flags));
MDVals.push_back(Uint32ToConstMD(nodeinput.MaxRecords));
MDVals.push_back(Uint32ToConstMD(nodeinput.RecordType.size));
MDVals.push_back(
Uint32ToConstMD(nodeinput.RecordType.SV_DispatchGrid.ByteOffset));
MDVals.push_back(Uint32ToConstMD(static_cast<unsigned>(
nodeinput.RecordType.SV_DispatchGrid.ComponentType)));
MDVals.push_back(
Uint32ToConstMD(nodeinput.RecordType.SV_DispatchGrid.NumComponents));
MDVals.push_back(Uint32ToConstMD(nodeinput.RecordType.alignment));
}
for (auto &nodeoutput : props->OutputNodes) {
MDVals.push_back(Uint32ToConstMD(nodeoutput.Flags));
MDVals.push_back(Uint32ToConstMD(nodeoutput.RecordType.size));
MDVals.push_back(
Uint32ToConstMD(nodeoutput.RecordType.SV_DispatchGrid.ByteOffset));
MDVals.push_back(Uint32ToConstMD(static_cast<unsigned>(
nodeoutput.RecordType.SV_DispatchGrid.ComponentType)));
MDVals.push_back(
Uint32ToConstMD(nodeoutput.RecordType.SV_DispatchGrid.NumComponents));
MDVals.push_back(MDString::get(m_Ctx, nodeoutput.OutputID.Name));
MDVals.push_back(Uint32ToConstMD(nodeoutput.OutputID.Index));
MDVals.push_back(Uint32ToConstMD(nodeoutput.MaxRecords));
MDVals.push_back(Int32ToConstMD(nodeoutput.MaxRecordsSharedWith));
MDVals.push_back(Uint32ToConstMD(nodeoutput.OutputArraySize));
MDVals.push_back(BoolToConstMD(nodeoutput.AllowSparseNodes));
MDVals.push_back(Uint32ToConstMD(nodeoutput.RecordType.alignment));
}
}
void DxilMDHelper::DeserializeNodeProps(const MDTuple *pProps, unsigned &idx,
hlsl::DxilFunctionProps *props) {
auto &NodeProps = props->Node;
NodeProps.LaunchType = static_cast<DXIL::NodeLaunchType>(
ConstMDToUint32(pProps->getOperand(idx++)));
NodeProps.IsProgramEntry = ConstMDToBool(pProps->getOperand(idx++));
props->NodeShaderID.Name = StringMDToString(pProps->getOperand(idx++));
props->NodeShaderID.Index = ConstMDToUint32(pProps->getOperand(idx++));
props->NodeShaderSharedInput.Name =
StringMDToString(pProps->getOperand(idx++));
props->NodeShaderSharedInput.Index =
ConstMDToUint32(pProps->getOperand(idx++));
NodeProps.LocalRootArgumentsTableIndex =
ConstMDToUint32(pProps->getOperand(idx++));
NodeProps.DispatchGrid[0] = ConstMDToUint32(pProps->getOperand(idx++));
NodeProps.DispatchGrid[1] = ConstMDToUint32(pProps->getOperand(idx++));
NodeProps.DispatchGrid[2] = ConstMDToUint32(pProps->getOperand(idx++));
NodeProps.MaxDispatchGrid[0] = ConstMDToUint32(pProps->getOperand(idx++));
NodeProps.MaxDispatchGrid[1] = ConstMDToUint32(pProps->getOperand(idx++));
NodeProps.MaxDispatchGrid[2] = ConstMDToUint32(pProps->getOperand(idx++));
NodeProps.MaxRecursionDepth = ConstMDToUint32(pProps->getOperand(idx++));
for (auto &nodeinput : props->InputNodes) {
nodeinput.Flags = NodeFlags(ConstMDToUint32(pProps->getOperand(idx++)));
nodeinput.MaxRecords = ConstMDToUint32(pProps->getOperand(idx++));
nodeinput.RecordType.size = ConstMDToUint32(pProps->getOperand(idx++));
nodeinput.RecordType.SV_DispatchGrid.ByteOffset =
ConstMDToUint32(pProps->getOperand(idx++));
nodeinput.RecordType.SV_DispatchGrid.ComponentType =
static_cast<DXIL::ComponentType>(
ConstMDToUint32(pProps->getOperand(idx++)));
nodeinput.RecordType.SV_DispatchGrid.NumComponents =
ConstMDToUint32(pProps->getOperand(idx++));
if (pProps->getNumOperands() > idx) {
nodeinput.RecordType.alignment =
ConstMDToUint32(pProps->getOperand(idx++));
}
}
for (auto &nodeoutput : props->OutputNodes) {
nodeoutput.Flags = NodeFlags(ConstMDToUint32(pProps->getOperand(idx++)));
nodeoutput.RecordType.size = ConstMDToUint32(pProps->getOperand(idx++));
nodeoutput.RecordType.SV_DispatchGrid.ByteOffset =
ConstMDToUint32(pProps->getOperand(idx++));
nodeoutput.RecordType.SV_DispatchGrid.ComponentType =
static_cast<DXIL::ComponentType>(
ConstMDToUint32(pProps->getOperand(idx++)));
nodeoutput.RecordType.SV_DispatchGrid.NumComponents =
ConstMDToUint32(pProps->getOperand(idx++));
nodeoutput.OutputID.Name = StringMDToString(pProps->getOperand(idx++));
nodeoutput.OutputID.Index = ConstMDToUint32(pProps->getOperand(idx++));
nodeoutput.MaxRecords = ConstMDToUint32(pProps->getOperand(idx++));
nodeoutput.MaxRecordsSharedWith = ConstMDToInt32(pProps->getOperand(idx++));
nodeoutput.OutputArraySize = ConstMDToUint32(pProps->getOperand(idx++));
nodeoutput.AllowSparseNodes = ConstMDToBool(pProps->getOperand(idx++));
if (pProps->getNumOperands() > idx) {
nodeoutput.RecordType.alignment =
ConstMDToUint32(pProps->getOperand(idx++));
}
}
}
MDTuple *
DxilMDHelper::EmitDxilFunctionProps(const hlsl::DxilFunctionProps *props,
const Function *F) {
bool bRayAttributes = false;
SmallVector<Metadata *, 35> MDVals;
auto SerializeNumThreads = [&]() {
MDVals.push_back(Uint32ToConstMD(props->numThreads[0]));
MDVals.push_back(Uint32ToConstMD(props->numThreads[1]));
MDVals.push_back(Uint32ToConstMD(props->numThreads[2]));
};
unsigned valIdx = 0;
MDVals.push_back(ValueAsMetadata::get(const_cast<Function *>(F)));
MDVals.push_back(Uint32ToConstMD(static_cast<unsigned>(props->shaderKind)));
switch (props->shaderKind) {
case DXIL::ShaderKind::Compute:
SerializeNumThreads();
if (props->IsNode())
SerializeNodeProps(MDVals, valIdx, props);
break;
case DXIL::ShaderKind::Geometry:
MDVals.push_back(
Uint8ToConstMD((uint8_t)props->ShaderProps.GS.inputPrimitive));
MDVals.push_back(Uint32ToConstMD(props->ShaderProps.GS.maxVertexCount));
MDVals.push_back(Uint32ToConstMD(props->ShaderProps.GS.instanceCount));
for (size_t i = 0;
i < _countof(props->ShaderProps.GS.streamPrimitiveTopologies); ++i)
MDVals.push_back(Uint8ToConstMD(
(uint8_t)props->ShaderProps.GS.streamPrimitiveTopologies[i]));
break;
case DXIL::ShaderKind::Hull:
MDVals.push_back(
ValueAsMetadata::get(props->ShaderProps.HS.patchConstantFunc));
MDVals.push_back(Uint8ToConstMD((uint8_t)props->ShaderProps.HS.domain));
MDVals.push_back(Uint8ToConstMD((uint8_t)props->ShaderProps.HS.partition));
MDVals.push_back(
Uint8ToConstMD((uint8_t)props->ShaderProps.HS.outputPrimitive));
MDVals.push_back(Uint32ToConstMD(props->ShaderProps.HS.inputControlPoints));
MDVals.push_back(
Uint32ToConstMD(props->ShaderProps.HS.outputControlPoints));
MDVals.push_back(FloatToConstMD(props->ShaderProps.HS.maxTessFactor));
break;
case DXIL::ShaderKind::Domain:
MDVals.push_back(Uint8ToConstMD((uint8_t)props->ShaderProps.DS.domain));
MDVals.push_back(Uint32ToConstMD(props->ShaderProps.DS.inputControlPoints));
break;
case DXIL::ShaderKind::Pixel:
MDVals.push_back(BoolToConstMD(props->ShaderProps.PS.EarlyDepthStencil));
break;
case DXIL::ShaderKind::AnyHit:
case DXIL::ShaderKind::ClosestHit:
bRayAttributes = true;
LLVM_FALLTHROUGH;
case DXIL::ShaderKind::Miss:
case DXIL::ShaderKind::Callable:
// payload/params unioned and first:
MDVals.push_back(
Uint32ToConstMD(props->ShaderProps.Ray.payloadSizeInBytes));
if (bRayAttributes)
MDVals.push_back(
Uint32ToConstMD(props->ShaderProps.Ray.attributeSizeInBytes));
break;
case DXIL::ShaderKind::Mesh:
SerializeNumThreads();
MDVals.push_back(Uint32ToConstMD(props->ShaderProps.MS.maxVertexCount));
MDVals.push_back(Uint32ToConstMD(props->ShaderProps.MS.maxPrimitiveCount));
MDVals.push_back(
Uint8ToConstMD((uint8_t)props->ShaderProps.MS.outputTopology));
MDVals.push_back(Uint32ToConstMD(props->ShaderProps.MS.payloadSizeInBytes));
break;
case DXIL::ShaderKind::Amplification:
SerializeNumThreads();
MDVals.push_back(Uint32ToConstMD(props->ShaderProps.AS.payloadSizeInBytes));
break;
case DXIL::ShaderKind::Node:
SerializeNumThreads();
// Node specific properties
SerializeNodeProps(MDVals, valIdx, props);
break;
default:
break;
}
return MDTuple::get(m_Ctx,
ArrayRef<llvm::Metadata *>(MDVals.data(), MDVals.size()));
}
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;
LLVM_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, AnyHit, ClosestHit, Intersection),
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;
LLVM_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;
}
//
// 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));
}
void DxilMDHelper::EmitDxilNodeState(std::vector<llvm::Metadata *> &MDVals,
const DxilFunctionProps &props) {
auto &Node = props.Node;
// Required Fields
MDVals.emplace_back(Uint32ToConstMD(DxilMDHelper::kDxilNodeLaunchTypeTag));
MDVals.emplace_back(Uint32ToConstMD(static_cast<unsigned>(Node.LaunchType)));
// Optional Fields
if (props.WaveSize.IsDefined()) {
const hlsl::ShaderModel *SM = GetShaderModel();
MDVals.emplace_back(
Uint32ToConstMD(SM->IsSM68Plus() ? DxilMDHelper::kDxilRangedWaveSizeTag
: DxilMDHelper::kDxilWaveSizeTag));
SmallVector<Metadata *, 3> WaveSizeVal;
WaveSizeVal.emplace_back(Uint32ToConstMD(props.WaveSize.Min));
if (SM->IsSM68Plus()) {
WaveSizeVal.emplace_back(Uint32ToConstMD(props.WaveSize.Max));
WaveSizeVal.emplace_back(Uint32ToConstMD(props.WaveSize.Preferred));
}
MDVals.emplace_back(MDNode::get(m_Ctx, WaveSizeVal));
}
if (Node.IsProgramEntry) {
MDVals.emplace_back(
Uint32ToConstMD(DxilMDHelper::kDxilNodeIsProgramEntryTag));
MDVals.emplace_back(BoolToConstMD(true));
}
if (!props.NodeShaderID.Name.empty()) {
MDVals.emplace_back(Uint32ToConstMD(kDxilNodeIdTag));
vector<Metadata *> NodeIDVals;
NodeIDVals.emplace_back(MDString::get(m_Ctx, props.NodeShaderID.Name));
NodeIDVals.emplace_back(Uint32ToConstMD(props.NodeShaderID.Index));
MDVals.emplace_back(MDNode::get(m_Ctx, NodeIDVals));
}
MDVals.emplace_back(
Uint32ToConstMD(DxilMDHelper::kDxilNodeLocalRootArgumentsTableIndexTag));
MDVals.emplace_back(Uint32ToConstMD(Node.LocalRootArgumentsTableIndex));
if (!props.NodeShaderSharedInput.Name.empty()) {
MDVals.emplace_back(Uint32ToConstMD(kDxilShareInputOfTag));
vector<Metadata *> NodeIDVals;
NodeIDVals.emplace_back(
MDString::get(m_Ctx, props.NodeShaderSharedInput.Name));
NodeIDVals.emplace_back(Uint32ToConstMD(props.NodeShaderSharedInput.Index));
MDVals.emplace_back(MDNode::get(m_Ctx, NodeIDVals));
}
if (Node.DispatchGrid[0] || Node.DispatchGrid[1] || Node.DispatchGrid[2]) {
MDVals.emplace_back(
Uint32ToConstMD(DxilMDHelper::kDxilNodeDispatchGridTag));
vector<Metadata *> DispatchGridVals;
DispatchGridVals.emplace_back(Uint32ToConstMD(Node.DispatchGrid[0]));
DispatchGridVals.emplace_back(Uint32ToConstMD(Node.DispatchGrid[1]));
DispatchGridVals.emplace_back(Uint32ToConstMD(Node.DispatchGrid[2]));
MDVals.emplace_back(MDNode::get(m_Ctx, DispatchGridVals));
}
if (Node.MaxDispatchGrid[0] || Node.MaxDispatchGrid[1] ||
Node.MaxDispatchGrid[2]) {
MDVals.emplace_back(
Uint32ToConstMD(DxilMDHelper::kDxilNodeMaxDispatchGridTag));
vector<Metadata *> MaxDispatchGridVals;
MaxDispatchGridVals.emplace_back(Uint32ToConstMD(Node.MaxDispatchGrid[0]));
MaxDispatchGridVals.emplace_back(Uint32ToConstMD(Node.MaxDispatchGrid[1]));
MaxDispatchGridVals.emplace_back(Uint32ToConstMD(Node.MaxDispatchGrid[2]));
MDVals.emplace_back(MDNode::get(m_Ctx, MaxDispatchGridVals));
}
if (Node.MaxRecursionDepth) {
MDVals.emplace_back(
Uint32ToConstMD(DxilMDHelper::kDxilNodeMaxRecursionDepthTag));
MDVals.emplace_back(Uint32ToConstMD(Node.MaxRecursionDepth));
}
if (props.InputNodes.size()) {
MDVals.emplace_back(Uint32ToConstMD(DxilMDHelper::kDxilNodeInputsTag));
vector<Metadata *> NodeInputVals;
for (auto &InputNode : props.InputNodes)
NodeInputVals.emplace_back(EmitDxilNodeIOState(InputNode));
MDVals.emplace_back(MDNode::get(m_Ctx, NodeInputVals));
}
if (props.OutputNodes.size()) {
MDVals.emplace_back(Uint32ToConstMD(DxilMDHelper::kDxilNodeOutputsTag));
vector<Metadata *> NodeOutputVals;
for (auto &OutputNode : props.OutputNodes)
NodeOutputVals.emplace_back(EmitDxilNodeIOState(OutputNode));
MDVals.emplace_back(MDNode::get(m_Ctx, NodeOutputVals));
}
}
llvm::MDTuple *
DxilMDHelper::EmitDxilNodeRecordType(const NodeRecordType &RecordType) {
vector<Metadata *> MDVals;
MDVals.emplace_back(Uint32ToConstMD(DxilMDHelper::kDxilNodeRecordSizeTag));
MDVals.emplace_back(Uint32ToConstMD(RecordType.size));
if (RecordType.SV_DispatchGrid.NumComponents) {
MDVals.emplace_back(
Uint32ToConstMD(DxilMDHelper::kDxilNodeSVDispatchGridTag));
vector<Metadata *> SVDispatchGridVals;
SVDispatchGridVals.emplace_back(
Uint32ToConstMD(RecordType.SV_DispatchGrid.ByteOffset));
SVDispatchGridVals.emplace_back(Uint32ToConstMD(
static_cast<unsigned>(RecordType.SV_DispatchGrid.ComponentType)));
SVDispatchGridVals.emplace_back(
Uint32ToConstMD(RecordType.SV_DispatchGrid.NumComponents));
MDVals.emplace_back(MDNode::get(m_Ctx, SVDispatchGridVals));
}
if (RecordType.alignment) {
MDVals.emplace_back(
Uint32ToConstMD(DxilMDHelper::kDxilNodeRecordAlignmentTag));
MDVals.emplace_back(Uint32ToConstMD(RecordType.alignment));
}
return MDNode::get(m_Ctx, MDVals);
}
llvm::MDTuple *
DxilMDHelper::EmitDxilNodeIOState(const hlsl::NodeIOProperties &Node) {
vector<Metadata *> MDVals;
MDVals.emplace_back(Uint32ToConstMD(DxilMDHelper::kDxilNodeIOFlagsTag));
MDVals.emplace_back(Uint32ToConstMD(Node.Flags));
if (Node.RecordType.size) {
MDVals.emplace_back(Uint32ToConstMD(DxilMDHelper::kDxilNodeRecordTypeTag));
MDVals.emplace_back(EmitDxilNodeRecordType(Node.RecordType));
}
if (Node.Flags.IsOutputNode()) {
// Required Field
MDVals.emplace_back(Uint32ToConstMD(DxilMDHelper::kDxilNodeMaxRecordsTag));
MDVals.emplace_back(Uint32ToConstMD(Node.MaxRecords));
if (Node.OutputArraySize) {
MDVals.emplace_back(
Uint32ToConstMD(DxilMDHelper::kDxilNodeOutputArraySizeTag));
MDVals.emplace_back(Uint32ToConstMD(Node.OutputArraySize));
}
if (Node.MaxRecordsSharedWith >= 0) {
MDVals.emplace_back(
Uint32ToConstMD(DxilMDHelper::kDxilNodeMaxRecordsSharedWithTag));
MDVals.emplace_back(Int32ToConstMD(Node.MaxRecordsSharedWith));
}
if (Node.AllowSparseNodes) {
MDVals.emplace_back(
Uint32ToConstMD(DxilMDHelper::kDxilNodeAllowSparseNodesTag));
MDVals.emplace_back(BoolToConstMD((uint32_t)Node.AllowSparseNodes));
}
if (!Node.OutputID.Name.empty()) {
MDVals.emplace_back(Uint32ToConstMD(kDxilNodeOutputIDTag));
vector<Metadata *> NodeOpIDVals;
NodeOpIDVals.emplace_back(MDString::get(m_Ctx, Node.OutputID.Name));
NodeOpIDVals.emplace_back(Uint32ToConstMD(Node.OutputID.Index));
MDVals.emplace_back(MDNode::get(m_Ctx, NodeOpIDVals));
}
} else {
DXASSERT(Node.Flags.IsInputRecord(), "Invalid NodeIO Kind");
if (Node.MaxRecords) {
MDVals.emplace_back(
Uint32ToConstMD(DxilMDHelper::kDxilNodeMaxRecordsTag));
MDVals.emplace_back(Uint32ToConstMD(Node.MaxRecords));
}
}
return MDNode::get(m_Ctx, MDVals);
}
NodeRecordType
DxilMDHelper::LoadDxilNodeRecordType(const llvm::MDOperand &MDO) {
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);
NodeRecordType Record = {};
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::kDxilNodeRecordSizeTag: {
Record.size = ConstMDToUint32(MDO);
} break;
case DxilMDHelper::kDxilNodeSVDispatchGridTag: {
MDTuple *pSVDTupleMD = cast<MDTuple>(MDO.get());
// < 3 if fatal
IFTBOOL(pSVDTupleMD->getNumOperands() >= 3,
DXC_E_INCORRECT_DXIL_METADATA);
// > 3 is extra metadata, validator will fail.
if (pSVDTupleMD->getNumOperands() > 3)
m_bExtraMetadata = true;
Record.SV_DispatchGrid.ByteOffset =
ConstMDToUint32(pSVDTupleMD->getOperand(0));
Record.SV_DispatchGrid.ComponentType = static_cast<DXIL::ComponentType>(
ConstMDToUint32(pSVDTupleMD->getOperand(1)));
Record.SV_DispatchGrid.NumComponents =
ConstMDToUint32(pSVDTupleMD->getOperand(2));
} break;
case DxilMDHelper::kDxilNodeRecordAlignmentTag: {
Record.alignment = ConstMDToUint32(MDO);
} break;
default:
m_bExtraMetadata = true;
break;
}
}
return Record;
}
NodeIOProperties DxilMDHelper::LoadDxilNodeIOState(const llvm::MDOperand &MDO) {
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);
NodeIOProperties Node = {};
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::kDxilNodeIOFlagsTag: {
Node.Flags = NodeFlags(ConstMDToUint32(MDO));
} break;
case DxilMDHelper::kDxilNodeRecordTypeTag: {
Node.RecordType = LoadDxilNodeRecordType(MDO);
} break;
case DxilMDHelper::kDxilNodeOutputArraySizeTag: {
Node.OutputArraySize = ConstMDToUint32(MDO);
} break;
case DxilMDHelper::kDxilNodeMaxRecordsTag: {
Node.MaxRecords = ConstMDToUint32(MDO);
} break;
case DxilMDHelper::kDxilNodeMaxRecordsSharedWithTag: {
Node.MaxRecordsSharedWith = ConstMDToInt32(MDO);
} break;
case DxilMDHelper::kDxilNodeAllowSparseNodesTag: {
Node.AllowSparseNodes = ConstMDToBool(MDO);
} break;
case DxilMDHelper::kDxilNodeOutputIDTag: {
MDNode *pNode = cast<MDNode>(MDO.get());
Node.OutputID.Name = StringMDToString(pNode->getOperand(0));
Node.OutputID.Index = ConstMDToUint32(pNode->getOperand(1));
} break;
default:
m_bExtraMetadata = true;
break;
}
}
return Node;
}
void DxilMDHelper::AddCounterIfNonZero(uint32_t value, StringRef name,
vector<Metadata *> &MDVals) {
if (value) {
MDVals.emplace_back(MDString::get(m_Ctx, name));
MDVals.emplace_back(Uint32ToConstMD(value));
}
}
void DxilMDHelper::EmitDxilCounters(const DxilCounters &counters) {
NamedMDNode *pDxilCountersMD =
m_pModule->getNamedMetadata(kDxilCountersMDName);
if (pDxilCountersMD)
m_pModule->eraseNamedMetadata(pDxilCountersMD);
vector<Metadata *> MDVals;
// clang-format off
// Python lines need to be not formatted.
// <py::lines('OPCODE-COUNTERS')>['AddCounterIfNonZero(counters.%s, "%s", MDVals);' % (c,c) for c in hctdb_instrhelp.get_counters()]</py>
// clang-format on
// OPCODE-COUNTERS:BEGIN
AddCounterIfNonZero(counters.array_local_bytes, "array_local_bytes", MDVals);
AddCounterIfNonZero(counters.array_local_ldst, "array_local_ldst", MDVals);
AddCounterIfNonZero(counters.array_static_bytes, "array_static_bytes",
MDVals);
AddCounterIfNonZero(counters.array_static_ldst, "array_static_ldst", MDVals);
AddCounterIfNonZero(counters.array_tgsm_bytes, "array_tgsm_bytes", MDVals);
AddCounterIfNonZero(counters.array_tgsm_ldst, "array_tgsm_ldst", MDVals);
AddCounterIfNonZero(counters.atomic, "atomic", MDVals);
AddCounterIfNonZero(counters.barrier, "barrier", MDVals);
AddCounterIfNonZero(counters.branches, "branches", MDVals);
AddCounterIfNonZero(counters.fence, "fence", MDVals);
AddCounterIfNonZero(counters.floats, "floats", MDVals);
AddCounterIfNonZero(counters.gs_cut, "gs_cut", MDVals);
AddCounterIfNonZero(counters.gs_emit, "gs_emit", MDVals);
AddCounterIfNonZero(counters.insts, "insts", MDVals);
AddCounterIfNonZero(counters.ints, "ints", MDVals);
AddCounterIfNonZero(counters.sig_ld, "sig_ld", MDVals);
AddCounterIfNonZero(counters.sig_st, "sig_st", MDVals);
AddCounterIfNonZero(counters.tex_bias, "tex_bias", MDVals);
AddCounterIfNonZero(counters.tex_cmp, "tex_cmp", MDVals);
AddCounterIfNonZero(counters.tex_grad, "tex_grad", MDVals);
AddCounterIfNonZero(counters.tex_load, "tex_load", MDVals);
AddCounterIfNonZero(counters.tex_norm, "tex_norm", MDVals);
AddCounterIfNonZero(counters.tex_store, "tex_store", MDVals);
AddCounterIfNonZero(counters.uints, "uints", MDVals);
// OPCODE-COUNTERS:END
if (MDVals.size()) {
pDxilCountersMD = m_pModule->getOrInsertNamedMetadata(kDxilCountersMDName);
pDxilCountersMD->addOperand(MDNode::get(m_Ctx, MDVals));
}
}
void DxilMDHelper::LoadCounterMD(const MDOperand &MDName,
const MDOperand &MDValue,
DxilCounters &counters) const {
StringRef name = StringMDToStringRef(MDName);
uint32_t value = ConstMDToUint32(MDValue);
uint32_t *counter = LookupByName(name, counters);
if (counter)
*counter = value;
}
void DxilMDHelper::LoadDxilCounters(DxilCounters &counters) const {
ZeroMemory(&counters, sizeof(counters));
if (NamedMDNode *pDxilCountersMD =
m_pModule->getNamedMetadata(kDxilCountersMDName)) {
MDNode *pMDCounters = pDxilCountersMD->getOperand(0);
for (unsigned i = 0; i < pMDCounters->getNumOperands(); i += 2) {
LoadCounterMD(pMDCounters->getOperand(i), pMDCounters->getOperand(i + 1),
counters);
}
}
}
//
// 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));
}
// Whether resource is used for 64-bit atomic op
if (DXIL::CompareVersions(m_ValMajor, m_ValMinor, 1, 6) >= 0 &&
UAV.HasAtomic64Use()) {
MDVals.emplace_back(DxilMDHelper::Uint32ToConstMD(
DxilMDHelper::kDxilAtomic64UseTag, m_Ctx));
MDVals.emplace_back(DxilMDHelper::Uint32ToConstMD((unsigned)true, 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;
case DxilMDHelper::kDxilAtomic64UseTag:
UAV.SetHasAtomic64Use(DxilMDHelper::ConstMDToBool(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;
}
bool DxilMDHelper::IsKnownMetadataID(LLVMContext &Ctx, unsigned ID) {
SmallVector<unsigned, 2> IDs;
GetKnownMetadataIDs(Ctx, &IDs);
return std::find(IDs.begin(), IDs.end(), ID) != IDs.end();
}
void DxilMDHelper::GetKnownMetadataIDs(LLVMContext &Ctx,
SmallVectorImpl<unsigned> *pIDs) {
SmallVector<StringRef, 4> Names;
Ctx.getMDKindNames(Names);
for (auto Name : Names) {
if (Name == hlsl::DxilMDHelper::kDxilPreciseAttributeMDName ||
Name == hlsl::DxilMDHelper::kDxilNonUniformAttributeMDName) {
pIDs->push_back(Ctx.getMDKindID(Name));
}
}
}
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().str();
}
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