1f5b36e56SScott Linder //===- AMDGPUMetadataVerifier.cpp - MsgPack Types ---------------*- C++ -*-===//
2f5b36e56SScott Linder //
32946cd70SChandler Carruth // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
42946cd70SChandler Carruth // See https://llvm.org/LICENSE.txt for license information.
52946cd70SChandler Carruth // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6f5b36e56SScott Linder //
7f5b36e56SScott Linder //===----------------------------------------------------------------------===//
8f5b36e56SScott Linder //
9f5b36e56SScott Linder /// \file
10f5b36e56SScott Linder /// Implements a verifier for AMDGPU HSA metadata.
11f5b36e56SScott Linder //
12f5b36e56SScott Linder //===----------------------------------------------------------------------===//
13f5b36e56SScott Linder 
14f5b36e56SScott Linder #include "llvm/BinaryFormat/AMDGPUMetadataVerifier.h"
15af450eabSReid Kleckner #include "llvm/ADT/StringSwitch.h"
16f5b36e56SScott Linder #include "llvm/Support/AMDGPUMetadata.h"
17f5b36e56SScott Linder 
18f5b36e56SScott Linder namespace llvm {
19f5b36e56SScott Linder namespace AMDGPU {
20f5b36e56SScott Linder namespace HSAMD {
21f5b36e56SScott Linder namespace V3 {
22f5b36e56SScott Linder 
23f5b36e56SScott Linder bool MetadataVerifier::verifyScalar(
24ed0b9af9STim Renouf     msgpack::DocNode &Node, msgpack::Type SKind,
25ed0b9af9STim Renouf     function_ref<bool(msgpack::DocNode &)> verifyValue) {
26ed0b9af9STim Renouf   if (!Node.isScalar())
27f5b36e56SScott Linder     return false;
28ed0b9af9STim Renouf   if (Node.getKind() != SKind) {
29f5b36e56SScott Linder     if (Strict)
30f5b36e56SScott Linder       return false;
31f5b36e56SScott Linder     // If we are not strict, we interpret string values as "implicitly typed"
32f5b36e56SScott Linder     // and attempt to coerce them to the expected type here.
33ed0b9af9STim Renouf     if (Node.getKind() != msgpack::Type::String)
34f5b36e56SScott Linder       return false;
35ed0b9af9STim Renouf     StringRef StringValue = Node.getString();
36ed0b9af9STim Renouf     Node.fromString(StringValue);
37ed0b9af9STim Renouf     if (Node.getKind() != SKind)
38f5b36e56SScott Linder       return false;
39f5b36e56SScott Linder   }
40f5b36e56SScott Linder   if (verifyValue)
41ed0b9af9STim Renouf     return verifyValue(Node);
42f5b36e56SScott Linder   return true;
43f5b36e56SScott Linder }
44f5b36e56SScott Linder 
45ed0b9af9STim Renouf bool MetadataVerifier::verifyInteger(msgpack::DocNode &Node) {
46ed0b9af9STim Renouf   if (!verifyScalar(Node, msgpack::Type::UInt))
47ed0b9af9STim Renouf     if (!verifyScalar(Node, msgpack::Type::Int))
48f5b36e56SScott Linder       return false;
49f5b36e56SScott Linder   return true;
50f5b36e56SScott Linder }
51f5b36e56SScott Linder 
52f5b36e56SScott Linder bool MetadataVerifier::verifyArray(
53ed0b9af9STim Renouf     msgpack::DocNode &Node, function_ref<bool(msgpack::DocNode &)> verifyNode,
54f5b36e56SScott Linder     Optional<size_t> Size) {
55ed0b9af9STim Renouf   if (!Node.isArray())
56f5b36e56SScott Linder     return false;
57ed0b9af9STim Renouf   auto &Array = Node.getArray();
58f5b36e56SScott Linder   if (Size && Array.size() != *Size)
59f5b36e56SScott Linder     return false;
60*c2bb9637SKazu Hirata   return llvm::all_of(Array, verifyNode);
61f5b36e56SScott Linder }
62f5b36e56SScott Linder 
63f5b36e56SScott Linder bool MetadataVerifier::verifyEntry(
64ed0b9af9STim Renouf     msgpack::MapDocNode &MapNode, StringRef Key, bool Required,
65ed0b9af9STim Renouf     function_ref<bool(msgpack::DocNode &)> verifyNode) {
66f5b36e56SScott Linder   auto Entry = MapNode.find(Key);
67f5b36e56SScott Linder   if (Entry == MapNode.end())
68f5b36e56SScott Linder     return !Required;
69ed0b9af9STim Renouf   return verifyNode(Entry->second);
70f5b36e56SScott Linder }
71f5b36e56SScott Linder 
72f5b36e56SScott Linder bool MetadataVerifier::verifyScalarEntry(
73ed0b9af9STim Renouf     msgpack::MapDocNode &MapNode, StringRef Key, bool Required,
74ed0b9af9STim Renouf     msgpack::Type SKind,
75ed0b9af9STim Renouf     function_ref<bool(msgpack::DocNode &)> verifyValue) {
76ed0b9af9STim Renouf   return verifyEntry(MapNode, Key, Required, [=](msgpack::DocNode &Node) {
77f5b36e56SScott Linder     return verifyScalar(Node, SKind, verifyValue);
78f5b36e56SScott Linder   });
79f5b36e56SScott Linder }
80f5b36e56SScott Linder 
81ed0b9af9STim Renouf bool MetadataVerifier::verifyIntegerEntry(msgpack::MapDocNode &MapNode,
82f5b36e56SScott Linder                                           StringRef Key, bool Required) {
83ed0b9af9STim Renouf   return verifyEntry(MapNode, Key, Required, [this](msgpack::DocNode &Node) {
84f5b36e56SScott Linder     return verifyInteger(Node);
85f5b36e56SScott Linder   });
86f5b36e56SScott Linder }
87f5b36e56SScott Linder 
88ed0b9af9STim Renouf bool MetadataVerifier::verifyKernelArgs(msgpack::DocNode &Node) {
89ed0b9af9STim Renouf   if (!Node.isMap())
90f5b36e56SScott Linder     return false;
91ed0b9af9STim Renouf   auto &ArgsMap = Node.getMap();
92f5b36e56SScott Linder 
93f5b36e56SScott Linder   if (!verifyScalarEntry(ArgsMap, ".name", false,
94ed0b9af9STim Renouf                          msgpack::Type::String))
95f5b36e56SScott Linder     return false;
96f5b36e56SScott Linder   if (!verifyScalarEntry(ArgsMap, ".type_name", false,
97ed0b9af9STim Renouf                          msgpack::Type::String))
98f5b36e56SScott Linder     return false;
99f5b36e56SScott Linder   if (!verifyIntegerEntry(ArgsMap, ".size", true))
100f5b36e56SScott Linder     return false;
101f5b36e56SScott Linder   if (!verifyIntegerEntry(ArgsMap, ".offset", true))
102f5b36e56SScott Linder     return false;
103f5b36e56SScott Linder   if (!verifyScalarEntry(ArgsMap, ".value_kind", true,
104ed0b9af9STim Renouf                          msgpack::Type::String,
105ed0b9af9STim Renouf                          [](msgpack::DocNode &SNode) {
106f5b36e56SScott Linder                            return StringSwitch<bool>(SNode.getString())
107f5b36e56SScott Linder                                .Case("by_value", true)
108f5b36e56SScott Linder                                .Case("global_buffer", true)
109f5b36e56SScott Linder                                .Case("dynamic_shared_pointer", true)
110f5b36e56SScott Linder                                .Case("sampler", true)
111f5b36e56SScott Linder                                .Case("image", true)
112f5b36e56SScott Linder                                .Case("pipe", true)
113f5b36e56SScott Linder                                .Case("queue", true)
114f5b36e56SScott Linder                                .Case("hidden_global_offset_x", true)
115f5b36e56SScott Linder                                .Case("hidden_global_offset_y", true)
116f5b36e56SScott Linder                                .Case("hidden_global_offset_z", true)
117f5b36e56SScott Linder                                .Case("hidden_none", true)
118f5b36e56SScott Linder                                .Case("hidden_printf_buffer", true)
11952c5014dSSameer Sahasrabuddhe                                .Case("hidden_hostcall_buffer", true)
120f5b36e56SScott Linder                                .Case("hidden_default_queue", true)
121f5b36e56SScott Linder                                .Case("hidden_completion_action", true)
122a6241352SYaxun Liu                                .Case("hidden_multigrid_sync_arg", true)
123f5b36e56SScott Linder                                .Default(false);
124f5b36e56SScott Linder                          }))
125f5b36e56SScott Linder     return false;
126f5b36e56SScott Linder   if (!verifyIntegerEntry(ArgsMap, ".pointee_align", false))
127f5b36e56SScott Linder     return false;
128f5b36e56SScott Linder   if (!verifyScalarEntry(ArgsMap, ".address_space", false,
129ed0b9af9STim Renouf                          msgpack::Type::String,
130ed0b9af9STim Renouf                          [](msgpack::DocNode &SNode) {
131f5b36e56SScott Linder                            return StringSwitch<bool>(SNode.getString())
132f5b36e56SScott Linder                                .Case("private", true)
133f5b36e56SScott Linder                                .Case("global", true)
134f5b36e56SScott Linder                                .Case("constant", true)
135f5b36e56SScott Linder                                .Case("local", true)
136f5b36e56SScott Linder                                .Case("generic", true)
137f5b36e56SScott Linder                                .Case("region", true)
138f5b36e56SScott Linder                                .Default(false);
139f5b36e56SScott Linder                          }))
140f5b36e56SScott Linder     return false;
141f5b36e56SScott Linder   if (!verifyScalarEntry(ArgsMap, ".access", false,
142ed0b9af9STim Renouf                          msgpack::Type::String,
143ed0b9af9STim Renouf                          [](msgpack::DocNode &SNode) {
144f5b36e56SScott Linder                            return StringSwitch<bool>(SNode.getString())
145f5b36e56SScott Linder                                .Case("read_only", true)
146f5b36e56SScott Linder                                .Case("write_only", true)
147f5b36e56SScott Linder                                .Case("read_write", true)
148f5b36e56SScott Linder                                .Default(false);
149f5b36e56SScott Linder                          }))
150f5b36e56SScott Linder     return false;
151f5b36e56SScott Linder   if (!verifyScalarEntry(ArgsMap, ".actual_access", false,
152ed0b9af9STim Renouf                          msgpack::Type::String,
153ed0b9af9STim Renouf                          [](msgpack::DocNode &SNode) {
154f5b36e56SScott Linder                            return StringSwitch<bool>(SNode.getString())
155f5b36e56SScott Linder                                .Case("read_only", true)
156f5b36e56SScott Linder                                .Case("write_only", true)
157f5b36e56SScott Linder                                .Case("read_write", true)
158f5b36e56SScott Linder                                .Default(false);
159f5b36e56SScott Linder                          }))
160f5b36e56SScott Linder     return false;
161f5b36e56SScott Linder   if (!verifyScalarEntry(ArgsMap, ".is_const", false,
162ed0b9af9STim Renouf                          msgpack::Type::Boolean))
163f5b36e56SScott Linder     return false;
164f5b36e56SScott Linder   if (!verifyScalarEntry(ArgsMap, ".is_restrict", false,
165ed0b9af9STim Renouf                          msgpack::Type::Boolean))
166f5b36e56SScott Linder     return false;
167f5b36e56SScott Linder   if (!verifyScalarEntry(ArgsMap, ".is_volatile", false,
168ed0b9af9STim Renouf                          msgpack::Type::Boolean))
169f5b36e56SScott Linder     return false;
170f5b36e56SScott Linder   if (!verifyScalarEntry(ArgsMap, ".is_pipe", false,
171ed0b9af9STim Renouf                          msgpack::Type::Boolean))
172f5b36e56SScott Linder     return false;
173f5b36e56SScott Linder 
174f5b36e56SScott Linder   return true;
175f5b36e56SScott Linder }
176f5b36e56SScott Linder 
177ed0b9af9STim Renouf bool MetadataVerifier::verifyKernel(msgpack::DocNode &Node) {
178ed0b9af9STim Renouf   if (!Node.isMap())
179f5b36e56SScott Linder     return false;
180ed0b9af9STim Renouf   auto &KernelMap = Node.getMap();
181f5b36e56SScott Linder 
182f5b36e56SScott Linder   if (!verifyScalarEntry(KernelMap, ".name", true,
183ed0b9af9STim Renouf                          msgpack::Type::String))
184f5b36e56SScott Linder     return false;
185f5b36e56SScott Linder   if (!verifyScalarEntry(KernelMap, ".symbol", true,
186ed0b9af9STim Renouf                          msgpack::Type::String))
187f5b36e56SScott Linder     return false;
188f5b36e56SScott Linder   if (!verifyScalarEntry(KernelMap, ".language", false,
189ed0b9af9STim Renouf                          msgpack::Type::String,
190ed0b9af9STim Renouf                          [](msgpack::DocNode &SNode) {
191f5b36e56SScott Linder                            return StringSwitch<bool>(SNode.getString())
192f5b36e56SScott Linder                                .Case("OpenCL C", true)
193f5b36e56SScott Linder                                .Case("OpenCL C++", true)
194f5b36e56SScott Linder                                .Case("HCC", true)
195f5b36e56SScott Linder                                .Case("HIP", true)
196f5b36e56SScott Linder                                .Case("OpenMP", true)
197f5b36e56SScott Linder                                .Case("Assembler", true)
198f5b36e56SScott Linder                                .Default(false);
199f5b36e56SScott Linder                          }))
200f5b36e56SScott Linder     return false;
201f5b36e56SScott Linder   if (!verifyEntry(
202ed0b9af9STim Renouf           KernelMap, ".language_version", false, [this](msgpack::DocNode &Node) {
203f5b36e56SScott Linder             return verifyArray(
204f5b36e56SScott Linder                 Node,
205ed0b9af9STim Renouf                 [this](msgpack::DocNode &Node) { return verifyInteger(Node); }, 2);
206f5b36e56SScott Linder           }))
207f5b36e56SScott Linder     return false;
208ed0b9af9STim Renouf   if (!verifyEntry(KernelMap, ".args", false, [this](msgpack::DocNode &Node) {
209ed0b9af9STim Renouf         return verifyArray(Node, [this](msgpack::DocNode &Node) {
210f5b36e56SScott Linder           return verifyKernelArgs(Node);
211f5b36e56SScott Linder         });
212f5b36e56SScott Linder       }))
213f5b36e56SScott Linder     return false;
214f5b36e56SScott Linder   if (!verifyEntry(KernelMap, ".reqd_workgroup_size", false,
215ed0b9af9STim Renouf                    [this](msgpack::DocNode &Node) {
216f5b36e56SScott Linder                      return verifyArray(Node,
217ed0b9af9STim Renouf                                         [this](msgpack::DocNode &Node) {
218f5b36e56SScott Linder                                           return verifyInteger(Node);
219f5b36e56SScott Linder                                         },
220f5b36e56SScott Linder                                         3);
221f5b36e56SScott Linder                    }))
222f5b36e56SScott Linder     return false;
223f5b36e56SScott Linder   if (!verifyEntry(KernelMap, ".workgroup_size_hint", false,
224ed0b9af9STim Renouf                    [this](msgpack::DocNode &Node) {
225f5b36e56SScott Linder                      return verifyArray(Node,
226ed0b9af9STim Renouf                                         [this](msgpack::DocNode &Node) {
227f5b36e56SScott Linder                                           return verifyInteger(Node);
228f5b36e56SScott Linder                                         },
229f5b36e56SScott Linder                                         3);
230f5b36e56SScott Linder                    }))
231f5b36e56SScott Linder     return false;
232f5b36e56SScott Linder   if (!verifyScalarEntry(KernelMap, ".vec_type_hint", false,
233ed0b9af9STim Renouf                          msgpack::Type::String))
234f5b36e56SScott Linder     return false;
235f5b36e56SScott Linder   if (!verifyScalarEntry(KernelMap, ".device_enqueue_symbol", false,
236ed0b9af9STim Renouf                          msgpack::Type::String))
237f5b36e56SScott Linder     return false;
238f5b36e56SScott Linder   if (!verifyIntegerEntry(KernelMap, ".kernarg_segment_size", true))
239f5b36e56SScott Linder     return false;
240f5b36e56SScott Linder   if (!verifyIntegerEntry(KernelMap, ".group_segment_fixed_size", true))
241f5b36e56SScott Linder     return false;
242f5b36e56SScott Linder   if (!verifyIntegerEntry(KernelMap, ".private_segment_fixed_size", true))
243f5b36e56SScott Linder     return false;
244f5b36e56SScott Linder   if (!verifyIntegerEntry(KernelMap, ".kernarg_segment_align", true))
245f5b36e56SScott Linder     return false;
246f5b36e56SScott Linder   if (!verifyIntegerEntry(KernelMap, ".wavefront_size", true))
247f5b36e56SScott Linder     return false;
248f5b36e56SScott Linder   if (!verifyIntegerEntry(KernelMap, ".sgpr_count", true))
249f5b36e56SScott Linder     return false;
250f5b36e56SScott Linder   if (!verifyIntegerEntry(KernelMap, ".vgpr_count", true))
251f5b36e56SScott Linder     return false;
252f5b36e56SScott Linder   if (!verifyIntegerEntry(KernelMap, ".max_flat_workgroup_size", true))
253f5b36e56SScott Linder     return false;
254f5b36e56SScott Linder   if (!verifyIntegerEntry(KernelMap, ".sgpr_spill_count", false))
255f5b36e56SScott Linder     return false;
256f5b36e56SScott Linder   if (!verifyIntegerEntry(KernelMap, ".vgpr_spill_count", false))
257f5b36e56SScott Linder     return false;
258f5b36e56SScott Linder 
259f5b36e56SScott Linder   return true;
260f5b36e56SScott Linder }
261f5b36e56SScott Linder 
262ed0b9af9STim Renouf bool MetadataVerifier::verify(msgpack::DocNode &HSAMetadataRoot) {
263ed0b9af9STim Renouf   if (!HSAMetadataRoot.isMap())
264f5b36e56SScott Linder     return false;
265ed0b9af9STim Renouf   auto &RootMap = HSAMetadataRoot.getMap();
266f5b36e56SScott Linder 
267f5b36e56SScott Linder   if (!verifyEntry(
268ed0b9af9STim Renouf           RootMap, "amdhsa.version", true, [this](msgpack::DocNode &Node) {
269f5b36e56SScott Linder             return verifyArray(
270f5b36e56SScott Linder                 Node,
271ed0b9af9STim Renouf                 [this](msgpack::DocNode &Node) { return verifyInteger(Node); }, 2);
272f5b36e56SScott Linder           }))
273f5b36e56SScott Linder     return false;
274f5b36e56SScott Linder   if (!verifyEntry(
275ed0b9af9STim Renouf           RootMap, "amdhsa.printf", false, [this](msgpack::DocNode &Node) {
276ed0b9af9STim Renouf             return verifyArray(Node, [this](msgpack::DocNode &Node) {
277ed0b9af9STim Renouf               return verifyScalar(Node, msgpack::Type::String);
278f5b36e56SScott Linder             });
279f5b36e56SScott Linder           }))
280f5b36e56SScott Linder     return false;
281f5b36e56SScott Linder   if (!verifyEntry(RootMap, "amdhsa.kernels", true,
282ed0b9af9STim Renouf                    [this](msgpack::DocNode &Node) {
283ed0b9af9STim Renouf                      return verifyArray(Node, [this](msgpack::DocNode &Node) {
284f5b36e56SScott Linder                        return verifyKernel(Node);
285f5b36e56SScott Linder                      });
286f5b36e56SScott Linder                    }))
287f5b36e56SScott Linder     return false;
288f5b36e56SScott Linder 
289f5b36e56SScott Linder   return true;
290f5b36e56SScott Linder }
291f5b36e56SScott Linder 
292f5b36e56SScott Linder } // end namespace V3
293f5b36e56SScott Linder } // end namespace HSAMD
294f5b36e56SScott Linder } // end namespace AMDGPU
295f5b36e56SScott Linder } // end namespace llvm
296