From d7c5f99bd910a681b907815ebd44ef319ff417c4 Mon Sep 17 00:00:00 2001 From: nrudenko Date: Mon, 1 Jun 2020 15:27:27 +0300 Subject: [PATCH] Add list of vector compute metadata to GenXMetadata.h Add GenXSPIRVWriterAdaptor and GenXSPIRVReaderAdaptor --- .../llvm/GenXIntrinsics/GenXMetadata.h | 20 +- .../GenXIntrinsics/GenXSPIRVReaderAdaptor.h | 57 +++++ .../GenXIntrinsics/GenXSPIRVWriterAdaptor.h | 57 +++++ .../lib/GenXIntrinsics/CMakeLists.txt | 4 + .../GenXIntrinsics/GenXSPIRVReaderAdaptor.cpp | 181 +++++++++++++++ .../GenXIntrinsics/GenXSPIRVWriterAdaptor.cpp | 209 ++++++++++++++++++ 6 files changed, 527 insertions(+), 1 deletion(-) create mode 100755 GenXIntrinsics/include/llvm/GenXIntrinsics/GenXSPIRVReaderAdaptor.h create mode 100755 GenXIntrinsics/include/llvm/GenXIntrinsics/GenXSPIRVWriterAdaptor.h create mode 100755 GenXIntrinsics/lib/GenXIntrinsics/GenXSPIRVReaderAdaptor.cpp create mode 100755 GenXIntrinsics/lib/GenXIntrinsics/GenXSPIRVWriterAdaptor.cpp diff --git a/GenXIntrinsics/include/llvm/GenXIntrinsics/GenXMetadata.h b/GenXIntrinsics/include/llvm/GenXIntrinsics/GenXMetadata.h index 664d6860..0f5a627d 100644 --- a/GenXIntrinsics/include/llvm/GenXIntrinsics/GenXMetadata.h +++ b/GenXIntrinsics/include/llvm/GenXIntrinsics/GenXMetadata.h @@ -47,12 +47,30 @@ const static char OCLRuntime[] = "oclrt"; const static char ReferencedIndirectly[] = "referenced-indirectly"; } // namespace FunctionMD +namespace VCModuleMD { +const static char VCGlobalVariable[] = "VCGlobalVariable"; +const static char VCVolatile[] = "VCVolatile"; +const static char VCByteOffset[] = "VCByteOffset"; +} // namespace VCModuleMD + +namespace VCFunctionMD { +const static char VCFunction[] = "VCFunction"; +const static char VCStackCall[] = "VCStackCall"; +const static char VCArgumentIOKind[] = "VCArgumentIOKind"; +const static char VCFloatControl[] = "VCFloatControl"; +const static char VCSLMSize[] = "VCSLMSize"; +const static char VCArgumentKind[] = "VCArgumentKind"; +const static char VCArgumentDesc[] = "VCArgumentDesc"; +} // namespace VCFunctionMD + namespace SPIRVParams { const static char SPIRVMemoryModel[] = "spirv.MemoryModel"; +const static char SPIRVSIMDSubgroupSize[] = "intel_reqd_sub_group_size"; const static unsigned SPIRVMemoryModelSimple = 0; +const static unsigned SPIRVMemoryModelOCL = 2; const static unsigned SPIRVAddressingModel32 = 1; const static unsigned SPIRVAddressingModel64 = 2; -} // namespace SPIRVMD +} // namespace SPIRVParams enum KernelMDOp { FunctionRef, // Reference to Function diff --git a/GenXIntrinsics/include/llvm/GenXIntrinsics/GenXSPIRVReaderAdaptor.h b/GenXIntrinsics/include/llvm/GenXIntrinsics/GenXSPIRVReaderAdaptor.h new file mode 100755 index 00000000..947fd43f --- /dev/null +++ b/GenXIntrinsics/include/llvm/GenXIntrinsics/GenXSPIRVReaderAdaptor.h @@ -0,0 +1,57 @@ +/*===================== begin_copyright_notice ================================== + +Copyright (c) 2017 Intel Corporation + +Permission is hereby granted, free of charge, to any person obtaining a +copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + +======================= end_copyright_notice ==================================*/ +/// +/// GenXSPIRVReaderAdaptor +/// --------------------------- +/// This pass converts metadata from SPIRV format to whichever used in backend + +#include "llvm/ADT/StringRef.h" +#include "llvm/Pass.h" + +namespace llvm { +namespace genx { +class GenXSPIRVReaderAdaptor final : public ModulePass { + +public: + static char ID; + explicit GenXSPIRVReaderAdaptor() : ModulePass(ID) {} + llvm::StringRef getPassName() const override { + return "GenX SPIRVReader Adaptor"; + } + void getAnalysisUsage(AnalysisUsage &AU) const override; + bool runOnModule(Module &M) override; + +private: + bool runOnFunction(Function &F); +}; + +} // namespace genx +} // namespace llvm + +namespace llvm { +void initializeGenXSPIRVReaderAdaptorPass(PassRegistry &); +ModulePass *createGenXSPIRVReaderAdaptorPass(); +} // namespace llvm diff --git a/GenXIntrinsics/include/llvm/GenXIntrinsics/GenXSPIRVWriterAdaptor.h b/GenXIntrinsics/include/llvm/GenXIntrinsics/GenXSPIRVWriterAdaptor.h new file mode 100755 index 00000000..404f9b2a --- /dev/null +++ b/GenXIntrinsics/include/llvm/GenXIntrinsics/GenXSPIRVWriterAdaptor.h @@ -0,0 +1,57 @@ +/*===================== begin_copyright_notice ================================== + +Copyright (c) 2017 Intel Corporation + +Permission is hereby granted, free of charge, to any person obtaining a +copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + +======================= end_copyright_notice ==================================*/ +/// +/// GenXSPIRVWriterAdaptor +/// --------------------------- +/// This pass converts metadata to SPIRV format from whichever used in frontend + +#include "llvm/ADT/StringRef.h" +#include "llvm/Pass.h" + +namespace llvm { +namespace genx { +class GenXSPIRVWriterAdaptor final : public ModulePass { + +public: + static char ID; + explicit GenXSPIRVWriterAdaptor() : ModulePass(ID) {} + llvm::StringRef getPassName() const override { + return "GenX SPIRVWriter Adaptor"; + } + void getAnalysisUsage(AnalysisUsage &AU) const override; + bool runOnModule(Module &M) override; + +private: + bool runOnFunction(Function &F); +}; + +} // namespace genx +} // namespace llvm + +namespace llvm { +void initializeGenXSPIRVWriterAdaptorPass(PassRegistry &); +ModulePass *createGenXSPIRVWriterAdaptorPass(); +} // namespace llvm diff --git a/GenXIntrinsics/lib/GenXIntrinsics/CMakeLists.txt b/GenXIntrinsics/lib/GenXIntrinsics/CMakeLists.txt index 521069b4..0604611b 100755 --- a/GenXIntrinsics/lib/GenXIntrinsics/CMakeLists.txt +++ b/GenXIntrinsics/lib/GenXIntrinsics/CMakeLists.txt @@ -3,6 +3,8 @@ if(BUILD_EXTERNAL) GenXIntrinsics.cpp GenXRestoreIntrAttr.cpp GenXSimdCFLowering.cpp + GenXSPIRVReaderAdaptor.cpp + GenXSPIRVWriterAdaptor.cpp ) llvm_update_compile_flags(LLVMGenXIntrinsics) add_dependencies(LLVMGenXIntrinsics GenXIntrinsicsGen) @@ -21,6 +23,8 @@ else() GenXIntrinsics.cpp GenXRestoreIntrAttr.cpp GenXSimdCFLowering.cpp + GenXSPIRVReaderAdaptor.cpp + GenXSPIRVWriterAdaptor.cpp ADDITIONAL_HEADER_DIRS ${GENX_INTRINSICS_MAIN_INCLUDE_DIR}/llvm/GenXIntrinsics diff --git a/GenXIntrinsics/lib/GenXIntrinsics/GenXSPIRVReaderAdaptor.cpp b/GenXIntrinsics/lib/GenXIntrinsics/GenXSPIRVReaderAdaptor.cpp new file mode 100755 index 00000000..8cb0b5d4 --- /dev/null +++ b/GenXIntrinsics/lib/GenXIntrinsics/GenXSPIRVReaderAdaptor.cpp @@ -0,0 +1,181 @@ +/*===================== begin_copyright_notice ================================== + +Copyright (c) 2017 Intel Corporation + +Permission is hereby granted, free of charge, to any person obtaining a +copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + +======================= end_copyright_notice ==================================*/ +/// +/// GenXSPIRVReaderAdaptor +/// --------------------------- +/// This pass converts metadata from SPIRV format to whichever used in backend + +#include "llvm/GenXIntrinsics/GenXSPIRVReaderAdaptor.h" +#include "llvm/GenXIntrinsics/GenXMetadata.h" +#include "llvm/IR/Constants.h" +#include "llvm/IR/Function.h" +#include "llvm/IR/Metadata.h" +#include "llvm/IR/Module.h" + +using namespace llvm; +using namespace genx; + +char GenXSPIRVReaderAdaptor::ID = 0; + +INITIALIZE_PASS_BEGIN(GenXSPIRVReaderAdaptor, "GenXSPIRVReaderAdaptor", + "GenXSPIRVReaderAdaptor", false, false) +INITIALIZE_PASS_END(GenXSPIRVReaderAdaptor, "GenXSPIRVReaderAdaptor", + "GenXSPIRVReaderAdaptor", false, false) + +ModulePass *llvm::createGenXSPIRVReaderAdaptorPass() { + return new GenXSPIRVReaderAdaptor(); +} + +void GenXSPIRVReaderAdaptor::getAnalysisUsage(AnalysisUsage &AU) const { + AU.setPreservesCFG(); +} + +bool GenXSPIRVReaderAdaptor::runOnModule(Module &M) { + auto TargetTriple = StringRef(M.getTargetTriple()); + if (TargetTriple.startswith("spir")) { + if (TargetTriple.startswith("spir64")) + M.setTargetTriple("genx64"); + else + M.setTargetTriple("genx"); + } + + for (auto &&GV : M.getGlobalList()) { + if (!GV.hasAttribute(VCModuleMD::VCGlobalVariable)) + continue; + if (GV.hasAttribute(VCModuleMD::VCVolatile)) + GV.addAttribute(FunctionMD::GenXVolatile); + if (GV.hasAttribute(VCModuleMD::VCByteOffset)) { + auto Offset = + GV.getAttribute(VCModuleMD::VCByteOffset).getValueAsString(); + GV.addAttribute(FunctionMD::GenXByteOffset, Offset); + } + } + + for (auto &&F : M) + runOnFunction(F); + + return true; +} + +bool GenXSPIRVReaderAdaptor::runOnFunction(Function &F) { + auto Attrs = F.getAttributes(); + if (!Attrs.hasFnAttribute(VCFunctionMD::VCFunction)) + return true; + + if (Attrs.hasFnAttribute(VCFunctionMD::VCStackCall)) { + F.addFnAttr(FunctionMD::CMStackCall); + F.addFnAttr(Attribute::NoInline); + } + + auto &&Context = F.getContext(); + if (Attrs.hasFnAttribute(VCFunctionMD::VCFloatControl)) { + auto FloatControl = unsigned(0); + Attrs + .getAttribute(AttributeList::FunctionIndex, + VCFunctionMD::VCFloatControl) + .getValueAsString() + .getAsInteger(0, FloatControl); + + auto Attr = Attribute::get(Context, FunctionMD::CMFloatControl, + std::to_string(FloatControl)); + F.addAttribute(AttributeList::FunctionIndex, Attr); + } + + if (auto *ReqdSubgroupSize = + F.getMetadata(SPIRVParams::SPIRVSIMDSubgroupSize)) { + auto SIMDSize = + mdconst::dyn_extract(ReqdSubgroupSize->getOperand(0)) + ->getZExtValue(); + Attribute Attr = Attribute::get(Context, FunctionMD::OCLRuntime, + std::to_string(SIMDSize)); + F.addAttribute(AttributeList::FunctionIndex, Attr); + } + + if (!(F.getCallingConv() == CallingConv::SPIR_KERNEL)) + return true; + F.addFnAttr(FunctionMD::CMGenXMain); + F.setDLLStorageClass(llvm::GlobalVariable::DLLExportStorageClass); + + auto *FunctionRef = ValueAsMetadata::get(&F); + auto KernelName = F.getName(); + auto ArgKinds = llvm::SmallVector(); + auto SLMSize = unsigned(0); + auto ArgOffset = unsigned(0); + auto ArgIOKinds = llvm::SmallVector(); + auto ArgDescs = llvm::SmallVector(); + + llvm::Type *I32Ty = llvm::Type::getInt32Ty(Context); + + if (Attrs.hasFnAttribute(VCFunctionMD::VCSLMSize)) { + Attrs.getAttribute(AttributeList::FunctionIndex, VCFunctionMD::VCSLMSize) + .getValueAsString() + .getAsInteger(0, SLMSize); + } + + for (Function::arg_iterator I = F.arg_begin(), E = F.arg_end(); I != E; ++I) { + auto ArgNo = I->getArgNo(); + auto ArgKind = unsigned(0); + auto ArgIOKind = unsigned(0); + auto ArgDesc = std::string(); + if (Attrs.hasAttribute(ArgNo + 1, VCFunctionMD::VCArgumentKind)) { + Attrs.getAttribute(ArgNo + 1, VCFunctionMD::VCArgumentKind) + .getValueAsString() + .getAsInteger(0, ArgKind); + } + if (Attrs.hasAttribute(ArgNo + 1, VCFunctionMD::VCArgumentIOKind)) { + Attrs.getAttribute(ArgNo + 1, VCFunctionMD::VCArgumentIOKind) + .getValueAsString() + .getAsInteger(0, ArgIOKind); + } + if (Attrs.hasAttribute(ArgNo + 1, VCFunctionMD::VCArgumentDesc)) { + ArgDesc = Attrs.getAttribute(ArgNo + 1, VCFunctionMD::VCArgumentDesc) + .getValueAsString() + .str(); + } + ArgKinds.push_back( + llvm::ValueAsMetadata::get(llvm::ConstantInt::get(I32Ty, ArgKind))); + ArgIOKinds.push_back( + llvm::ValueAsMetadata::get(llvm::ConstantInt::get(I32Ty, ArgIOKind))); + ArgDescs.push_back(llvm::MDString::get(Context, ArgDesc)); + } + + auto KernelMD = std::vector(); + KernelMD.push_back(FunctionRef); + KernelMD.push_back(llvm::MDString::get(Context, KernelName)); + KernelMD.push_back(llvm::MDNode::get(Context, ArgKinds)); + KernelMD.push_back(ConstantAsMetadata::get(ConstantInt::get(I32Ty, SLMSize))); + KernelMD.push_back( + ConstantAsMetadata::get(ConstantInt::get(I32Ty, ArgOffset))); + KernelMD.push_back(llvm::MDNode::get(Context, ArgIOKinds)); + KernelMD.push_back(llvm::MDNode::get(Context, ArgDescs)); + KernelMD.push_back(ConstantAsMetadata::get(ConstantInt::get(I32Ty, 0))); + + NamedMDNode *KernelMDs = + F.getParent()->getOrInsertNamedMetadata(FunctionMD::GenXKernels); + llvm::MDNode *Node = MDNode::get(F.getContext(), KernelMD); + KernelMDs->addOperand(Node); + return true; +} diff --git a/GenXIntrinsics/lib/GenXIntrinsics/GenXSPIRVWriterAdaptor.cpp b/GenXIntrinsics/lib/GenXIntrinsics/GenXSPIRVWriterAdaptor.cpp new file mode 100755 index 00000000..c7b29960 --- /dev/null +++ b/GenXIntrinsics/lib/GenXIntrinsics/GenXSPIRVWriterAdaptor.cpp @@ -0,0 +1,209 @@ +/*===================== begin_copyright_notice ================================== + +Copyright (c) 2017 Intel Corporation + +Permission is hereby granted, free of charge, to any person obtaining a +copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + +======================= end_copyright_notice ==================================*/ +/// +/// GenXSPIRVWriterAdaptor +/// --------------------------- +/// This pass converts metadata to SPIRV format from whichever used in frontend + +#include "llvm/GenXIntrinsics/GenXSPIRVWriterAdaptor.h" +#include "llvm/GenXIntrinsics/GenXIntrinsics.h" +#include "llvm/GenXIntrinsics/GenXMetadata.h" +#include "llvm/IR/Constants.h" +#include "llvm/IR/Function.h" +#include "llvm/IR/Metadata.h" +#include "llvm/IR/Module.h" + +using namespace llvm; +using namespace genx; + +char GenXSPIRVWriterAdaptor::ID = 0; + +INITIALIZE_PASS_BEGIN(GenXSPIRVWriterAdaptor, "GenXSPIRVWriterAdaptor", + "GenXSPIRVWriterAdaptor", false, false) +INITIALIZE_PASS_END(GenXSPIRVWriterAdaptor, "GenXSPIRVWriterAdaptor", + "GenXSPIRVWriterAdaptor", false, false) + +ModulePass *llvm::createGenXSPIRVWriterAdaptorPass() { + return new GenXSPIRVWriterAdaptor(); +} + +void GenXSPIRVWriterAdaptor::getAnalysisUsage(AnalysisUsage &AU) const { + AU.setPreservesCFG(); +} + +bool GenXSPIRVWriterAdaptor::runOnModule(Module &M) { + + auto TargetTriple = StringRef(M.getTargetTriple()); + if (!M.getNamedMetadata(SPIRVParams::SPIRVMemoryModel)) { + // TODO: remove this block when finally transferred to open source + auto &&Context = M.getContext(); + auto AddressingModel = TargetTriple.startswith("genx64") + ? SPIRVParams::SPIRVAddressingModel64 + : SPIRVParams::SPIRVAddressingModel32; + auto *MemoryModelMD = + M.getOrInsertNamedMetadata(SPIRVParams::SPIRVMemoryModel); + auto ValueVec = std::vector(); + ValueVec.push_back(ConstantAsMetadata::get( + ConstantInt::get(Type::getInt32Ty(Context), AddressingModel))); + ValueVec.push_back(ConstantAsMetadata::get(ConstantInt::get( + Type::getInt32Ty(Context), SPIRVParams::SPIRVMemoryModelSimple))); + MemoryModelMD->addOperand(MDNode::get(Context, ValueVec)); + } + if (TargetTriple.startswith("genx")) { + if (TargetTriple.startswith("genx64")) + M.setTargetTriple("spir64"); + else + M.setTargetTriple("spir"); + } + + for (auto &&GV : M.getGlobalList()) { + GV.addAttribute(VCModuleMD::VCGlobalVariable); + if (GV.hasAttribute(FunctionMD::GenXVolatile)) + GV.addAttribute(VCModuleMD::VCVolatile); + if (GV.hasAttribute(FunctionMD::GenXByteOffset)) { + auto Offset = + GV.getAttribute(FunctionMD::GenXByteOffset).getValueAsString(); + GV.addAttribute(VCModuleMD::VCByteOffset, Offset); + } + } + + for (auto &&F : M) + runOnFunction(F); + + return true; +} + +bool GenXSPIRVWriterAdaptor::runOnFunction(Function &F) { + if (F.isIntrinsic() && !GenXIntrinsic::isGenXIntrinsic(&F)) + return true; + F.addFnAttr(VCFunctionMD::VCFunction); + + auto Attrs = F.getAttributes(); + if (Attrs.hasFnAttribute(FunctionMD::CMStackCall)) { + F.addFnAttr(VCFunctionMD::VCStackCall); + } + + auto &&Context = F.getContext(); + if (Attrs.hasFnAttribute(FunctionMD::CMFloatControl)) { + auto FloatControl = unsigned(0); + Attrs.getAttribute(AttributeList::FunctionIndex, FunctionMD::CMFloatControl) + .getValueAsString() + .getAsInteger(0, FloatControl); + + auto Attr = Attribute::get(Context, VCFunctionMD::VCFloatControl, + std::to_string(FloatControl)); + F.addAttribute(AttributeList::FunctionIndex, Attr); + } + + auto *KernelMDs = F.getParent()->getNamedMetadata(FunctionMD::GenXKernels); + if (!KernelMDs) + return true; + + if (Attrs.hasFnAttribute(FunctionMD::OCLRuntime)) { + auto SIMDSize = unsigned(0); + Attrs.getAttribute(AttributeList::FunctionIndex, FunctionMD::OCLRuntime) + .getValueAsString() + .getAsInteger(0, SIMDSize); + auto SizeMD = ConstantAsMetadata::get( + llvm::ConstantInt::get(llvm::Type::getInt32Ty(Context), SIMDSize)); + F.setMetadata(SPIRVParams::SPIRVSIMDSubgroupSize, + MDNode::get(Context, SizeMD)); + } + + auto *KernelMD = static_cast(nullptr); + for (unsigned I = 0, E = KernelMDs->getNumOperands(); I < E; ++I) { + auto *Kernel = mdconst::dyn_extract( + KernelMDs->getOperand(I)->getOperand(KernelMDOp::FunctionRef)); + if (Kernel == &F) { + KernelMD = KernelMDs->getOperand(I); + break; + } + } + if (!KernelMD) + return true; + + F.setCallingConv(CallingConv::SPIR_KERNEL); + + if (KernelMD->getNumOperands() > KernelMDOp::ArgKinds) { + if (auto *KindsNode = + dyn_cast(KernelMD->getOperand(KernelMDOp::ArgKinds))) { + for (unsigned ArgNo = 0, e = KindsNode->getNumOperands(); ArgNo != e; + ++ArgNo) { + if (auto *VM = dyn_cast(KindsNode->getOperand(ArgNo))) + if (auto *V = dyn_cast(VM->getValue())) { + auto ArgKind = V->getZExtValue(); + auto Attr = Attribute::get(Context, VCFunctionMD::VCArgumentKind, + std::to_string(ArgKind)); + F.addAttribute(ArgNo + 1, Attr); + } + } + } + } + + if (KernelMD->getNumOperands() > KernelMDOp::SLMSize) { + if (auto *VM = dyn_cast( + KernelMD->getOperand(KernelMDOp::SLMSize))) + if (auto *V = dyn_cast(VM->getValue())) { + auto SLMSize = V->getZExtValue(); + auto Attr = Attribute::get(Context, VCFunctionMD::VCSLMSize, + std::to_string(SLMSize)); + F.addAttribute(AttributeList::FunctionIndex, Attr); + } + } + + if (KernelMD->getNumOperands() > KernelMDOp::ArgIOKinds) { + if (auto *KindsNode = + dyn_cast(KernelMD->getOperand(KernelMDOp::ArgIOKinds))) { + for (unsigned ArgNo = 0, e = KindsNode->getNumOperands(); ArgNo != e; + ++ArgNo) { + if (auto *VM = dyn_cast(KindsNode->getOperand(ArgNo))) + if (auto *V = dyn_cast(VM->getValue())) { + auto ArgKind = V->getZExtValue(); + auto Attr = Attribute::get(Context, VCFunctionMD::VCArgumentIOKind, + std::to_string(ArgKind)); + F.addAttribute(ArgNo + 1, Attr); + } + } + } + } + + if (KernelMD->getNumOperands() > KernelMDOp::ArgTypeDescs) { + if (auto Node = + dyn_cast(KernelMD->getOperand(KernelMDOp::ArgTypeDescs))) { + for (unsigned ArgNo = 0, e = Node->getNumOperands(); ArgNo != e; + ++ArgNo) { + if (auto *MS = dyn_cast(Node->getOperand(ArgNo))) { + auto &&Desc = MS->getString(); + auto Attr = + Attribute::get(Context, VCFunctionMD::VCArgumentDesc, Desc); + F.addAttribute(ArgNo + 1, Attr); + } + } + } + } + + return true; +}