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