[llvm] [DXIL] Consume Metadata Analysis information in passes (PR #108034)
S. Bharadwaj Yadavalli via llvm-commits
llvm-commits at lists.llvm.org
Wed Sep 18 14:08:53 PDT 2024
================
@@ -58,25 +94,258 @@ static void emitResourceMetadata(Module &M, const DXILResourceMap &DRM,
}
if (!HasResources)
- return;
+ return nullptr;
NamedMDNode *ResourceMD = M.getOrInsertNamedMetadata("dx.resources");
ResourceMD->addOperand(
MDNode::get(M.getContext(), {SRVMD, UAVMD, CBufMD, SmpMD}));
+
+ return ResourceMD;
+}
+
+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.");
+}
+
+static uint32_t getShaderStage(Triple::EnvironmentType Env) {
+ return (uint32_t)Env - (uint32_t)llvm::Triple::Pixel;
+}
+
+namespace {
+enum EntryPropsTag {
+ ShaderFlagsTag = 0,
+ GSStateTag,
+ DSStateTag,
+ HSStateTag,
+ NumThreadsTag,
+ AutoBindingSpaceTag,
+ RayPayloadSizeTag,
+ RayAttribSizeTag,
+ ShaderKindTag,
+ MSStateTag,
+ ASStateTag,
+ WaveSizeTag,
+ EntryRootSigTag,
+};
+} // namespace
+
+static SmallVector<Metadata *>
+getTagValueAsMetadata(EntryPropsTag Tag, uint64_t Value, LLVMContext &Ctx) {
+ 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;
+}
+
+static MDTuple *
+getEntryPropAsMetadata(const EntryProperties &EP, uint64_t EntryShaderFlags,
+ const Triple::EnvironmentType ShaderProfile) {
+ SmallVector<Metadata *> MDVals;
+ LLVMContext &Ctx = EP.Entry->getContext();
+ if (EntryShaderFlags != 0)
+ MDVals.append(getTagValueAsMetadata(ShaderFlagsTag, EntryShaderFlags, Ctx));
+
+ if (EP.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 &&
+ EP.ShaderStage != Triple::EnvironmentType::Library)
+ MDVals.append(getTagValueAsMetadata(ShaderKindTag,
+ getShaderStage(EP.ShaderStage), Ctx));
+
+ if (EP.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), EP.NumThreadsX)));
+ NumThreadVals.emplace_back(ConstantAsMetadata::get(
+ ConstantInt::get(Type::getInt32Ty(Ctx), EP.NumThreadsY)));
+ NumThreadVals.emplace_back(ConstantAsMetadata::get(
+ ConstantInt::get(Type::getInt32Ty(Ctx), EP.NumThreadsZ)));
+ MDVals.emplace_back(MDNode::get(Ctx, NumThreadVals));
+ }
+ }
+ if (MDVals.empty())
+ return nullptr;
+ return MDNode::get(Ctx, MDVals);
+}
+
+// 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(const Function *EntryFn, MDTuple *Signatures,
+ MDNode *Resources, MDTuple *Properties,
+ LLVMContext &Ctx) {
+ Metadata *MDVals[5];
+ MDVals[0] =
+ EntryFn ? ValueAsMetadata::get(const_cast<Function *>(EntryFn)) : nullptr;
+ MDVals[1] = MDString::get(Ctx, EntryFn ? EntryFn->getName() : "");
+ MDVals[2] = Signatures;
+ MDVals[3] = Resources;
+ MDVals[4] = Properties;
+ return MDNode::get(Ctx, MDVals);
+}
+
+static MDTuple *emitEntryMD(const EntryProperties &EP, MDTuple *Signatures,
+ MDNode *MDResources,
+ const uint64_t EntryShaderFlags,
+ const Triple::EnvironmentType ShaderProfile) {
+ MDTuple *Properties =
+ getEntryPropAsMetadata(EP, EntryShaderFlags, ShaderProfile);
+ return constructEntryMetadata(EP.Entry, Signatures, MDResources, Properties,
+ EP.Entry->getContext());
+}
+
+static void emitValidatorVersionMD(Module &M, const ModuleMetadataInfo &MMDI) {
+ if (!MMDI.ValidatorVersion.empty()) {
+ LLVMContext &Ctx = M.getContext();
+ IRBuilder<> IRB(Ctx);
+ Metadata *MDVals[2];
+ MDVals[0] =
+ ConstantAsMetadata::get(IRB.getInt32(MMDI.ValidatorVersion.getMajor()));
+ MDVals[1] = ConstantAsMetadata::get(
+ IRB.getInt32(MMDI.ValidatorVersion.getMinor().value_or(0)));
+ NamedMDNode *ValVerNode = M.getOrInsertNamedMetadata("dx.valver");
+ // Set validator version obtained from DXIL Metadata Analysis pass
+ ValVerNode->clearOperands();
+ ValVerNode->addOperand(MDNode::get(Ctx, MDVals));
+ }
+}
+
+static void emitShaderModelVersionMD(Module &M,
+ const ModuleMetadataInfo &MMDI) {
+ LLVMContext &Ctx = M.getContext();
+ IRBuilder<> IRB(Ctx);
+ Metadata *SMVals[3];
+ VersionTuple SM = MMDI.ShaderModelVersion;
+ SMVals[0] = MDString::get(Ctx, getShortShaderStage(MMDI.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));
+}
+
+static void emitDXILVersionTupleMD(Module &M, const ModuleMetadataInfo &MMDI) {
+ LLVMContext &Ctx = M.getContext();
+ IRBuilder<> IRB(Ctx);
+ VersionTuple DXILVer = MMDI.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));
+}
+
+static MDTuple *emitTopLevelLibraryNode(Module &M, MDNode *RMD,
+ uint64_t ShaderFlags) {
+ LLVMContext &Ctx = M.getContext();
+ MDTuple *Properties = nullptr;
+ if (ShaderFlags != 0) {
+ SmallVector<Metadata *> MDVals;
+ // 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?
+ MDVals.append(getTagValueAsMetadata(ShaderFlagsTag, ShaderFlags, Ctx));
+ Properties = MDNode::get(Ctx, MDVals);
+ }
+ // Library has an entry metadata with resource table metadata and all other
+ // MDNodes as null.
+ return constructEntryMetadata(nullptr, nullptr, RMD, Properties, Ctx);
}
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 Resources &MDResources,
+ const ComputedShaderFlags &ShaderFlags,
+ const ModuleMetadataInfo &MMDI) {
+ LLVMContext &Ctx = M.getContext();
+ IRBuilder<> IRB(Ctx);
+ SmallVector<MDNode *> EntryFnMDNodes;
+
+ emitValidatorVersionMD(M, MMDI);
+ emitShaderModelVersionMD(M, MMDI);
+ emitDXILVersionTupleMD(M, MMDI);
+ NamedMDNode *NamedResourceMD = emitResourceMetadata(M, DRM, MDResources);
+ auto *ResourceMD =
+ (NamedResourceMD != nullptr) ? NamedResourceMD->getOperand(0) : nullptr;
+ // FIXME: Add support to construct Signatures
+ // See https://github.com/llvm/llvm-project/issues/57928
+ MDTuple *Signatures = nullptr;
- emitResourceMetadata(M, DRM, MDResources);
+ if (MMDI.ShaderProfile == Triple::EnvironmentType::Library)
+ EntryFnMDNodes.emplace_back(
+ emitTopLevelLibraryNode(M, ResourceMD, ShaderFlags));
+ else if (MMDI.EntryPropertyVec.size() > 1) {
+ M.getContext().diagnose(DiagnosticInfoModuleFormat(
+ M, "Non-library shader: One and only one entry expected"));
+ }
+
+ for (const EntryProperties &EntryProp : MMDI.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.
+ uint64_t EntryShaderFlags =
+ (MMDI.ShaderProfile == Triple::EnvironmentType::Library) ? 0
+ : ShaderFlags;
+ if (MMDI.ShaderProfile != Triple::EnvironmentType::Library) {
+ if (EntryProp.ShaderStage != MMDI.ShaderProfile) {
+ M.getContext().diagnose(DiagnosticInfoModuleFormat(
+ M, "Non-library shader: Stage of Shader entry different from "
----------------
bharadwajy wrote:
> > "Non-library shader: Stage of shader entry different from shader target profile"
>
> So, I think: if this diagnostic is emitted for IR generated by Clang then this is a bug in Clang. Does that sound right? The only way to really hit this is for some other frontend to do the wrong thing?
>
> Given that the case we can probably frame the diagnostic using llvm terms like "environment" and "triple" if that helps at all?
How about -
```
Shader stage '<entry-shader-stage>' of entry '<entry>' different from specified target profile '<target-shader-profile>'
```
where the exact mismatching component is spelt out? An instance of such a message would look like
```
Shader stage 'cs' of entry 'cs_entry' different from specified target profile 'pixel'
```
https://github.com/llvm/llvm-project/pull/108034
More information about the llvm-commits
mailing list