1*0fca6ea1SDimitry Andric //===--- SPIRVMetadata.cpp ---- IR Metadata Parsing Funcs -------*- C++ -*-===// 2*0fca6ea1SDimitry Andric // 3*0fca6ea1SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4*0fca6ea1SDimitry Andric // See https://llvm.org/LICENSE.txt for license information. 5*0fca6ea1SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6*0fca6ea1SDimitry Andric // 7*0fca6ea1SDimitry Andric //===----------------------------------------------------------------------===// 8*0fca6ea1SDimitry Andric // 9*0fca6ea1SDimitry Andric // This file contains functions needed for parsing LLVM IR metadata relevant 10*0fca6ea1SDimitry Andric // to the SPIR-V target. 11*0fca6ea1SDimitry Andric // 12*0fca6ea1SDimitry Andric //===----------------------------------------------------------------------===// 13*0fca6ea1SDimitry Andric 14*0fca6ea1SDimitry Andric #include "SPIRVMetadata.h" 15*0fca6ea1SDimitry Andric 16*0fca6ea1SDimitry Andric using namespace llvm; 17*0fca6ea1SDimitry Andric 18*0fca6ea1SDimitry Andric static MDString *getOCLKernelArgAttribute(const Function &F, unsigned ArgIdx, 19*0fca6ea1SDimitry Andric const StringRef AttributeName) { 20*0fca6ea1SDimitry Andric assert( 21*0fca6ea1SDimitry Andric F.getCallingConv() == CallingConv::SPIR_KERNEL && 22*0fca6ea1SDimitry Andric "Kernel attributes are attached/belong only to OpenCL kernel functions"); 23*0fca6ea1SDimitry Andric 24*0fca6ea1SDimitry Andric // Lookup the argument attribute in metadata attached to the kernel function. 25*0fca6ea1SDimitry Andric MDNode *Node = F.getMetadata(AttributeName); 26*0fca6ea1SDimitry Andric if (Node && ArgIdx < Node->getNumOperands()) 27*0fca6ea1SDimitry Andric return cast<MDString>(Node->getOperand(ArgIdx)); 28*0fca6ea1SDimitry Andric 29*0fca6ea1SDimitry Andric // Sometimes metadata containing kernel attributes is not attached to the 30*0fca6ea1SDimitry Andric // function, but can be found in the named module-level metadata instead. 31*0fca6ea1SDimitry Andric // For example: 32*0fca6ea1SDimitry Andric // !opencl.kernels = !{!0} 33*0fca6ea1SDimitry Andric // !0 = !{void ()* @someKernelFunction, !1, ...} 34*0fca6ea1SDimitry Andric // !1 = !{!"kernel_arg_addr_space", ...} 35*0fca6ea1SDimitry Andric // In this case the actual index of searched argument attribute is ArgIdx + 1, 36*0fca6ea1SDimitry Andric // since the first metadata node operand is occupied by attribute name 37*0fca6ea1SDimitry Andric // ("kernel_arg_addr_space" in the example above). 38*0fca6ea1SDimitry Andric unsigned MDArgIdx = ArgIdx + 1; 39*0fca6ea1SDimitry Andric NamedMDNode *OpenCLKernelsMD = 40*0fca6ea1SDimitry Andric F.getParent()->getNamedMetadata("opencl.kernels"); 41*0fca6ea1SDimitry Andric if (!OpenCLKernelsMD || OpenCLKernelsMD->getNumOperands() == 0) 42*0fca6ea1SDimitry Andric return nullptr; 43*0fca6ea1SDimitry Andric 44*0fca6ea1SDimitry Andric // KernelToMDNodeList contains kernel function declarations followed by 45*0fca6ea1SDimitry Andric // corresponding MDNodes for each attribute. Search only MDNodes "belonging" 46*0fca6ea1SDimitry Andric // to the currently lowered kernel function. 47*0fca6ea1SDimitry Andric MDNode *KernelToMDNodeList = OpenCLKernelsMD->getOperand(0); 48*0fca6ea1SDimitry Andric bool FoundLoweredKernelFunction = false; 49*0fca6ea1SDimitry Andric for (const MDOperand &Operand : KernelToMDNodeList->operands()) { 50*0fca6ea1SDimitry Andric ValueAsMetadata *MaybeValue = dyn_cast<ValueAsMetadata>(Operand); 51*0fca6ea1SDimitry Andric if (MaybeValue && 52*0fca6ea1SDimitry Andric dyn_cast<Function>(MaybeValue->getValue())->getName() == F.getName()) { 53*0fca6ea1SDimitry Andric FoundLoweredKernelFunction = true; 54*0fca6ea1SDimitry Andric continue; 55*0fca6ea1SDimitry Andric } 56*0fca6ea1SDimitry Andric if (MaybeValue && FoundLoweredKernelFunction) 57*0fca6ea1SDimitry Andric return nullptr; 58*0fca6ea1SDimitry Andric 59*0fca6ea1SDimitry Andric MDNode *MaybeNode = dyn_cast<MDNode>(Operand); 60*0fca6ea1SDimitry Andric if (FoundLoweredKernelFunction && MaybeNode && 61*0fca6ea1SDimitry Andric cast<MDString>(MaybeNode->getOperand(0))->getString() == 62*0fca6ea1SDimitry Andric AttributeName && 63*0fca6ea1SDimitry Andric MDArgIdx < MaybeNode->getNumOperands()) 64*0fca6ea1SDimitry Andric return cast<MDString>(MaybeNode->getOperand(MDArgIdx)); 65*0fca6ea1SDimitry Andric } 66*0fca6ea1SDimitry Andric return nullptr; 67*0fca6ea1SDimitry Andric } 68*0fca6ea1SDimitry Andric 69*0fca6ea1SDimitry Andric namespace llvm { 70*0fca6ea1SDimitry Andric 71*0fca6ea1SDimitry Andric MDString *getOCLKernelArgAccessQual(const Function &F, unsigned ArgIdx) { 72*0fca6ea1SDimitry Andric assert( 73*0fca6ea1SDimitry Andric F.getCallingConv() == CallingConv::SPIR_KERNEL && 74*0fca6ea1SDimitry Andric "Kernel attributes are attached/belong only to OpenCL kernel functions"); 75*0fca6ea1SDimitry Andric return getOCLKernelArgAttribute(F, ArgIdx, "kernel_arg_access_qual"); 76*0fca6ea1SDimitry Andric } 77*0fca6ea1SDimitry Andric 78*0fca6ea1SDimitry Andric MDString *getOCLKernelArgTypeQual(const Function &F, unsigned ArgIdx) { 79*0fca6ea1SDimitry Andric assert( 80*0fca6ea1SDimitry Andric F.getCallingConv() == CallingConv::SPIR_KERNEL && 81*0fca6ea1SDimitry Andric "Kernel attributes are attached/belong only to OpenCL kernel functions"); 82*0fca6ea1SDimitry Andric return getOCLKernelArgAttribute(F, ArgIdx, "kernel_arg_type_qual"); 83*0fca6ea1SDimitry Andric } 84*0fca6ea1SDimitry Andric 85*0fca6ea1SDimitry Andric } // namespace llvm 86