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"
15b58174d6Sserge-sans-paille
16b58174d6Sserge-sans-paille #include "llvm/ADT/STLExtras.h"
17b58174d6Sserge-sans-paille #include "llvm/ADT/STLForwardCompat.h"
18af450eabSReid Kleckner #include "llvm/ADT/StringSwitch.h"
19b58174d6Sserge-sans-paille #include "llvm/BinaryFormat/MsgPackDocument.h"
20b58174d6Sserge-sans-paille
21b58174d6Sserge-sans-paille #include <map>
22b58174d6Sserge-sans-paille #include <utility>
23f5b36e56SScott Linder
24f5b36e56SScott Linder namespace llvm {
25f5b36e56SScott Linder namespace AMDGPU {
26f5b36e56SScott Linder namespace HSAMD {
27f5b36e56SScott Linder namespace V3 {
28f5b36e56SScott Linder
verifyScalar(msgpack::DocNode & Node,msgpack::Type SKind,function_ref<bool (msgpack::DocNode &)> verifyValue)29f5b36e56SScott Linder bool MetadataVerifier::verifyScalar(
30ed0b9af9STim Renouf msgpack::DocNode &Node, msgpack::Type SKind,
31ed0b9af9STim Renouf function_ref<bool(msgpack::DocNode &)> verifyValue) {
32ed0b9af9STim Renouf if (!Node.isScalar())
33f5b36e56SScott Linder return false;
34ed0b9af9STim Renouf if (Node.getKind() != SKind) {
35f5b36e56SScott Linder if (Strict)
36f5b36e56SScott Linder return false;
37f5b36e56SScott Linder // If we are not strict, we interpret string values as "implicitly typed"
38f5b36e56SScott Linder // and attempt to coerce them to the expected type here.
39ed0b9af9STim Renouf if (Node.getKind() != msgpack::Type::String)
40f5b36e56SScott Linder return false;
41ed0b9af9STim Renouf StringRef StringValue = Node.getString();
42ed0b9af9STim Renouf Node.fromString(StringValue);
43ed0b9af9STim Renouf if (Node.getKind() != SKind)
44f5b36e56SScott Linder return false;
45f5b36e56SScott Linder }
46f5b36e56SScott Linder if (verifyValue)
47ed0b9af9STim Renouf return verifyValue(Node);
48f5b36e56SScott Linder return true;
49f5b36e56SScott Linder }
50f5b36e56SScott Linder
verifyInteger(msgpack::DocNode & Node)51ed0b9af9STim Renouf bool MetadataVerifier::verifyInteger(msgpack::DocNode &Node) {
52ed0b9af9STim Renouf if (!verifyScalar(Node, msgpack::Type::UInt))
53ed0b9af9STim Renouf if (!verifyScalar(Node, msgpack::Type::Int))
54f5b36e56SScott Linder return false;
55f5b36e56SScott Linder return true;
56f5b36e56SScott Linder }
57f5b36e56SScott Linder
verifyArray(msgpack::DocNode & Node,function_ref<bool (msgpack::DocNode &)> verifyNode,Optional<size_t> Size)58f5b36e56SScott Linder bool MetadataVerifier::verifyArray(
59ed0b9af9STim Renouf msgpack::DocNode &Node, function_ref<bool(msgpack::DocNode &)> verifyNode,
60f5b36e56SScott Linder Optional<size_t> Size) {
61ed0b9af9STim Renouf if (!Node.isArray())
62f5b36e56SScott Linder return false;
63ed0b9af9STim Renouf auto &Array = Node.getArray();
64f5b36e56SScott Linder if (Size && Array.size() != *Size)
65f5b36e56SScott Linder return false;
66c2bb9637SKazu Hirata return llvm::all_of(Array, verifyNode);
67f5b36e56SScott Linder }
68f5b36e56SScott Linder
verifyEntry(msgpack::MapDocNode & MapNode,StringRef Key,bool Required,function_ref<bool (msgpack::DocNode &)> verifyNode)69f5b36e56SScott Linder bool MetadataVerifier::verifyEntry(
70ed0b9af9STim Renouf msgpack::MapDocNode &MapNode, StringRef Key, bool Required,
71ed0b9af9STim Renouf function_ref<bool(msgpack::DocNode &)> verifyNode) {
72f5b36e56SScott Linder auto Entry = MapNode.find(Key);
73f5b36e56SScott Linder if (Entry == MapNode.end())
74f5b36e56SScott Linder return !Required;
75ed0b9af9STim Renouf return verifyNode(Entry->second);
76f5b36e56SScott Linder }
77f5b36e56SScott Linder
verifyScalarEntry(msgpack::MapDocNode & MapNode,StringRef Key,bool Required,msgpack::Type SKind,function_ref<bool (msgpack::DocNode &)> verifyValue)78f5b36e56SScott Linder bool MetadataVerifier::verifyScalarEntry(
79ed0b9af9STim Renouf msgpack::MapDocNode &MapNode, StringRef Key, bool Required,
80ed0b9af9STim Renouf msgpack::Type SKind,
81ed0b9af9STim Renouf function_ref<bool(msgpack::DocNode &)> verifyValue) {
82ed0b9af9STim Renouf return verifyEntry(MapNode, Key, Required, [=](msgpack::DocNode &Node) {
83f5b36e56SScott Linder return verifyScalar(Node, SKind, verifyValue);
84f5b36e56SScott Linder });
85f5b36e56SScott Linder }
86f5b36e56SScott Linder
verifyIntegerEntry(msgpack::MapDocNode & MapNode,StringRef Key,bool Required)87ed0b9af9STim Renouf bool MetadataVerifier::verifyIntegerEntry(msgpack::MapDocNode &MapNode,
88f5b36e56SScott Linder StringRef Key, bool Required) {
89ed0b9af9STim Renouf return verifyEntry(MapNode, Key, Required, [this](msgpack::DocNode &Node) {
90f5b36e56SScott Linder return verifyInteger(Node);
91f5b36e56SScott Linder });
92f5b36e56SScott Linder }
93f5b36e56SScott Linder
verifyKernelArgs(msgpack::DocNode & Node)94ed0b9af9STim Renouf bool MetadataVerifier::verifyKernelArgs(msgpack::DocNode &Node) {
95ed0b9af9STim Renouf if (!Node.isMap())
96f5b36e56SScott Linder return false;
97ed0b9af9STim Renouf auto &ArgsMap = Node.getMap();
98f5b36e56SScott Linder
99f5b36e56SScott Linder if (!verifyScalarEntry(ArgsMap, ".name", false,
100ed0b9af9STim Renouf msgpack::Type::String))
101f5b36e56SScott Linder return false;
102f5b36e56SScott Linder if (!verifyScalarEntry(ArgsMap, ".type_name", false,
103ed0b9af9STim Renouf msgpack::Type::String))
104f5b36e56SScott Linder return false;
105f5b36e56SScott Linder if (!verifyIntegerEntry(ArgsMap, ".size", true))
106f5b36e56SScott Linder return false;
107f5b36e56SScott Linder if (!verifyIntegerEntry(ArgsMap, ".offset", true))
108f5b36e56SScott Linder return false;
109ca62b1dbSChangpeng Fang if (!verifyScalarEntry(ArgsMap, ".value_kind", true, msgpack::Type::String,
110ed0b9af9STim Renouf [](msgpack::DocNode &SNode) {
111f5b36e56SScott Linder return StringSwitch<bool>(SNode.getString())
112f5b36e56SScott Linder .Case("by_value", true)
113f5b36e56SScott Linder .Case("global_buffer", true)
114f5b36e56SScott Linder .Case("dynamic_shared_pointer", true)
115f5b36e56SScott Linder .Case("sampler", true)
116f5b36e56SScott Linder .Case("image", true)
117f5b36e56SScott Linder .Case("pipe", true)
118f5b36e56SScott Linder .Case("queue", true)
1191194b9cdSChangpeng Fang .Case("hidden_block_count_x", true)
1201194b9cdSChangpeng Fang .Case("hidden_block_count_y", true)
1211194b9cdSChangpeng Fang .Case("hidden_block_count_z", true)
1221194b9cdSChangpeng Fang .Case("hidden_group_size_x", true)
1231194b9cdSChangpeng Fang .Case("hidden_group_size_y", true)
1241194b9cdSChangpeng Fang .Case("hidden_group_size_z", true)
1251194b9cdSChangpeng Fang .Case("hidden_remainder_x", true)
1261194b9cdSChangpeng Fang .Case("hidden_remainder_y", true)
1271194b9cdSChangpeng Fang .Case("hidden_remainder_z", true)
128f5b36e56SScott Linder .Case("hidden_global_offset_x", true)
129f5b36e56SScott Linder .Case("hidden_global_offset_y", true)
130f5b36e56SScott Linder .Case("hidden_global_offset_z", true)
1311194b9cdSChangpeng Fang .Case("hidden_grid_dims", true)
132f5b36e56SScott Linder .Case("hidden_none", true)
133f5b36e56SScott Linder .Case("hidden_printf_buffer", true)
13452c5014dSSameer Sahasrabuddhe .Case("hidden_hostcall_buffer", true)
135ca62b1dbSChangpeng Fang .Case("hidden_heap_v1", true)
136f5b36e56SScott Linder .Case("hidden_default_queue", true)
137f5b36e56SScott Linder .Case("hidden_completion_action", true)
138a6241352SYaxun Liu .Case("hidden_multigrid_sync_arg", true)
1391194b9cdSChangpeng Fang .Case("hidden_private_base", true)
1401194b9cdSChangpeng Fang .Case("hidden_shared_base", true)
1411194b9cdSChangpeng Fang .Case("hidden_queue_ptr", true)
142f5b36e56SScott Linder .Default(false);
143f5b36e56SScott Linder }))
144f5b36e56SScott Linder return false;
145f5b36e56SScott Linder if (!verifyIntegerEntry(ArgsMap, ".pointee_align", false))
146f5b36e56SScott Linder return false;
147f5b36e56SScott Linder if (!verifyScalarEntry(ArgsMap, ".address_space", false,
148ed0b9af9STim Renouf msgpack::Type::String,
149ed0b9af9STim Renouf [](msgpack::DocNode &SNode) {
150f5b36e56SScott Linder return StringSwitch<bool>(SNode.getString())
151f5b36e56SScott Linder .Case("private", true)
152f5b36e56SScott Linder .Case("global", true)
153f5b36e56SScott Linder .Case("constant", true)
154f5b36e56SScott Linder .Case("local", true)
155f5b36e56SScott Linder .Case("generic", true)
156f5b36e56SScott Linder .Case("region", true)
157f5b36e56SScott Linder .Default(false);
158f5b36e56SScott Linder }))
159f5b36e56SScott Linder return false;
160f5b36e56SScott Linder if (!verifyScalarEntry(ArgsMap, ".access", false,
161ed0b9af9STim Renouf msgpack::Type::String,
162ed0b9af9STim Renouf [](msgpack::DocNode &SNode) {
163f5b36e56SScott Linder return StringSwitch<bool>(SNode.getString())
164f5b36e56SScott Linder .Case("read_only", true)
165f5b36e56SScott Linder .Case("write_only", true)
166f5b36e56SScott Linder .Case("read_write", true)
167f5b36e56SScott Linder .Default(false);
168f5b36e56SScott Linder }))
169f5b36e56SScott Linder return false;
170f5b36e56SScott Linder if (!verifyScalarEntry(ArgsMap, ".actual_access", false,
171ed0b9af9STim Renouf msgpack::Type::String,
172ed0b9af9STim Renouf [](msgpack::DocNode &SNode) {
173f5b36e56SScott Linder return StringSwitch<bool>(SNode.getString())
174f5b36e56SScott Linder .Case("read_only", true)
175f5b36e56SScott Linder .Case("write_only", true)
176f5b36e56SScott Linder .Case("read_write", true)
177f5b36e56SScott Linder .Default(false);
178f5b36e56SScott Linder }))
179f5b36e56SScott Linder return false;
180f5b36e56SScott Linder if (!verifyScalarEntry(ArgsMap, ".is_const", false,
181ed0b9af9STim Renouf msgpack::Type::Boolean))
182f5b36e56SScott Linder return false;
183f5b36e56SScott Linder if (!verifyScalarEntry(ArgsMap, ".is_restrict", false,
184ed0b9af9STim Renouf msgpack::Type::Boolean))
185f5b36e56SScott Linder return false;
186f5b36e56SScott Linder if (!verifyScalarEntry(ArgsMap, ".is_volatile", false,
187ed0b9af9STim Renouf msgpack::Type::Boolean))
188f5b36e56SScott Linder return false;
189f5b36e56SScott Linder if (!verifyScalarEntry(ArgsMap, ".is_pipe", false,
190ed0b9af9STim Renouf msgpack::Type::Boolean))
191f5b36e56SScott Linder return false;
192f5b36e56SScott Linder
193f5b36e56SScott Linder return true;
194f5b36e56SScott Linder }
195f5b36e56SScott Linder
verifyKernel(msgpack::DocNode & Node)196ed0b9af9STim Renouf bool MetadataVerifier::verifyKernel(msgpack::DocNode &Node) {
197ed0b9af9STim Renouf if (!Node.isMap())
198f5b36e56SScott Linder return false;
199ed0b9af9STim Renouf auto &KernelMap = Node.getMap();
200f5b36e56SScott Linder
201f5b36e56SScott Linder if (!verifyScalarEntry(KernelMap, ".name", true,
202ed0b9af9STim Renouf msgpack::Type::String))
203f5b36e56SScott Linder return false;
204f5b36e56SScott Linder if (!verifyScalarEntry(KernelMap, ".symbol", true,
205ed0b9af9STim Renouf msgpack::Type::String))
206f5b36e56SScott Linder return false;
207f5b36e56SScott Linder if (!verifyScalarEntry(KernelMap, ".language", false,
208ed0b9af9STim Renouf msgpack::Type::String,
209ed0b9af9STim Renouf [](msgpack::DocNode &SNode) {
210f5b36e56SScott Linder return StringSwitch<bool>(SNode.getString())
211f5b36e56SScott Linder .Case("OpenCL C", true)
212f5b36e56SScott Linder .Case("OpenCL C++", true)
213f5b36e56SScott Linder .Case("HCC", true)
214f5b36e56SScott Linder .Case("HIP", true)
215f5b36e56SScott Linder .Case("OpenMP", true)
216f5b36e56SScott Linder .Case("Assembler", true)
217f5b36e56SScott Linder .Default(false);
218f5b36e56SScott Linder }))
219f5b36e56SScott Linder return false;
220f5b36e56SScott Linder if (!verifyEntry(
221ed0b9af9STim Renouf KernelMap, ".language_version", false, [this](msgpack::DocNode &Node) {
222f5b36e56SScott Linder return verifyArray(
223f5b36e56SScott Linder Node,
224ed0b9af9STim Renouf [this](msgpack::DocNode &Node) { return verifyInteger(Node); }, 2);
225f5b36e56SScott Linder }))
226f5b36e56SScott Linder return false;
227ed0b9af9STim Renouf if (!verifyEntry(KernelMap, ".args", false, [this](msgpack::DocNode &Node) {
228ed0b9af9STim Renouf return verifyArray(Node, [this](msgpack::DocNode &Node) {
229f5b36e56SScott Linder return verifyKernelArgs(Node);
230f5b36e56SScott Linder });
231f5b36e56SScott Linder }))
232f5b36e56SScott Linder return false;
233f5b36e56SScott Linder if (!verifyEntry(KernelMap, ".reqd_workgroup_size", false,
234ed0b9af9STim Renouf [this](msgpack::DocNode &Node) {
235f5b36e56SScott Linder return verifyArray(Node,
236ed0b9af9STim Renouf [this](msgpack::DocNode &Node) {
237f5b36e56SScott Linder return verifyInteger(Node);
238f5b36e56SScott Linder },
239f5b36e56SScott Linder 3);
240f5b36e56SScott Linder }))
241f5b36e56SScott Linder return false;
242f5b36e56SScott Linder if (!verifyEntry(KernelMap, ".workgroup_size_hint", false,
243ed0b9af9STim Renouf [this](msgpack::DocNode &Node) {
244f5b36e56SScott Linder return verifyArray(Node,
245ed0b9af9STim Renouf [this](msgpack::DocNode &Node) {
246f5b36e56SScott Linder return verifyInteger(Node);
247f5b36e56SScott Linder },
248f5b36e56SScott Linder 3);
249f5b36e56SScott Linder }))
250f5b36e56SScott Linder return false;
251f5b36e56SScott Linder if (!verifyScalarEntry(KernelMap, ".vec_type_hint", false,
252ed0b9af9STim Renouf msgpack::Type::String))
253f5b36e56SScott Linder return false;
254f5b36e56SScott Linder if (!verifyScalarEntry(KernelMap, ".device_enqueue_symbol", false,
255ed0b9af9STim Renouf msgpack::Type::String))
256f5b36e56SScott Linder return false;
257f5b36e56SScott Linder if (!verifyIntegerEntry(KernelMap, ".kernarg_segment_size", true))
258f5b36e56SScott Linder return false;
259f5b36e56SScott Linder if (!verifyIntegerEntry(KernelMap, ".group_segment_fixed_size", true))
260f5b36e56SScott Linder return false;
261f5b36e56SScott Linder if (!verifyIntegerEntry(KernelMap, ".private_segment_fixed_size", true))
262f5b36e56SScott Linder return false;
263*d96361d7SAbinav Puthan Purayil if (!verifyScalarEntry(KernelMap, ".uses_dynamic_stack", false,
264*d96361d7SAbinav Puthan Purayil msgpack::Type::Boolean))
265*d96361d7SAbinav Puthan Purayil return false;
266f5b36e56SScott Linder if (!verifyIntegerEntry(KernelMap, ".kernarg_segment_align", true))
267f5b36e56SScott Linder return false;
268f5b36e56SScott Linder if (!verifyIntegerEntry(KernelMap, ".wavefront_size", true))
269f5b36e56SScott Linder return false;
270f5b36e56SScott Linder if (!verifyIntegerEntry(KernelMap, ".sgpr_count", true))
271f5b36e56SScott Linder return false;
272f5b36e56SScott Linder if (!verifyIntegerEntry(KernelMap, ".vgpr_count", true))
273f5b36e56SScott Linder return false;
274f5b36e56SScott Linder if (!verifyIntegerEntry(KernelMap, ".max_flat_workgroup_size", true))
275f5b36e56SScott Linder return false;
276f5b36e56SScott Linder if (!verifyIntegerEntry(KernelMap, ".sgpr_spill_count", false))
277f5b36e56SScott Linder return false;
278f5b36e56SScott Linder if (!verifyIntegerEntry(KernelMap, ".vgpr_spill_count", false))
279f5b36e56SScott Linder return false;
280f5b36e56SScott Linder
281f5b36e56SScott Linder return true;
282f5b36e56SScott Linder }
283f5b36e56SScott Linder
verify(msgpack::DocNode & HSAMetadataRoot)284ed0b9af9STim Renouf bool MetadataVerifier::verify(msgpack::DocNode &HSAMetadataRoot) {
285ed0b9af9STim Renouf if (!HSAMetadataRoot.isMap())
286f5b36e56SScott Linder return false;
287ed0b9af9STim Renouf auto &RootMap = HSAMetadataRoot.getMap();
288f5b36e56SScott Linder
289f5b36e56SScott Linder if (!verifyEntry(
290ed0b9af9STim Renouf RootMap, "amdhsa.version", true, [this](msgpack::DocNode &Node) {
291f5b36e56SScott Linder return verifyArray(
292f5b36e56SScott Linder Node,
293ed0b9af9STim Renouf [this](msgpack::DocNode &Node) { return verifyInteger(Node); }, 2);
294f5b36e56SScott Linder }))
295f5b36e56SScott Linder return false;
296f5b36e56SScott Linder if (!verifyEntry(
297ed0b9af9STim Renouf RootMap, "amdhsa.printf", false, [this](msgpack::DocNode &Node) {
298ed0b9af9STim Renouf return verifyArray(Node, [this](msgpack::DocNode &Node) {
299ed0b9af9STim Renouf return verifyScalar(Node, msgpack::Type::String);
300f5b36e56SScott Linder });
301f5b36e56SScott Linder }))
302f5b36e56SScott Linder return false;
303f5b36e56SScott Linder if (!verifyEntry(RootMap, "amdhsa.kernels", true,
304ed0b9af9STim Renouf [this](msgpack::DocNode &Node) {
305ed0b9af9STim Renouf return verifyArray(Node, [this](msgpack::DocNode &Node) {
306f5b36e56SScott Linder return verifyKernel(Node);
307f5b36e56SScott Linder });
308f5b36e56SScott Linder }))
309f5b36e56SScott Linder return false;
310f5b36e56SScott Linder
311f5b36e56SScott Linder return true;
312f5b36e56SScott Linder }
313f5b36e56SScott Linder
314f5b36e56SScott Linder } // end namespace V3
315f5b36e56SScott Linder } // end namespace HSAMD
316f5b36e56SScott Linder } // end namespace AMDGPU
317f5b36e56SScott Linder } // end namespace llvm
318