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