[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:23 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()) {
----------------
bharadwajy wrote:
> This pass shouldn't know the details of how the analysis gets the validator version, and so it should really emit/update the `dx.valver` version to whatever the metadata analysis says. Also IIRC we decided to set the default in the frontend, so I'm not sure we should be duplicating that logic here.
Changed.
https://github.com/llvm/llvm-project/pull/108034
More information about the llvm-commits
mailing list