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