summaryrefslogtreecommitdiffstats
path: root/contrib/llvm/lib/Target/AMDGPU/MCTargetDesc/AMDGPURuntimeMD.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'contrib/llvm/lib/Target/AMDGPU/MCTargetDesc/AMDGPURuntimeMD.cpp')
-rw-r--r--contrib/llvm/lib/Target/AMDGPU/MCTargetDesc/AMDGPURuntimeMD.cpp408
1 files changed, 408 insertions, 0 deletions
diff --git a/contrib/llvm/lib/Target/AMDGPU/MCTargetDesc/AMDGPURuntimeMD.cpp b/contrib/llvm/lib/Target/AMDGPU/MCTargetDesc/AMDGPURuntimeMD.cpp
new file mode 100644
index 0000000..95387ad
--- /dev/null
+++ b/contrib/llvm/lib/Target/AMDGPU/MCTargetDesc/AMDGPURuntimeMD.cpp
@@ -0,0 +1,408 @@
+//===-- AMDGPURuntimeMD.cpp - Generates runtime metadata ------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+/// \file
+///
+/// Generates AMDGPU runtime metadata for YAML mapping.
+//
+//===----------------------------------------------------------------------===//
+//
+
+#include "AMDGPU.h"
+#include "AMDGPURuntimeMetadata.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/ADT/StringSwitch.h"
+#include "llvm/IR/Constants.h"
+#include "llvm/IR/DataLayout.h"
+#include "llvm/IR/Module.h"
+#include "llvm/Support/CommandLine.h"
+#include "llvm/Support/raw_ostream.h"
+#include "llvm/Support/YAMLTraits.h"
+#include <vector>
+#include "AMDGPURuntimeMD.h"
+
+using namespace llvm;
+using namespace ::AMDGPU::RuntimeMD;
+
+static cl::opt<bool>
+DumpRuntimeMD("amdgpu-dump-rtmd",
+ cl::desc("Dump AMDGPU runtime metadata"));
+
+static cl::opt<bool>
+CheckRuntimeMDParser("amdgpu-check-rtmd-parser", cl::Hidden,
+ cl::desc("Check AMDGPU runtime metadata YAML parser"));
+
+LLVM_YAML_IS_FLOW_SEQUENCE_VECTOR(uint8_t)
+LLVM_YAML_IS_FLOW_SEQUENCE_VECTOR(uint32_t)
+LLVM_YAML_IS_FLOW_SEQUENCE_VECTOR(std::string)
+LLVM_YAML_IS_SEQUENCE_VECTOR(Kernel::Metadata)
+LLVM_YAML_IS_SEQUENCE_VECTOR(KernelArg::Metadata)
+
+namespace llvm {
+namespace yaml {
+
+template <> struct MappingTraits<KernelArg::Metadata> {
+ static void mapping(IO &YamlIO, KernelArg::Metadata &A) {
+ YamlIO.mapRequired(KeyName::ArgSize, A.Size);
+ YamlIO.mapRequired(KeyName::ArgAlign, A.Align);
+ YamlIO.mapOptional(KeyName::ArgPointeeAlign, A.PointeeAlign, 0U);
+ YamlIO.mapRequired(KeyName::ArgKind, A.Kind);
+ YamlIO.mapRequired(KeyName::ArgValueType, A.ValueType);
+ YamlIO.mapOptional(KeyName::ArgTypeName, A.TypeName, std::string());
+ YamlIO.mapOptional(KeyName::ArgName, A.Name, std::string());
+ YamlIO.mapOptional(KeyName::ArgAddrQual, A.AddrQual, INVALID_ADDR_QUAL);
+ YamlIO.mapOptional(KeyName::ArgAccQual, A.AccQual, INVALID_ACC_QUAL);
+ YamlIO.mapOptional(KeyName::ArgIsVolatile, A.IsVolatile, uint8_t(0));
+ YamlIO.mapOptional(KeyName::ArgIsConst, A.IsConst, uint8_t(0));
+ YamlIO.mapOptional(KeyName::ArgIsRestrict, A.IsRestrict, uint8_t(0));
+ YamlIO.mapOptional(KeyName::ArgIsPipe, A.IsPipe, uint8_t(0));
+ }
+ static const bool flow = true;
+};
+
+template <> struct MappingTraits<Kernel::Metadata> {
+ static void mapping(IO &YamlIO, Kernel::Metadata &K) {
+ YamlIO.mapRequired(KeyName::KernelName, K.Name);
+ YamlIO.mapOptional(KeyName::Language, K.Language, std::string());
+ YamlIO.mapOptional(KeyName::LanguageVersion, K.LanguageVersion);
+ YamlIO.mapOptional(KeyName::ReqdWorkGroupSize, K.ReqdWorkGroupSize);
+ YamlIO.mapOptional(KeyName::WorkGroupSizeHint, K.WorkGroupSizeHint);
+ YamlIO.mapOptional(KeyName::VecTypeHint, K.VecTypeHint, std::string());
+ YamlIO.mapOptional(KeyName::KernelIndex, K.KernelIndex,
+ INVALID_KERNEL_INDEX);
+ YamlIO.mapOptional(KeyName::NoPartialWorkGroups, K.NoPartialWorkGroups,
+ uint8_t(0));
+ YamlIO.mapRequired(KeyName::Args, K.Args);
+ }
+ static const bool flow = true;
+};
+
+template <> struct MappingTraits<Program::Metadata> {
+ static void mapping(IO &YamlIO, Program::Metadata &Prog) {
+ YamlIO.mapRequired(KeyName::MDVersion, Prog.MDVersionSeq);
+ YamlIO.mapOptional(KeyName::PrintfInfo, Prog.PrintfInfo);
+ YamlIO.mapOptional(KeyName::Kernels, Prog.Kernels);
+ }
+ static const bool flow = true;
+};
+
+} // end namespace yaml
+} // end namespace llvm
+
+// Get a vector of three integer values from MDNode \p Node;
+static std::vector<uint32_t> getThreeInt32(MDNode *Node) {
+ assert(Node->getNumOperands() == 3);
+ std::vector<uint32_t> V;
+ for (const MDOperand &Op : Node->operands()) {
+ const ConstantInt *CI = mdconst::extract<ConstantInt>(Op);
+ V.push_back(CI->getZExtValue());
+ }
+ return V;
+}
+
+static std::string getOCLTypeName(Type *Ty, bool Signed) {
+ switch (Ty->getTypeID()) {
+ case Type::HalfTyID:
+ return "half";
+ case Type::FloatTyID:
+ return "float";
+ case Type::DoubleTyID:
+ return "double";
+ case Type::IntegerTyID: {
+ if (!Signed)
+ return (Twine('u') + getOCLTypeName(Ty, true)).str();
+ unsigned BW = Ty->getIntegerBitWidth();
+ switch (BW) {
+ case 8:
+ return "char";
+ case 16:
+ return "short";
+ case 32:
+ return "int";
+ case 64:
+ return "long";
+ default:
+ return (Twine('i') + Twine(BW)).str();
+ }
+ }
+ case Type::VectorTyID: {
+ VectorType *VecTy = cast<VectorType>(Ty);
+ Type *EleTy = VecTy->getElementType();
+ unsigned Size = VecTy->getVectorNumElements();
+ return (Twine(getOCLTypeName(EleTy, Signed)) + Twine(Size)).str();
+ }
+ default:
+ return "unknown";
+ }
+}
+
+static KernelArg::ValueType getRuntimeMDValueType(
+ Type *Ty, StringRef TypeName) {
+ switch (Ty->getTypeID()) {
+ case Type::HalfTyID:
+ return KernelArg::F16;
+ case Type::FloatTyID:
+ return KernelArg::F32;
+ case Type::DoubleTyID:
+ return KernelArg::F64;
+ case Type::IntegerTyID: {
+ bool Signed = !TypeName.startswith("u");
+ switch (Ty->getIntegerBitWidth()) {
+ case 8:
+ return Signed ? KernelArg::I8 : KernelArg::U8;
+ case 16:
+ return Signed ? KernelArg::I16 : KernelArg::U16;
+ case 32:
+ return Signed ? KernelArg::I32 : KernelArg::U32;
+ case 64:
+ return Signed ? KernelArg::I64 : KernelArg::U64;
+ default:
+ // Runtime does not recognize other integer types. Report as struct type.
+ return KernelArg::Struct;
+ }
+ }
+ case Type::VectorTyID:
+ return getRuntimeMDValueType(Ty->getVectorElementType(), TypeName);
+ case Type::PointerTyID:
+ return getRuntimeMDValueType(Ty->getPointerElementType(), TypeName);
+ default:
+ return KernelArg::Struct;
+ }
+}
+
+static KernelArg::AddressSpaceQualifer getRuntimeAddrSpace(
+ AMDGPUAS::AddressSpaces A) {
+ switch (A) {
+ case AMDGPUAS::GLOBAL_ADDRESS:
+ return KernelArg::Global;
+ case AMDGPUAS::CONSTANT_ADDRESS:
+ return KernelArg::Constant;
+ case AMDGPUAS::LOCAL_ADDRESS:
+ return KernelArg::Local;
+ case AMDGPUAS::FLAT_ADDRESS:
+ return KernelArg::Generic;
+ case AMDGPUAS::REGION_ADDRESS:
+ return KernelArg::Region;
+ default:
+ return KernelArg::Private;
+ }
+}
+
+static KernelArg::Metadata getRuntimeMDForKernelArg(const DataLayout &DL,
+ Type *T, KernelArg::Kind Kind, StringRef BaseTypeName = "",
+ StringRef TypeName = "", StringRef ArgName = "", StringRef TypeQual = "",
+ StringRef AccQual = "") {
+
+ KernelArg::Metadata Arg;
+
+ // Set ArgSize and ArgAlign.
+ Arg.Size = DL.getTypeAllocSize(T);
+ Arg.Align = DL.getABITypeAlignment(T);
+ if (auto PT = dyn_cast<PointerType>(T)) {
+ auto ET = PT->getElementType();
+ if (PT->getAddressSpace() == AMDGPUAS::LOCAL_ADDRESS && ET->isSized())
+ Arg.PointeeAlign = DL.getABITypeAlignment(ET);
+ }
+
+ // Set ArgTypeName.
+ Arg.TypeName = TypeName;
+
+ // Set ArgName.
+ Arg.Name = ArgName;
+
+ // Set ArgIsVolatile, ArgIsRestrict, ArgIsConst and ArgIsPipe.
+ SmallVector<StringRef, 1> SplitQ;
+ TypeQual.split(SplitQ, " ", -1, false /* Drop empty entry */);
+
+ for (StringRef KeyName : SplitQ) {
+ auto *P = StringSwitch<uint8_t *>(KeyName)
+ .Case("volatile", &Arg.IsVolatile)
+ .Case("restrict", &Arg.IsRestrict)
+ .Case("const", &Arg.IsConst)
+ .Case("pipe", &Arg.IsPipe)
+ .Default(nullptr);
+ if (P)
+ *P = 1;
+ }
+
+ // Set ArgKind.
+ Arg.Kind = Kind;
+
+ // Set ArgValueType.
+ Arg.ValueType = getRuntimeMDValueType(T, BaseTypeName);
+
+ // Set ArgAccQual.
+ if (!AccQual.empty()) {
+ Arg.AccQual = StringSwitch<KernelArg::AccessQualifer>(AccQual)
+ .Case("read_only", KernelArg::ReadOnly)
+ .Case("write_only", KernelArg::WriteOnly)
+ .Case("read_write", KernelArg::ReadWrite)
+ .Default(KernelArg::AccNone);
+ }
+
+ // Set ArgAddrQual.
+ if (auto *PT = dyn_cast<PointerType>(T)) {
+ Arg.AddrQual = getRuntimeAddrSpace(static_cast<AMDGPUAS::AddressSpaces>(
+ PT->getAddressSpace()));
+ }
+
+ return Arg;
+}
+
+static Kernel::Metadata getRuntimeMDForKernel(const Function &F) {
+ Kernel::Metadata Kernel;
+ Kernel.Name = F.getName();
+ auto &M = *F.getParent();
+
+ // Set Language and LanguageVersion.
+ if (auto MD = M.getNamedMetadata("opencl.ocl.version")) {
+ if (MD->getNumOperands() != 0) {
+ auto Node = MD->getOperand(0);
+ if (Node->getNumOperands() > 1) {
+ Kernel.Language = "OpenCL C";
+ uint16_t Major = mdconst::extract<ConstantInt>(Node->getOperand(0))
+ ->getZExtValue();
+ uint16_t Minor = mdconst::extract<ConstantInt>(Node->getOperand(1))
+ ->getZExtValue();
+ Kernel.LanguageVersion.push_back(Major);
+ Kernel.LanguageVersion.push_back(Minor);
+ }
+ }
+ }
+
+ const DataLayout &DL = F.getParent()->getDataLayout();
+ for (auto &Arg : F.args()) {
+ unsigned I = Arg.getArgNo();
+ Type *T = Arg.getType();
+ auto TypeName = dyn_cast<MDString>(F.getMetadata(
+ "kernel_arg_type")->getOperand(I))->getString();
+ auto BaseTypeName = cast<MDString>(F.getMetadata(
+ "kernel_arg_base_type")->getOperand(I))->getString();
+ StringRef ArgName;
+ if (auto ArgNameMD = F.getMetadata("kernel_arg_name"))
+ ArgName = cast<MDString>(ArgNameMD->getOperand(I))->getString();
+ auto TypeQual = cast<MDString>(F.getMetadata(
+ "kernel_arg_type_qual")->getOperand(I))->getString();
+ auto AccQual = cast<MDString>(F.getMetadata(
+ "kernel_arg_access_qual")->getOperand(I))->getString();
+ KernelArg::Kind Kind;
+ if (TypeQual.find("pipe") != StringRef::npos)
+ Kind = KernelArg::Pipe;
+ else Kind = StringSwitch<KernelArg::Kind>(BaseTypeName)
+ .Case("sampler_t", KernelArg::Sampler)
+ .Case("queue_t", KernelArg::Queue)
+ .Cases("image1d_t", "image1d_array_t", "image1d_buffer_t",
+ "image2d_t" , "image2d_array_t", KernelArg::Image)
+ .Cases("image2d_depth_t", "image2d_array_depth_t",
+ "image2d_msaa_t", "image2d_array_msaa_t",
+ "image2d_msaa_depth_t", KernelArg::Image)
+ .Cases("image2d_array_msaa_depth_t", "image3d_t",
+ KernelArg::Image)
+ .Default(isa<PointerType>(T) ?
+ (T->getPointerAddressSpace() == AMDGPUAS::LOCAL_ADDRESS ?
+ KernelArg::DynamicSharedPointer :
+ KernelArg::GlobalBuffer) :
+ KernelArg::ByValue);
+ Kernel.Args.emplace_back(getRuntimeMDForKernelArg(DL, T, Kind,
+ BaseTypeName, TypeName, ArgName, TypeQual, AccQual));
+ }
+
+ // Emit hidden kernel arguments for OpenCL kernels.
+ if (F.getParent()->getNamedMetadata("opencl.ocl.version")) {
+ auto Int64T = Type::getInt64Ty(F.getContext());
+ Kernel.Args.emplace_back(getRuntimeMDForKernelArg(DL, Int64T,
+ KernelArg::HiddenGlobalOffsetX));
+ Kernel.Args.emplace_back(getRuntimeMDForKernelArg(DL, Int64T,
+ KernelArg::HiddenGlobalOffsetY));
+ Kernel.Args.emplace_back(getRuntimeMDForKernelArg(DL, Int64T,
+ KernelArg::HiddenGlobalOffsetZ));
+ if (F.getParent()->getNamedMetadata("llvm.printf.fmts")) {
+ auto Int8PtrT = Type::getInt8PtrTy(F.getContext(),
+ KernelArg::Global);
+ Kernel.Args.emplace_back(getRuntimeMDForKernelArg(DL, Int8PtrT,
+ KernelArg::HiddenPrintfBuffer));
+ }
+ }
+
+ // Set ReqdWorkGroupSize, WorkGroupSizeHint, and VecTypeHint.
+ if (auto RWGS = F.getMetadata("reqd_work_group_size"))
+ Kernel.ReqdWorkGroupSize = getThreeInt32(RWGS);
+
+ if (auto WGSH = F.getMetadata("work_group_size_hint"))
+ Kernel.WorkGroupSizeHint = getThreeInt32(WGSH);
+
+ if (auto VTH = F.getMetadata("vec_type_hint"))
+ Kernel.VecTypeHint = getOCLTypeName(cast<ValueAsMetadata>(
+ VTH->getOperand(0))->getType(), mdconst::extract<ConstantInt>(
+ VTH->getOperand(1))->getZExtValue());
+
+ return Kernel;
+}
+
+Program::Metadata::Metadata(const std::string &YAML) {
+ yaml::Input Input(YAML);
+ Input >> *this;
+}
+
+std::string Program::Metadata::toYAML(void) {
+ std::string Text;
+ raw_string_ostream Stream(Text);
+ yaml::Output Output(Stream, nullptr, INT_MAX /* do not wrap line */);
+ Output << *this;
+ return Stream.str();
+}
+
+Program::Metadata Program::Metadata::fromYAML(const std::string &S) {
+ return Program::Metadata(S);
+}
+
+// Check if the YAML string can be parsed.
+static void checkRuntimeMDYAMLString(const std::string &YAML) {
+ auto P = Program::Metadata::fromYAML(YAML);
+ auto S = P.toYAML();
+ llvm::errs() << "AMDGPU runtime metadata parser test "
+ << (YAML == S ? "passes" : "fails") << ".\n";
+ if (YAML != S) {
+ llvm::errs() << "First output: " << YAML << '\n'
+ << "Second output: " << S << '\n';
+ }
+}
+
+std::string llvm::getRuntimeMDYAMLString(Module &M) {
+ Program::Metadata Prog;
+ Prog.MDVersionSeq.push_back(MDVersion);
+ Prog.MDVersionSeq.push_back(MDRevision);
+
+ // Set PrintfInfo.
+ if (auto MD = M.getNamedMetadata("llvm.printf.fmts")) {
+ for (unsigned I = 0; I < MD->getNumOperands(); ++I) {
+ auto Node = MD->getOperand(I);
+ if (Node->getNumOperands() > 0)
+ Prog.PrintfInfo.push_back(cast<MDString>(Node->getOperand(0))
+ ->getString());
+ }
+ }
+
+ // Set Kernels.
+ for (auto &F: M.functions()) {
+ if (!F.getMetadata("kernel_arg_type"))
+ continue;
+ Prog.Kernels.emplace_back(getRuntimeMDForKernel(F));
+ }
+
+ auto YAML = Prog.toYAML();
+
+ if (DumpRuntimeMD)
+ llvm::errs() << "AMDGPU runtime metadata:\n" << YAML << '\n';
+
+ if (CheckRuntimeMDParser)
+ checkRuntimeMDYAMLString(YAML);
+
+ return YAML;
+}
OpenPOWER on IntegriCloud