[llvm] [DXIL] Consume Metadata Analysis information in passes (PR #108034)
S. Bharadwaj Yadavalli via llvm-commits
llvm-commits at lists.llvm.org
Thu Sep 12 17:17:24 PDT 2024
================
@@ -65,18 +69,269 @@ static void emitResourceMetadata(Module &M, const DXILResourceMap &DRM,
MDNode::get(M.getContext(), {SRVMD, UAVMD, CBufMD, SmpMD}));
}
+static StringRef getShortShaderStage(Triple::EnvironmentType Env) {
+ switch (Env) {
+ case Triple::Pixel:
+ return "ps";
+ case Triple::Vertex:
+ return "vs";
+ case Triple::Geometry:
+ return "gs";
+ case Triple::Hull:
+ return "hs";
+ case Triple::Domain:
+ return "ds";
+ case Triple::Compute:
+ return "cs";
+ case Triple::Library:
+ return "lib";
+ case Triple::Mesh:
+ return "ms";
+ case Triple::Amplification:
+ return "as";
+ default:
+ break;
+ }
+ llvm_unreachable("Unsupported environment for DXIL generation.");
+ return "";
+}
+
+static uint32_t getShaderStage(Triple::EnvironmentType Env) {
+ return (uint32_t)Env - (uint32_t)llvm::Triple::Pixel;
+}
+
+struct ShaderEntryMDInfo : EntryProperties {
+
+ enum EntryPropsTag {
+ ShaderFlagsTag = 0,
+ GSStateTag,
+ DSStateTag,
+ HSStateTag,
+ NumThreadsTag,
+ AutoBindingSpaceTag,
+ RayPayloadSizeTag,
+ RayAttribSizeTag,
+ ShaderKindTag,
+ MSStateTag,
+ ASStateTag,
+ WaveSizeTag,
+ EntryRootSigTag,
+ };
+
+ ShaderEntryMDInfo(EntryProperties &EP, LLVMContext &C,
+ Triple::EnvironmentType SP, MDTuple *MDR = nullptr,
+ uint64_t ShaderFlags = 0)
+ : EntryProperties(EP), Ctx(C), EntryShaderFlags(ShaderFlags),
+ MDResources(MDR), ShaderProfile(SP) {};
+
+ MDTuple *getAsMetadata() {
+ MDTuple *Properties = constructEntryPropMetadata();
+ // FIXME: Add support to construct Signatures
+ // See https://github.com/llvm/llvm-project/issues/57928
+ MDTuple *Signatures = nullptr;
+ return constructEntryMetadata(Signatures, MDResources, Properties);
+ }
+
+private:
+ LLVMContext &Ctx;
+ // Shader Flags for the Entry - from ShadeFLagsAnalysis pass
+ uint64_t EntryShaderFlags{0};
+ MDTuple *MDResources{nullptr};
+ Triple::EnvironmentType ShaderProfile{
+ Triple::EnvironmentType::UnknownEnvironment};
+ // Each entry point metadata record specifies:
+ // * reference to the entry point function global symbol
+ // * unmangled name
+ // * list of signatures
+ // * list of resources
+ // * list of tag-value pairs of shader capabilities and other properties
+
+ MDTuple *constructEntryMetadata(MDTuple *Signatures, MDTuple *Resources,
+ MDTuple *Properties) {
+ Metadata *MDVals[5];
+ MDVals[0] =
+ Entry ? ValueAsMetadata::get(const_cast<Function *>(Entry)) : nullptr;
+ MDVals[1] = MDString::get(Ctx, Entry ? Entry->getName() : "");
+ MDVals[2] = Signatures;
+ MDVals[3] = Resources;
+ MDVals[4] = Properties;
+ return MDNode::get(Ctx, MDVals);
+ }
+
+ SmallVector<Metadata *> getTagValueAsMetadata(EntryPropsTag Tag,
+ uint64_t Value) {
+ SmallVector<Metadata *> MDVals;
+ MDVals.emplace_back(
+ ConstantAsMetadata::get(ConstantInt::get(Type::getInt32Ty(Ctx), Tag)));
+ switch (Tag) {
+ case ShaderFlagsTag:
+ MDVals.emplace_back(ConstantAsMetadata::get(
+ ConstantInt::get(Type::getInt64Ty(Ctx), Value)));
+ break;
+ case ShaderKindTag:
+ MDVals.emplace_back(ConstantAsMetadata::get(
+ ConstantInt::get(Type::getInt32Ty(Ctx), Value)));
+ break;
+ default:
+ assert(false && "NYI: Unhandled entry property tag");
+ }
+ return MDVals;
+ }
+
+ MDTuple *constructEntryPropMetadata() {
+ SmallVector<Metadata *> MDVals;
+ if (EntryShaderFlags != 0)
+ MDVals.append(getTagValueAsMetadata(ShaderFlagsTag, EntryShaderFlags));
+
+ if (Entry != nullptr) {
+ // FIXME: support more props.
+ // See https://github.com/llvm/llvm-project/issues/57948.
+ // Add shader kind for lib entries.
+ if (ShaderProfile == Triple::EnvironmentType::Library &&
+ ShaderStage != Triple::EnvironmentType::Library)
+ MDVals.append(
+ getTagValueAsMetadata(ShaderKindTag, getShaderStage(ShaderStage)));
+
+ if (ShaderStage == Triple::EnvironmentType::Compute) {
+ MDVals.emplace_back(ConstantAsMetadata::get(
+ ConstantInt::get(Type::getInt32Ty(Ctx), NumThreadsTag)));
+ std::vector<Metadata *> NumThreadVals;
+ NumThreadVals.emplace_back(ConstantAsMetadata::get(
+ ConstantInt::get(Type::getInt32Ty(Ctx), NumThreadsX)));
+ NumThreadVals.emplace_back(ConstantAsMetadata::get(
+ ConstantInt::get(Type::getInt32Ty(Ctx), NumThreadsY)));
+ NumThreadVals.emplace_back(ConstantAsMetadata::get(
+ ConstantInt::get(Type::getInt32Ty(Ctx), NumThreadsZ)));
+ MDVals.emplace_back(MDNode::get(Ctx, NumThreadVals));
+ }
+ }
+ if (MDVals.empty())
+ return nullptr;
+ return MDNode::get(Ctx, MDVals);
+ }
+};
+
+static void createEntryMD(Module &M, const uint64_t ShaderFlags,
+ const dxil::ModuleMetadataInfo &MDAnalysisInfo) {
+ auto &Ctx = M.getContext();
+ // FIXME: generate metadata for resource.
+ MDTuple *MDResources = nullptr;
+ if (auto *NamedResources = M.getNamedMetadata("dx.resources"))
+ MDResources = dyn_cast<MDTuple>(NamedResources->getOperand(0));
+
+ std::vector<MDNode *> EntryFnMDNodes;
+ switch (MDAnalysisInfo.ShaderProfile) {
+ case Triple::EnvironmentType::Library: {
+ // Library has an entry metadata with resource table metadata and all other
+ // MDNodes as null.
+ EntryProperties EP{};
+ // FIXME: ShaderFlagsAnalysis pass needs to collect and provide ShaderFlags
+ // for each entry function. Currently, ShaderFlags value provided by
+ // ShaderFlagsAnalysis pass is created by walking *all* the function
+ // instructions of the module. Is it is correct to use this value for
+ // metadata of the empty library entry?
+ ShaderEntryMDInfo EmptyFunEntryProps(EP, Ctx, MDAnalysisInfo.ShaderProfile,
+ MDResources, ShaderFlags);
+ MDTuple *EmptyMDT = EmptyFunEntryProps.getAsMetadata();
+ EntryFnMDNodes.emplace_back(EmptyMDT);
+
+ for (auto EntryProp : MDAnalysisInfo.EntryPropertyVec) {
+ // FIXME: ShaderFlagsAnalysis pass needs to collect and provide
+ // ShaderFlags for each entry function. For now, assume shader flags value
+ // of entry functions being compiled for lib_* shader profile viz.,
+ // EntryPro.Entry is 0.
+ ShaderEntryMDInfo SEP(EntryProp, Ctx, MDAnalysisInfo.ShaderProfile,
+ nullptr, 0);
+ MDTuple *MDT = SEP.getAsMetadata();
+ EntryFnMDNodes.emplace_back(MDT);
+ }
+ } break;
+ case Triple::EnvironmentType::Compute: {
+ size_t NumEntries = MDAnalysisInfo.EntryPropertyVec.size();
+ assert(NumEntries == 1 &&
+ "Compute shader: One and only one entry expected");
+ EntryProperties EntryProp = MDAnalysisInfo.EntryPropertyVec[0];
+ // ShaderFlagsAnalysis pass needs to collect and provide ShaderFlags for
+ // each entry function. Currently, even though the ShaderFlags value
+ // provided by ShaderFlagsAnalysis pass is created by walking all the
+ // function instructions of the module, it is sufficient to since there is
+ // only one entry function in the module.
+ ShaderEntryMDInfo SEP(EntryProp, Ctx, MDAnalysisInfo.ShaderProfile,
+ MDResources, ShaderFlags);
+ MDTuple *MDT = SEP.getAsMetadata();
+ EntryFnMDNodes.emplace_back(MDT);
+ break;
+ }
+ case Triple::EnvironmentType::Amplification:
+ case Triple::EnvironmentType::Mesh:
+ case Triple::EnvironmentType::Vertex:
+ case Triple::EnvironmentType::Hull:
+ case Triple::EnvironmentType::Domain:
+ case Triple::EnvironmentType::Geometry:
+ case Triple::EnvironmentType::Pixel: {
+ size_t NumEntries = MDAnalysisInfo.EntryPropertyVec.size();
+ assert(NumEntries == 1 && "non-lib profiles should only have one entry");
+ EntryProperties EntryProp = MDAnalysisInfo.EntryPropertyVec[0];
+ // ShaderFlagsAnalysis pass needs to collect and provide ShaderFlags for
+ // each entry function. Currently, even though the ShaderFlags value
+ // provided by ShaderFlagsAnalysis pass is created by walking all the
+ // function instructions of the module, it is sufficient to since there is
+ // only one entry function in the module.
+ ShaderEntryMDInfo SEP(EntryProp, Ctx, MDAnalysisInfo.ShaderProfile,
+ MDResources, ShaderFlags);
+ MDTuple *MDT = SEP.getAsMetadata();
+ EntryFnMDNodes.emplace_back(MDT);
+ } break;
+ default:
+ assert(0 && "invalid profile");
+ break;
+ }
+
+ NamedMDNode *EntryPointsNamedMD =
+ M.getOrInsertNamedMetadata("dx.entryPoints");
+ for (auto *Entry : EntryFnMDNodes)
+ EntryPointsNamedMD->addOperand(Entry);
+}
+
static void translateMetadata(Module &M, const DXILResourceMap &DRM,
const dxil::Resources &MDResources,
- const ComputedShaderFlags &ShaderFlags) {
- dxil::ValidatorVersionMD ValVerMD(M);
- if (ValVerMD.isEmpty())
- ValVerMD.update(VersionTuple(1, 0));
- dxil::createShaderModelMD(M);
- dxil::createDXILVersionMD(M);
+ const ComputedShaderFlags &ShaderFlags,
+ const dxil::ModuleMetadataInfo &MDAnalysisInfo) {
+ LLVMContext &Ctx = M.getContext();
+ IRBuilder<> IRB(Ctx);
+ if (MDAnalysisInfo.ValidatorVersion.empty()) {
+ // Module has no metadata node signifying valid validator version.
+ // Create metadata dx.valver node with version value of 1.0
+ const VersionTuple DefaultValidatorVer{1, 0};
+ Metadata *MDVals[2];
+ MDVals[0] =
+ ConstantAsMetadata::get(IRB.getInt32(DefaultValidatorVer.getMajor()));
+ MDVals[1] = ConstantAsMetadata::get(
+ IRB.getInt32(DefaultValidatorVer.getMinor().value_or(0)));
+ NamedMDNode *ValVerNode = M.getOrInsertNamedMetadata("dx.valver");
+ ValVerNode->addOperand(MDNode::get(Ctx, MDVals));
+ }
+
+ Metadata *SMVals[3];
+ VersionTuple SM = MDAnalysisInfo.ShaderModelVersion;
+ SMVals[0] =
+ MDString::get(Ctx, getShortShaderStage(MDAnalysisInfo.ShaderProfile));
+ SMVals[1] = ConstantAsMetadata::get(IRB.getInt32(SM.getMajor()));
+ SMVals[2] = ConstantAsMetadata::get(IRB.getInt32(SM.getMinor().value_or(0)));
+ NamedMDNode *SMMDNode = M.getOrInsertNamedMetadata("dx.shaderModel");
+ SMMDNode->addOperand(MDNode::get(Ctx, SMVals));
+
+ VersionTuple DXILVer = MDAnalysisInfo.DXILVersion;
+ Metadata *DXILVals[2];
+ DXILVals[0] = ConstantAsMetadata::get(IRB.getInt32(DXILVer.getMajor()));
+ DXILVals[1] =
+ ConstantAsMetadata::get(IRB.getInt32(DXILVer.getMinor().value_or(0)));
+ NamedMDNode *DXILVerMDNode = M.getOrInsertNamedMetadata("dx.version");
+ DXILVerMDNode->addOperand(MDNode::get(Ctx, DXILVals));
----------------
bharadwajy wrote:
> I'd probably move these three blocks of logic into simple functions to keep the level of abstraction at a single level here, so this function would just look something like:
>
> ```c++
> emitValidatorVersionMD(M, MMI);
> emitShaderModuleMD(M, MMI);
> emitDXILVersionMD(M, MMI);
> NamedMDNode *ResourceNode = emitResourceMetadata(M, DRM, MDResources);
>
> SmallVector<MDNode *> EntryNodes;
> if (MMI.ShaderProfile == Triple::EnvironmentType::Library)
> EntryNodes.push_back(emitTopLevelLibraryNode(M, ResourceNode, ShaderFlags));
> else if (MMI.EntryProps.size() != 1)
> diagnoseWrongNumberOfEntryProps(MMI.ShaderProfile, MMI.EntryProps.size());
> for (const EntryProperties &Entry : MMI.EntryProps)
> EntryNodes.push_back(emitEntryNode(M, Entry, MMI, ResourceNode, ShaderFlags));
> emitEntryPointsMD(M, EntryNodes);
> ```
Done.
https://github.com/llvm/llvm-project/pull/108034
More information about the llvm-commits
mailing list