1*b5893f02SDimitry Andric //===- AMDGPUMetadataVerifier.cpp - MsgPack Types ---------------*- C++ -*-===//
2*b5893f02SDimitry Andric //
3*b5893f02SDimitry Andric //                     The LLVM Compiler Infrastructure
4*b5893f02SDimitry Andric //
5*b5893f02SDimitry Andric // This file is distributed under the University of Illinois Open Source
6*b5893f02SDimitry Andric // License. See LICENSE.TXT for details.
7*b5893f02SDimitry Andric //
8*b5893f02SDimitry Andric //===----------------------------------------------------------------------===//
9*b5893f02SDimitry Andric //
10*b5893f02SDimitry Andric /// \file
11*b5893f02SDimitry Andric /// Implements a verifier for AMDGPU HSA metadata.
12*b5893f02SDimitry Andric //
13*b5893f02SDimitry Andric //===----------------------------------------------------------------------===//
14*b5893f02SDimitry Andric 
15*b5893f02SDimitry Andric #include "llvm/BinaryFormat/AMDGPUMetadataVerifier.h"
16*b5893f02SDimitry Andric #include "llvm/Support/AMDGPUMetadata.h"
17*b5893f02SDimitry Andric 
18*b5893f02SDimitry Andric namespace llvm {
19*b5893f02SDimitry Andric namespace AMDGPU {
20*b5893f02SDimitry Andric namespace HSAMD {
21*b5893f02SDimitry Andric namespace V3 {
22*b5893f02SDimitry Andric 
verifyScalar(msgpack::Node & Node,msgpack::ScalarNode::ScalarKind SKind,function_ref<bool (msgpack::ScalarNode &)> verifyValue)23*b5893f02SDimitry Andric bool MetadataVerifier::verifyScalar(
24*b5893f02SDimitry Andric     msgpack::Node &Node, msgpack::ScalarNode::ScalarKind SKind,
25*b5893f02SDimitry Andric     function_ref<bool(msgpack::ScalarNode &)> verifyValue) {
26*b5893f02SDimitry Andric   auto ScalarPtr = dyn_cast<msgpack::ScalarNode>(&Node);
27*b5893f02SDimitry Andric   if (!ScalarPtr)
28*b5893f02SDimitry Andric     return false;
29*b5893f02SDimitry Andric   auto &Scalar = *ScalarPtr;
30*b5893f02SDimitry Andric   // Do not output extraneous tags for types we know from the spec.
31*b5893f02SDimitry Andric   Scalar.IgnoreTag = true;
32*b5893f02SDimitry Andric   if (Scalar.getScalarKind() != SKind) {
33*b5893f02SDimitry Andric     if (Strict)
34*b5893f02SDimitry Andric       return false;
35*b5893f02SDimitry Andric     // If we are not strict, we interpret string values as "implicitly typed"
36*b5893f02SDimitry Andric     // and attempt to coerce them to the expected type here.
37*b5893f02SDimitry Andric     if (Scalar.getScalarKind() != msgpack::ScalarNode::SK_String)
38*b5893f02SDimitry Andric       return false;
39*b5893f02SDimitry Andric     std::string StringValue = Scalar.getString();
40*b5893f02SDimitry Andric     Scalar.setScalarKind(SKind);
41*b5893f02SDimitry Andric     if (Scalar.inputYAML(StringValue) != StringRef())
42*b5893f02SDimitry Andric       return false;
43*b5893f02SDimitry Andric   }
44*b5893f02SDimitry Andric   if (verifyValue)
45*b5893f02SDimitry Andric     return verifyValue(Scalar);
46*b5893f02SDimitry Andric   return true;
47*b5893f02SDimitry Andric }
48*b5893f02SDimitry Andric 
verifyInteger(msgpack::Node & Node)49*b5893f02SDimitry Andric bool MetadataVerifier::verifyInteger(msgpack::Node &Node) {
50*b5893f02SDimitry Andric   if (!verifyScalar(Node, msgpack::ScalarNode::SK_UInt))
51*b5893f02SDimitry Andric     if (!verifyScalar(Node, msgpack::ScalarNode::SK_Int))
52*b5893f02SDimitry Andric       return false;
53*b5893f02SDimitry Andric   return true;
54*b5893f02SDimitry Andric }
55*b5893f02SDimitry Andric 
verifyArray(msgpack::Node & Node,function_ref<bool (msgpack::Node &)> verifyNode,Optional<size_t> Size)56*b5893f02SDimitry Andric bool MetadataVerifier::verifyArray(
57*b5893f02SDimitry Andric     msgpack::Node &Node, function_ref<bool(msgpack::Node &)> verifyNode,
58*b5893f02SDimitry Andric     Optional<size_t> Size) {
59*b5893f02SDimitry Andric   auto ArrayPtr = dyn_cast<msgpack::ArrayNode>(&Node);
60*b5893f02SDimitry Andric   if (!ArrayPtr)
61*b5893f02SDimitry Andric     return false;
62*b5893f02SDimitry Andric   auto &Array = *ArrayPtr;
63*b5893f02SDimitry Andric   if (Size && Array.size() != *Size)
64*b5893f02SDimitry Andric     return false;
65*b5893f02SDimitry Andric   for (auto &Item : Array)
66*b5893f02SDimitry Andric     if (!verifyNode(*Item.get()))
67*b5893f02SDimitry Andric       return false;
68*b5893f02SDimitry Andric 
69*b5893f02SDimitry Andric   return true;
70*b5893f02SDimitry Andric }
71*b5893f02SDimitry Andric 
verifyEntry(msgpack::MapNode & MapNode,StringRef Key,bool Required,function_ref<bool (msgpack::Node &)> verifyNode)72*b5893f02SDimitry Andric bool MetadataVerifier::verifyEntry(
73*b5893f02SDimitry Andric     msgpack::MapNode &MapNode, StringRef Key, bool Required,
74*b5893f02SDimitry Andric     function_ref<bool(msgpack::Node &)> verifyNode) {
75*b5893f02SDimitry Andric   auto Entry = MapNode.find(Key);
76*b5893f02SDimitry Andric   if (Entry == MapNode.end())
77*b5893f02SDimitry Andric     return !Required;
78*b5893f02SDimitry Andric   return verifyNode(*Entry->second.get());
79*b5893f02SDimitry Andric }
80*b5893f02SDimitry Andric 
verifyScalarEntry(msgpack::MapNode & MapNode,StringRef Key,bool Required,msgpack::ScalarNode::ScalarKind SKind,function_ref<bool (msgpack::ScalarNode &)> verifyValue)81*b5893f02SDimitry Andric bool MetadataVerifier::verifyScalarEntry(
82*b5893f02SDimitry Andric     msgpack::MapNode &MapNode, StringRef Key, bool Required,
83*b5893f02SDimitry Andric     msgpack::ScalarNode::ScalarKind SKind,
84*b5893f02SDimitry Andric     function_ref<bool(msgpack::ScalarNode &)> verifyValue) {
85*b5893f02SDimitry Andric   return verifyEntry(MapNode, Key, Required, [=](msgpack::Node &Node) {
86*b5893f02SDimitry Andric     return verifyScalar(Node, SKind, verifyValue);
87*b5893f02SDimitry Andric   });
88*b5893f02SDimitry Andric }
89*b5893f02SDimitry Andric 
verifyIntegerEntry(msgpack::MapNode & MapNode,StringRef Key,bool Required)90*b5893f02SDimitry Andric bool MetadataVerifier::verifyIntegerEntry(msgpack::MapNode &MapNode,
91*b5893f02SDimitry Andric                                           StringRef Key, bool Required) {
92*b5893f02SDimitry Andric   return verifyEntry(MapNode, Key, Required, [this](msgpack::Node &Node) {
93*b5893f02SDimitry Andric     return verifyInteger(Node);
94*b5893f02SDimitry Andric   });
95*b5893f02SDimitry Andric }
96*b5893f02SDimitry Andric 
verifyKernelArgs(msgpack::Node & Node)97*b5893f02SDimitry Andric bool MetadataVerifier::verifyKernelArgs(msgpack::Node &Node) {
98*b5893f02SDimitry Andric   auto ArgsMapPtr = dyn_cast<msgpack::MapNode>(&Node);
99*b5893f02SDimitry Andric   if (!ArgsMapPtr)
100*b5893f02SDimitry Andric     return false;
101*b5893f02SDimitry Andric   auto &ArgsMap = *ArgsMapPtr;
102*b5893f02SDimitry Andric 
103*b5893f02SDimitry Andric   if (!verifyScalarEntry(ArgsMap, ".name", false,
104*b5893f02SDimitry Andric                          msgpack::ScalarNode::SK_String))
105*b5893f02SDimitry Andric     return false;
106*b5893f02SDimitry Andric   if (!verifyScalarEntry(ArgsMap, ".type_name", false,
107*b5893f02SDimitry Andric                          msgpack::ScalarNode::SK_String))
108*b5893f02SDimitry Andric     return false;
109*b5893f02SDimitry Andric   if (!verifyIntegerEntry(ArgsMap, ".size", true))
110*b5893f02SDimitry Andric     return false;
111*b5893f02SDimitry Andric   if (!verifyIntegerEntry(ArgsMap, ".offset", true))
112*b5893f02SDimitry Andric     return false;
113*b5893f02SDimitry Andric   if (!verifyScalarEntry(ArgsMap, ".value_kind", true,
114*b5893f02SDimitry Andric                          msgpack::ScalarNode::SK_String,
115*b5893f02SDimitry Andric                          [](msgpack::ScalarNode &SNode) {
116*b5893f02SDimitry Andric                            return StringSwitch<bool>(SNode.getString())
117*b5893f02SDimitry Andric                                .Case("by_value", true)
118*b5893f02SDimitry Andric                                .Case("global_buffer", true)
119*b5893f02SDimitry Andric                                .Case("dynamic_shared_pointer", true)
120*b5893f02SDimitry Andric                                .Case("sampler", true)
121*b5893f02SDimitry Andric                                .Case("image", true)
122*b5893f02SDimitry Andric                                .Case("pipe", true)
123*b5893f02SDimitry Andric                                .Case("queue", true)
124*b5893f02SDimitry Andric                                .Case("hidden_global_offset_x", true)
125*b5893f02SDimitry Andric                                .Case("hidden_global_offset_y", true)
126*b5893f02SDimitry Andric                                .Case("hidden_global_offset_z", true)
127*b5893f02SDimitry Andric                                .Case("hidden_none", true)
128*b5893f02SDimitry Andric                                .Case("hidden_printf_buffer", true)
129*b5893f02SDimitry Andric                                .Case("hidden_default_queue", true)
130*b5893f02SDimitry Andric                                .Case("hidden_completion_action", true)
131*b5893f02SDimitry Andric                                .Default(false);
132*b5893f02SDimitry Andric                          }))
133*b5893f02SDimitry Andric     return false;
134*b5893f02SDimitry Andric   if (!verifyScalarEntry(ArgsMap, ".value_type", true,
135*b5893f02SDimitry Andric                          msgpack::ScalarNode::SK_String,
136*b5893f02SDimitry Andric                          [](msgpack::ScalarNode &SNode) {
137*b5893f02SDimitry Andric                            return StringSwitch<bool>(SNode.getString())
138*b5893f02SDimitry Andric                                .Case("struct", true)
139*b5893f02SDimitry Andric                                .Case("i8", true)
140*b5893f02SDimitry Andric                                .Case("u8", true)
141*b5893f02SDimitry Andric                                .Case("i16", true)
142*b5893f02SDimitry Andric                                .Case("u16", true)
143*b5893f02SDimitry Andric                                .Case("f16", true)
144*b5893f02SDimitry Andric                                .Case("i32", true)
145*b5893f02SDimitry Andric                                .Case("u32", true)
146*b5893f02SDimitry Andric                                .Case("f32", true)
147*b5893f02SDimitry Andric                                .Case("i64", true)
148*b5893f02SDimitry Andric                                .Case("u64", true)
149*b5893f02SDimitry Andric                                .Case("f64", true)
150*b5893f02SDimitry Andric                                .Default(false);
151*b5893f02SDimitry Andric                          }))
152*b5893f02SDimitry Andric     return false;
153*b5893f02SDimitry Andric   if (!verifyIntegerEntry(ArgsMap, ".pointee_align", false))
154*b5893f02SDimitry Andric     return false;
155*b5893f02SDimitry Andric   if (!verifyScalarEntry(ArgsMap, ".address_space", false,
156*b5893f02SDimitry Andric                          msgpack::ScalarNode::SK_String,
157*b5893f02SDimitry Andric                          [](msgpack::ScalarNode &SNode) {
158*b5893f02SDimitry Andric                            return StringSwitch<bool>(SNode.getString())
159*b5893f02SDimitry Andric                                .Case("private", true)
160*b5893f02SDimitry Andric                                .Case("global", true)
161*b5893f02SDimitry Andric                                .Case("constant", true)
162*b5893f02SDimitry Andric                                .Case("local", true)
163*b5893f02SDimitry Andric                                .Case("generic", true)
164*b5893f02SDimitry Andric                                .Case("region", true)
165*b5893f02SDimitry Andric                                .Default(false);
166*b5893f02SDimitry Andric                          }))
167*b5893f02SDimitry Andric     return false;
168*b5893f02SDimitry Andric   if (!verifyScalarEntry(ArgsMap, ".access", false,
169*b5893f02SDimitry Andric                          msgpack::ScalarNode::SK_String,
170*b5893f02SDimitry Andric                          [](msgpack::ScalarNode &SNode) {
171*b5893f02SDimitry Andric                            return StringSwitch<bool>(SNode.getString())
172*b5893f02SDimitry Andric                                .Case("read_only", true)
173*b5893f02SDimitry Andric                                .Case("write_only", true)
174*b5893f02SDimitry Andric                                .Case("read_write", true)
175*b5893f02SDimitry Andric                                .Default(false);
176*b5893f02SDimitry Andric                          }))
177*b5893f02SDimitry Andric     return false;
178*b5893f02SDimitry Andric   if (!verifyScalarEntry(ArgsMap, ".actual_access", false,
179*b5893f02SDimitry Andric                          msgpack::ScalarNode::SK_String,
180*b5893f02SDimitry Andric                          [](msgpack::ScalarNode &SNode) {
181*b5893f02SDimitry Andric                            return StringSwitch<bool>(SNode.getString())
182*b5893f02SDimitry Andric                                .Case("read_only", true)
183*b5893f02SDimitry Andric                                .Case("write_only", true)
184*b5893f02SDimitry Andric                                .Case("read_write", true)
185*b5893f02SDimitry Andric                                .Default(false);
186*b5893f02SDimitry Andric                          }))
187*b5893f02SDimitry Andric     return false;
188*b5893f02SDimitry Andric   if (!verifyScalarEntry(ArgsMap, ".is_const", false,
189*b5893f02SDimitry Andric                          msgpack::ScalarNode::SK_Boolean))
190*b5893f02SDimitry Andric     return false;
191*b5893f02SDimitry Andric   if (!verifyScalarEntry(ArgsMap, ".is_restrict", false,
192*b5893f02SDimitry Andric                          msgpack::ScalarNode::SK_Boolean))
193*b5893f02SDimitry Andric     return false;
194*b5893f02SDimitry Andric   if (!verifyScalarEntry(ArgsMap, ".is_volatile", false,
195*b5893f02SDimitry Andric                          msgpack::ScalarNode::SK_Boolean))
196*b5893f02SDimitry Andric     return false;
197*b5893f02SDimitry Andric   if (!verifyScalarEntry(ArgsMap, ".is_pipe", false,
198*b5893f02SDimitry Andric                          msgpack::ScalarNode::SK_Boolean))
199*b5893f02SDimitry Andric     return false;
200*b5893f02SDimitry Andric 
201*b5893f02SDimitry Andric   return true;
202*b5893f02SDimitry Andric }
203*b5893f02SDimitry Andric 
verifyKernel(msgpack::Node & Node)204*b5893f02SDimitry Andric bool MetadataVerifier::verifyKernel(msgpack::Node &Node) {
205*b5893f02SDimitry Andric   auto KernelMapPtr = dyn_cast<msgpack::MapNode>(&Node);
206*b5893f02SDimitry Andric   if (!KernelMapPtr)
207*b5893f02SDimitry Andric     return false;
208*b5893f02SDimitry Andric   auto &KernelMap = *KernelMapPtr;
209*b5893f02SDimitry Andric 
210*b5893f02SDimitry Andric   if (!verifyScalarEntry(KernelMap, ".name", true,
211*b5893f02SDimitry Andric                          msgpack::ScalarNode::SK_String))
212*b5893f02SDimitry Andric     return false;
213*b5893f02SDimitry Andric   if (!verifyScalarEntry(KernelMap, ".symbol", true,
214*b5893f02SDimitry Andric                          msgpack::ScalarNode::SK_String))
215*b5893f02SDimitry Andric     return false;
216*b5893f02SDimitry Andric   if (!verifyScalarEntry(KernelMap, ".language", false,
217*b5893f02SDimitry Andric                          msgpack::ScalarNode::SK_String,
218*b5893f02SDimitry Andric                          [](msgpack::ScalarNode &SNode) {
219*b5893f02SDimitry Andric                            return StringSwitch<bool>(SNode.getString())
220*b5893f02SDimitry Andric                                .Case("OpenCL C", true)
221*b5893f02SDimitry Andric                                .Case("OpenCL C++", true)
222*b5893f02SDimitry Andric                                .Case("HCC", true)
223*b5893f02SDimitry Andric                                .Case("HIP", true)
224*b5893f02SDimitry Andric                                .Case("OpenMP", true)
225*b5893f02SDimitry Andric                                .Case("Assembler", true)
226*b5893f02SDimitry Andric                                .Default(false);
227*b5893f02SDimitry Andric                          }))
228*b5893f02SDimitry Andric     return false;
229*b5893f02SDimitry Andric   if (!verifyEntry(
230*b5893f02SDimitry Andric           KernelMap, ".language_version", false, [this](msgpack::Node &Node) {
231*b5893f02SDimitry Andric             return verifyArray(
232*b5893f02SDimitry Andric                 Node,
233*b5893f02SDimitry Andric                 [this](msgpack::Node &Node) { return verifyInteger(Node); }, 2);
234*b5893f02SDimitry Andric           }))
235*b5893f02SDimitry Andric     return false;
236*b5893f02SDimitry Andric   if (!verifyEntry(KernelMap, ".args", false, [this](msgpack::Node &Node) {
237*b5893f02SDimitry Andric         return verifyArray(Node, [this](msgpack::Node &Node) {
238*b5893f02SDimitry Andric           return verifyKernelArgs(Node);
239*b5893f02SDimitry Andric         });
240*b5893f02SDimitry Andric       }))
241*b5893f02SDimitry Andric     return false;
242*b5893f02SDimitry Andric   if (!verifyEntry(KernelMap, ".reqd_workgroup_size", false,
243*b5893f02SDimitry Andric                    [this](msgpack::Node &Node) {
244*b5893f02SDimitry Andric                      return verifyArray(Node,
245*b5893f02SDimitry Andric                                         [this](msgpack::Node &Node) {
246*b5893f02SDimitry Andric                                           return verifyInteger(Node);
247*b5893f02SDimitry Andric                                         },
248*b5893f02SDimitry Andric                                         3);
249*b5893f02SDimitry Andric                    }))
250*b5893f02SDimitry Andric     return false;
251*b5893f02SDimitry Andric   if (!verifyEntry(KernelMap, ".workgroup_size_hint", false,
252*b5893f02SDimitry Andric                    [this](msgpack::Node &Node) {
253*b5893f02SDimitry Andric                      return verifyArray(Node,
254*b5893f02SDimitry Andric                                         [this](msgpack::Node &Node) {
255*b5893f02SDimitry Andric                                           return verifyInteger(Node);
256*b5893f02SDimitry Andric                                         },
257*b5893f02SDimitry Andric                                         3);
258*b5893f02SDimitry Andric                    }))
259*b5893f02SDimitry Andric     return false;
260*b5893f02SDimitry Andric   if (!verifyScalarEntry(KernelMap, ".vec_type_hint", false,
261*b5893f02SDimitry Andric                          msgpack::ScalarNode::SK_String))
262*b5893f02SDimitry Andric     return false;
263*b5893f02SDimitry Andric   if (!verifyScalarEntry(KernelMap, ".device_enqueue_symbol", false,
264*b5893f02SDimitry Andric                          msgpack::ScalarNode::SK_String))
265*b5893f02SDimitry Andric     return false;
266*b5893f02SDimitry Andric   if (!verifyIntegerEntry(KernelMap, ".kernarg_segment_size", true))
267*b5893f02SDimitry Andric     return false;
268*b5893f02SDimitry Andric   if (!verifyIntegerEntry(KernelMap, ".group_segment_fixed_size", true))
269*b5893f02SDimitry Andric     return false;
270*b5893f02SDimitry Andric   if (!verifyIntegerEntry(KernelMap, ".private_segment_fixed_size", true))
271*b5893f02SDimitry Andric     return false;
272*b5893f02SDimitry Andric   if (!verifyIntegerEntry(KernelMap, ".kernarg_segment_align", true))
273*b5893f02SDimitry Andric     return false;
274*b5893f02SDimitry Andric   if (!verifyIntegerEntry(KernelMap, ".wavefront_size", true))
275*b5893f02SDimitry Andric     return false;
276*b5893f02SDimitry Andric   if (!verifyIntegerEntry(KernelMap, ".sgpr_count", true))
277*b5893f02SDimitry Andric     return false;
278*b5893f02SDimitry Andric   if (!verifyIntegerEntry(KernelMap, ".vgpr_count", true))
279*b5893f02SDimitry Andric     return false;
280*b5893f02SDimitry Andric   if (!verifyIntegerEntry(KernelMap, ".max_flat_workgroup_size", true))
281*b5893f02SDimitry Andric     return false;
282*b5893f02SDimitry Andric   if (!verifyIntegerEntry(KernelMap, ".sgpr_spill_count", false))
283*b5893f02SDimitry Andric     return false;
284*b5893f02SDimitry Andric   if (!verifyIntegerEntry(KernelMap, ".vgpr_spill_count", false))
285*b5893f02SDimitry Andric     return false;
286*b5893f02SDimitry Andric 
287*b5893f02SDimitry Andric   return true;
288*b5893f02SDimitry Andric }
289*b5893f02SDimitry Andric 
verify(msgpack::Node & HSAMetadataRoot)290*b5893f02SDimitry Andric bool MetadataVerifier::verify(msgpack::Node &HSAMetadataRoot) {
291*b5893f02SDimitry Andric   auto RootMapPtr = dyn_cast<msgpack::MapNode>(&HSAMetadataRoot);
292*b5893f02SDimitry Andric   if (!RootMapPtr)
293*b5893f02SDimitry Andric     return false;
294*b5893f02SDimitry Andric   auto &RootMap = *RootMapPtr;
295*b5893f02SDimitry Andric 
296*b5893f02SDimitry Andric   if (!verifyEntry(
297*b5893f02SDimitry Andric           RootMap, "amdhsa.version", true, [this](msgpack::Node &Node) {
298*b5893f02SDimitry Andric             return verifyArray(
299*b5893f02SDimitry Andric                 Node,
300*b5893f02SDimitry Andric                 [this](msgpack::Node &Node) { return verifyInteger(Node); }, 2);
301*b5893f02SDimitry Andric           }))
302*b5893f02SDimitry Andric     return false;
303*b5893f02SDimitry Andric   if (!verifyEntry(
304*b5893f02SDimitry Andric           RootMap, "amdhsa.printf", false, [this](msgpack::Node &Node) {
305*b5893f02SDimitry Andric             return verifyArray(Node, [this](msgpack::Node &Node) {
306*b5893f02SDimitry Andric               return verifyScalar(Node, msgpack::ScalarNode::SK_String);
307*b5893f02SDimitry Andric             });
308*b5893f02SDimitry Andric           }))
309*b5893f02SDimitry Andric     return false;
310*b5893f02SDimitry Andric   if (!verifyEntry(RootMap, "amdhsa.kernels", true,
311*b5893f02SDimitry Andric                    [this](msgpack::Node &Node) {
312*b5893f02SDimitry Andric                      return verifyArray(Node, [this](msgpack::Node &Node) {
313*b5893f02SDimitry Andric                        return verifyKernel(Node);
314*b5893f02SDimitry Andric                      });
315*b5893f02SDimitry Andric                    }))
316*b5893f02SDimitry Andric     return false;
317*b5893f02SDimitry Andric 
318*b5893f02SDimitry Andric   return true;
319*b5893f02SDimitry Andric }
320*b5893f02SDimitry Andric 
321*b5893f02SDimitry Andric } // end namespace V3
322*b5893f02SDimitry Andric } // end namespace HSAMD
323*b5893f02SDimitry Andric } // end namespace AMDGPU
324*b5893f02SDimitry Andric } // end namespace llvm
325