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 | |
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(Kind: AttributeName); |
26 | if (Node && ArgIdx < Node->getNumOperands()) |
27 | return cast<MDString>(Val: Node->getOperand(I: 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(Name: "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(i: 0); |
48 | bool FoundLoweredKernelFunction = false; |
49 | for (const MDOperand &Operand : KernelToMDNodeList->operands()) { |
50 | ValueAsMetadata *MaybeValue = dyn_cast<ValueAsMetadata>(Val: Operand); |
51 | if (MaybeValue && |
52 | dyn_cast<Function>(Val: 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>(Val: Operand); |
60 | if (FoundLoweredKernelFunction && MaybeNode && |
61 | cast<MDString>(Val: MaybeNode->getOperand(I: 0))->getString() == |
62 | AttributeName && |
63 | MDArgIdx < MaybeNode->getNumOperands()) |
64 | return cast<MDString>(Val: MaybeNode->getOperand(I: MDArgIdx)); |
65 | } |
66 | return nullptr; |
67 | } |
68 | |
69 | namespace llvm { |
70 | |
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, AttributeName: "kernel_arg_access_qual" ); |
76 | } |
77 | |
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, AttributeName: "kernel_arg_type_qual" ); |
83 | } |
84 | |
85 | } // namespace llvm |
86 | |