Path: blob/main/contrib/llvm-project/llvm/lib/Target/DirectX/DXILMetadata.cpp
35266 views
//===- DXILMetadata.cpp - DXIL Metadata helper objects --------------------===//1//2// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.3// See https://llvm.org/LICENSE.txt for license information.4// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception5//6//===----------------------------------------------------------------------===//7///8/// \file This file contains helper objects for working with DXIL metadata.9///10//===----------------------------------------------------------------------===//1112#include "DXILMetadata.h"13#include "llvm/IR/Constants.h"14#include "llvm/IR/IRBuilder.h"15#include "llvm/IR/Metadata.h"16#include "llvm/IR/Module.h"17#include "llvm/Support/VersionTuple.h"18#include "llvm/TargetParser/Triple.h"1920using namespace llvm;21using namespace llvm::dxil;2223ValidatorVersionMD::ValidatorVersionMD(Module &M)24: Entry(M.getOrInsertNamedMetadata("dx.valver")) {}2526void ValidatorVersionMD::update(VersionTuple ValidatorVer) {27auto &Ctx = Entry->getParent()->getContext();28IRBuilder<> B(Ctx);29Metadata *MDVals[2];30MDVals[0] = ConstantAsMetadata::get(B.getInt32(ValidatorVer.getMajor()));31MDVals[1] =32ConstantAsMetadata::get(B.getInt32(ValidatorVer.getMinor().value_or(0)));3334if (isEmpty())35Entry->addOperand(MDNode::get(Ctx, MDVals));36else37Entry->setOperand(0, MDNode::get(Ctx, MDVals));38}3940bool ValidatorVersionMD::isEmpty() { return Entry->getNumOperands() == 0; }4142VersionTuple ValidatorVersionMD::getAsVersionTuple() {43if (isEmpty())44return VersionTuple(1, 0);45auto *ValVerMD = cast<MDNode>(Entry->getOperand(0));46auto *MajorMD = mdconst::extract<ConstantInt>(ValVerMD->getOperand(0));47auto *MinorMD = mdconst::extract<ConstantInt>(ValVerMD->getOperand(1));48return VersionTuple(MajorMD->getZExtValue(), MinorMD->getZExtValue());49}5051static StringRef getShortShaderStage(Triple::EnvironmentType Env) {52switch (Env) {53case Triple::Pixel:54return "ps";55case Triple::Vertex:56return "vs";57case Triple::Geometry:58return "gs";59case Triple::Hull:60return "hs";61case Triple::Domain:62return "ds";63case Triple::Compute:64return "cs";65case Triple::Library:66return "lib";67case Triple::Mesh:68return "ms";69case Triple::Amplification:70return "as";71default:72break;73}74llvm_unreachable("Unsupported environment for DXIL generation.");75return "";76}7778void dxil::createShaderModelMD(Module &M) {79NamedMDNode *Entry = M.getOrInsertNamedMetadata("dx.shaderModel");80Triple TT(M.getTargetTriple());81VersionTuple Ver = TT.getOSVersion();82LLVMContext &Ctx = M.getContext();83IRBuilder<> B(Ctx);8485Metadata *Vals[3];86Vals[0] = MDString::get(Ctx, getShortShaderStage(TT.getEnvironment()));87Vals[1] = ConstantAsMetadata::get(B.getInt32(Ver.getMajor()));88Vals[2] = ConstantAsMetadata::get(B.getInt32(Ver.getMinor().value_or(0)));89Entry->addOperand(MDNode::get(Ctx, Vals));90}9192void dxil::createDXILVersionMD(Module &M) {93Triple TT(Triple::normalize(M.getTargetTriple()));94VersionTuple Ver = TT.getDXILVersion();95LLVMContext &Ctx = M.getContext();96IRBuilder<> B(Ctx);97NamedMDNode *Entry = M.getOrInsertNamedMetadata("dx.version");98Metadata *Vals[2];99Vals[0] = ConstantAsMetadata::get(B.getInt32(Ver.getMajor()));100Vals[1] = ConstantAsMetadata::get(B.getInt32(Ver.getMinor().value_or(0)));101Entry->addOperand(MDNode::get(Ctx, Vals));102}103104static uint32_t getShaderStage(Triple::EnvironmentType Env) {105return (uint32_t)Env - (uint32_t)llvm::Triple::Pixel;106}107108namespace {109110struct EntryProps {111Triple::EnvironmentType ShaderKind;112// FIXME: support more shader profiles.113// See https://github.com/llvm/llvm-project/issues/57927.114struct {115unsigned NumThreads[3];116} CS;117118EntryProps(Function &F, Triple::EnvironmentType ModuleShaderKind)119: ShaderKind(ModuleShaderKind) {120121if (ShaderKind == Triple::EnvironmentType::Library) {122Attribute EntryAttr = F.getFnAttribute("hlsl.shader");123StringRef EntryProfile = EntryAttr.getValueAsString();124Triple T("", "", "", EntryProfile);125ShaderKind = T.getEnvironment();126}127128if (ShaderKind == Triple::EnvironmentType::Compute) {129auto NumThreadsStr =130F.getFnAttribute("hlsl.numthreads").getValueAsString();131SmallVector<StringRef> NumThreads;132NumThreadsStr.split(NumThreads, ',');133assert(NumThreads.size() == 3 && "invalid numthreads");134auto Zip =135llvm::zip(NumThreads, MutableArrayRef<unsigned>(CS.NumThreads));136for (auto It : Zip) {137StringRef Str = std::get<0>(It);138APInt V;139[[maybe_unused]] bool Result = Str.getAsInteger(10, V);140assert(!Result && "Failed to parse numthreads");141142unsigned &Num = std::get<1>(It);143Num = V.getLimitedValue();144}145}146}147148MDTuple *emitDXILEntryProps(uint64_t RawShaderFlag, LLVMContext &Ctx,149bool IsLib) {150std::vector<Metadata *> MDVals;151152if (RawShaderFlag != 0)153appendShaderFlags(MDVals, RawShaderFlag, Ctx);154155// Add shader kind for lib entrys.156if (IsLib && ShaderKind != Triple::EnvironmentType::Library)157appendShaderKind(MDVals, Ctx);158159if (ShaderKind == Triple::EnvironmentType::Compute)160appendNumThreads(MDVals, Ctx);161// FIXME: support more props.162// See https://github.com/llvm/llvm-project/issues/57948.163return MDNode::get(Ctx, MDVals);164}165166static MDTuple *emitEntryPropsForEmptyEntry(uint64_t RawShaderFlag,167LLVMContext &Ctx) {168if (RawShaderFlag == 0)169return nullptr;170171std::vector<Metadata *> MDVals;172173appendShaderFlags(MDVals, RawShaderFlag, Ctx);174// FIXME: support more props.175// See https://github.com/llvm/llvm-project/issues/57948.176return MDNode::get(Ctx, MDVals);177}178179private:180enum EntryPropsTag {181ShaderFlagsTag = 0,182GSStateTag,183DSStateTag,184HSStateTag,185NumThreadsTag,186AutoBindingSpaceTag,187RayPayloadSizeTag,188RayAttribSizeTag,189ShaderKindTag,190MSStateTag,191ASStateTag,192WaveSizeTag,193EntryRootSigTag,194};195196void appendNumThreads(std::vector<Metadata *> &MDVals, LLVMContext &Ctx) {197MDVals.emplace_back(ConstantAsMetadata::get(198ConstantInt::get(Type::getInt32Ty(Ctx), NumThreadsTag)));199200std::vector<Metadata *> NumThreadVals;201for (auto Num : ArrayRef<unsigned>(CS.NumThreads))202NumThreadVals.emplace_back(ConstantAsMetadata::get(203ConstantInt::get(Type::getInt32Ty(Ctx), Num)));204MDVals.emplace_back(MDNode::get(Ctx, NumThreadVals));205}206207static void appendShaderFlags(std::vector<Metadata *> &MDVals,208uint64_t RawShaderFlag, LLVMContext &Ctx) {209MDVals.emplace_back(ConstantAsMetadata::get(210ConstantInt::get(Type::getInt32Ty(Ctx), ShaderFlagsTag)));211MDVals.emplace_back(ConstantAsMetadata::get(212ConstantInt::get(Type::getInt64Ty(Ctx), RawShaderFlag)));213}214215void appendShaderKind(std::vector<Metadata *> &MDVals, LLVMContext &Ctx) {216MDVals.emplace_back(ConstantAsMetadata::get(217ConstantInt::get(Type::getInt32Ty(Ctx), ShaderKindTag)));218MDVals.emplace_back(ConstantAsMetadata::get(219ConstantInt::get(Type::getInt32Ty(Ctx), getShaderStage(ShaderKind))));220}221};222223class EntryMD {224Function &F;225LLVMContext &Ctx;226EntryProps Props;227228public:229EntryMD(Function &F, Triple::EnvironmentType ModuleShaderKind)230: F(F), Ctx(F.getContext()), Props(F, ModuleShaderKind) {}231232MDTuple *emitEntryTuple(MDTuple *Resources, uint64_t RawShaderFlag) {233// FIXME: add signature for profile other than CS.234// See https://github.com/llvm/llvm-project/issues/57928.235MDTuple *Signatures = nullptr;236return emitDXILEntryPointTuple(237&F, F.getName().str(), Signatures, Resources,238Props.emitDXILEntryProps(RawShaderFlag, Ctx, /*IsLib*/ false), Ctx);239}240241MDTuple *emitEntryTupleForLib(uint64_t RawShaderFlag) {242// FIXME: add signature for profile other than CS.243// See https://github.com/llvm/llvm-project/issues/57928.244MDTuple *Signatures = nullptr;245return emitDXILEntryPointTuple(246&F, F.getName().str(), Signatures,247/*entry in lib doesn't need resources metadata*/ nullptr,248Props.emitDXILEntryProps(RawShaderFlag, Ctx, /*IsLib*/ true), Ctx);249}250251// Library will have empty entry metadata which only store the resource table252// metadata.253static MDTuple *emitEmptyEntryForLib(MDTuple *Resources,254uint64_t RawShaderFlag,255LLVMContext &Ctx) {256return emitDXILEntryPointTuple(257nullptr, "", nullptr, Resources,258EntryProps::emitEntryPropsForEmptyEntry(RawShaderFlag, Ctx), Ctx);259}260261private:262static MDTuple *emitDXILEntryPointTuple(Function *Fn, const std::string &Name,263MDTuple *Signatures,264MDTuple *Resources,265MDTuple *Properties,266LLVMContext &Ctx) {267Metadata *MDVals[5];268MDVals[0] = Fn ? ValueAsMetadata::get(Fn) : nullptr;269MDVals[1] = MDString::get(Ctx, Name.c_str());270MDVals[2] = Signatures;271MDVals[3] = Resources;272MDVals[4] = Properties;273return MDNode::get(Ctx, MDVals);274}275};276} // namespace277278void dxil::createEntryMD(Module &M, const uint64_t ShaderFlags) {279SmallVector<Function *> EntryList;280for (auto &F : M.functions()) {281if (!F.hasFnAttribute("hlsl.shader"))282continue;283EntryList.emplace_back(&F);284}285286auto &Ctx = M.getContext();287// FIXME: generate metadata for resource.288// See https://github.com/llvm/llvm-project/issues/57926.289MDTuple *MDResources = nullptr;290if (auto *NamedResources = M.getNamedMetadata("dx.resources"))291MDResources = dyn_cast<MDTuple>(NamedResources->getOperand(0));292293std::vector<MDNode *> Entries;294Triple T = Triple(M.getTargetTriple());295switch (T.getEnvironment()) {296case Triple::EnvironmentType::Library: {297// Add empty entry to put resource metadata.298MDTuple *EmptyEntry =299EntryMD::emitEmptyEntryForLib(MDResources, ShaderFlags, Ctx);300Entries.emplace_back(EmptyEntry);301302for (Function *Entry : EntryList) {303EntryMD MD(*Entry, T.getEnvironment());304Entries.emplace_back(MD.emitEntryTupleForLib(0));305}306} break;307case Triple::EnvironmentType::Compute:308case Triple::EnvironmentType::Amplification:309case Triple::EnvironmentType::Mesh:310case Triple::EnvironmentType::Vertex:311case Triple::EnvironmentType::Hull:312case Triple::EnvironmentType::Domain:313case Triple::EnvironmentType::Geometry:314case Triple::EnvironmentType::Pixel: {315assert(EntryList.size() == 1 &&316"non-lib profiles should only have one entry");317EntryMD MD(*EntryList.front(), T.getEnvironment());318Entries.emplace_back(MD.emitEntryTuple(MDResources, ShaderFlags));319} break;320default:321assert(0 && "invalid profile");322break;323}324325NamedMDNode *EntryPointsNamedMD =326M.getOrInsertNamedMetadata("dx.entryPoints");327for (auto *Entry : Entries)328EntryPointsNamedMD->addOperand(Entry);329}330331332