xref: /freebsd-src/contrib/llvm-project/llvm/lib/Target/SPIRV/SPIRVMetadata.cpp (revision 0fca6ea1d4eea4c934cfff25ac9ee8ad6fe95583)
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