xref: /freebsd-src/contrib/llvm-project/llvm/lib/BinaryFormat/AMDGPUMetadataVerifier.cpp (revision 1db9f3b21e39176dd5b67cf8ac378633b172463e)
10b57cec5SDimitry Andric //===- AMDGPUMetadataVerifier.cpp - MsgPack Types ---------------*- C++ -*-===//
20b57cec5SDimitry Andric //
30b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
40b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
50b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
60b57cec5SDimitry Andric //
70b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
80b57cec5SDimitry Andric //
90b57cec5SDimitry Andric /// \file
100b57cec5SDimitry Andric /// Implements a verifier for AMDGPU HSA metadata.
110b57cec5SDimitry Andric //
120b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
130b57cec5SDimitry Andric 
140b57cec5SDimitry Andric #include "llvm/BinaryFormat/AMDGPUMetadataVerifier.h"
1504eeddc0SDimitry Andric 
1604eeddc0SDimitry Andric #include "llvm/ADT/STLExtras.h"
175ffd83dbSDimitry Andric #include "llvm/ADT/StringSwitch.h"
1804eeddc0SDimitry Andric #include "llvm/BinaryFormat/MsgPackDocument.h"
1904eeddc0SDimitry Andric 
2004eeddc0SDimitry Andric #include <utility>
210b57cec5SDimitry Andric 
220b57cec5SDimitry Andric namespace llvm {
230b57cec5SDimitry Andric namespace AMDGPU {
240b57cec5SDimitry Andric namespace HSAMD {
250b57cec5SDimitry Andric namespace V3 {
260b57cec5SDimitry Andric 
verifyScalar(msgpack::DocNode & Node,msgpack::Type SKind,function_ref<bool (msgpack::DocNode &)> verifyValue)270b57cec5SDimitry Andric bool MetadataVerifier::verifyScalar(
280b57cec5SDimitry Andric     msgpack::DocNode &Node, msgpack::Type SKind,
290b57cec5SDimitry Andric     function_ref<bool(msgpack::DocNode &)> verifyValue) {
300b57cec5SDimitry Andric   if (!Node.isScalar())
310b57cec5SDimitry Andric     return false;
320b57cec5SDimitry Andric   if (Node.getKind() != SKind) {
330b57cec5SDimitry Andric     if (Strict)
340b57cec5SDimitry Andric       return false;
350b57cec5SDimitry Andric     // If we are not strict, we interpret string values as "implicitly typed"
360b57cec5SDimitry Andric     // and attempt to coerce them to the expected type here.
370b57cec5SDimitry Andric     if (Node.getKind() != msgpack::Type::String)
380b57cec5SDimitry Andric       return false;
390b57cec5SDimitry Andric     StringRef StringValue = Node.getString();
400b57cec5SDimitry Andric     Node.fromString(StringValue);
410b57cec5SDimitry Andric     if (Node.getKind() != SKind)
420b57cec5SDimitry Andric       return false;
430b57cec5SDimitry Andric   }
440b57cec5SDimitry Andric   if (verifyValue)
450b57cec5SDimitry Andric     return verifyValue(Node);
460b57cec5SDimitry Andric   return true;
470b57cec5SDimitry Andric }
480b57cec5SDimitry Andric 
verifyInteger(msgpack::DocNode & Node)490b57cec5SDimitry Andric bool MetadataVerifier::verifyInteger(msgpack::DocNode &Node) {
500b57cec5SDimitry Andric   if (!verifyScalar(Node, msgpack::Type::UInt))
510b57cec5SDimitry Andric     if (!verifyScalar(Node, msgpack::Type::Int))
520b57cec5SDimitry Andric       return false;
530b57cec5SDimitry Andric   return true;
540b57cec5SDimitry Andric }
550b57cec5SDimitry Andric 
verifyArray(msgpack::DocNode & Node,function_ref<bool (msgpack::DocNode &)> verifyNode,std::optional<size_t> Size)560b57cec5SDimitry Andric bool MetadataVerifier::verifyArray(
570b57cec5SDimitry Andric     msgpack::DocNode &Node, function_ref<bool(msgpack::DocNode &)> verifyNode,
58bdd1243dSDimitry Andric     std::optional<size_t> Size) {
590b57cec5SDimitry Andric   if (!Node.isArray())
600b57cec5SDimitry Andric     return false;
610b57cec5SDimitry Andric   auto &Array = Node.getArray();
620b57cec5SDimitry Andric   if (Size && Array.size() != *Size)
630b57cec5SDimitry Andric     return false;
640eae32dcSDimitry Andric   return llvm::all_of(Array, verifyNode);
650b57cec5SDimitry Andric }
660b57cec5SDimitry Andric 
verifyEntry(msgpack::MapDocNode & MapNode,StringRef Key,bool Required,function_ref<bool (msgpack::DocNode &)> verifyNode)670b57cec5SDimitry Andric bool MetadataVerifier::verifyEntry(
680b57cec5SDimitry Andric     msgpack::MapDocNode &MapNode, StringRef Key, bool Required,
690b57cec5SDimitry Andric     function_ref<bool(msgpack::DocNode &)> verifyNode) {
700b57cec5SDimitry Andric   auto Entry = MapNode.find(Key);
710b57cec5SDimitry Andric   if (Entry == MapNode.end())
720b57cec5SDimitry Andric     return !Required;
730b57cec5SDimitry Andric   return verifyNode(Entry->second);
740b57cec5SDimitry Andric }
750b57cec5SDimitry Andric 
verifyScalarEntry(msgpack::MapDocNode & MapNode,StringRef Key,bool Required,msgpack::Type SKind,function_ref<bool (msgpack::DocNode &)> verifyValue)760b57cec5SDimitry Andric bool MetadataVerifier::verifyScalarEntry(
770b57cec5SDimitry Andric     msgpack::MapDocNode &MapNode, StringRef Key, bool Required,
780b57cec5SDimitry Andric     msgpack::Type SKind,
790b57cec5SDimitry Andric     function_ref<bool(msgpack::DocNode &)> verifyValue) {
800b57cec5SDimitry Andric   return verifyEntry(MapNode, Key, Required, [=](msgpack::DocNode &Node) {
810b57cec5SDimitry Andric     return verifyScalar(Node, SKind, verifyValue);
820b57cec5SDimitry Andric   });
830b57cec5SDimitry Andric }
840b57cec5SDimitry Andric 
verifyIntegerEntry(msgpack::MapDocNode & MapNode,StringRef Key,bool Required)850b57cec5SDimitry Andric bool MetadataVerifier::verifyIntegerEntry(msgpack::MapDocNode &MapNode,
860b57cec5SDimitry Andric                                           StringRef Key, bool Required) {
870b57cec5SDimitry Andric   return verifyEntry(MapNode, Key, Required, [this](msgpack::DocNode &Node) {
880b57cec5SDimitry Andric     return verifyInteger(Node);
890b57cec5SDimitry Andric   });
900b57cec5SDimitry Andric }
910b57cec5SDimitry Andric 
verifyKernelArgs(msgpack::DocNode & Node)920b57cec5SDimitry Andric bool MetadataVerifier::verifyKernelArgs(msgpack::DocNode &Node) {
930b57cec5SDimitry Andric   if (!Node.isMap())
940b57cec5SDimitry Andric     return false;
950b57cec5SDimitry Andric   auto &ArgsMap = Node.getMap();
960b57cec5SDimitry Andric 
970b57cec5SDimitry Andric   if (!verifyScalarEntry(ArgsMap, ".name", false,
980b57cec5SDimitry Andric                          msgpack::Type::String))
990b57cec5SDimitry Andric     return false;
1000b57cec5SDimitry Andric   if (!verifyScalarEntry(ArgsMap, ".type_name", false,
1010b57cec5SDimitry Andric                          msgpack::Type::String))
1020b57cec5SDimitry Andric     return false;
1030b57cec5SDimitry Andric   if (!verifyIntegerEntry(ArgsMap, ".size", true))
1040b57cec5SDimitry Andric     return false;
1050b57cec5SDimitry Andric   if (!verifyIntegerEntry(ArgsMap, ".offset", true))
1060b57cec5SDimitry Andric     return false;
10781ad6265SDimitry Andric   if (!verifyScalarEntry(ArgsMap, ".value_kind", true, msgpack::Type::String,
1080b57cec5SDimitry Andric                          [](msgpack::DocNode &SNode) {
1090b57cec5SDimitry Andric                            return StringSwitch<bool>(SNode.getString())
1100b57cec5SDimitry Andric                                .Case("by_value", true)
1110b57cec5SDimitry Andric                                .Case("global_buffer", true)
1120b57cec5SDimitry Andric                                .Case("dynamic_shared_pointer", true)
1130b57cec5SDimitry Andric                                .Case("sampler", true)
1140b57cec5SDimitry Andric                                .Case("image", true)
1150b57cec5SDimitry Andric                                .Case("pipe", true)
1160b57cec5SDimitry Andric                                .Case("queue", true)
1171fd87a68SDimitry Andric                                .Case("hidden_block_count_x", true)
1181fd87a68SDimitry Andric                                .Case("hidden_block_count_y", true)
1191fd87a68SDimitry Andric                                .Case("hidden_block_count_z", true)
1201fd87a68SDimitry Andric                                .Case("hidden_group_size_x", true)
1211fd87a68SDimitry Andric                                .Case("hidden_group_size_y", true)
1221fd87a68SDimitry Andric                                .Case("hidden_group_size_z", true)
1231fd87a68SDimitry Andric                                .Case("hidden_remainder_x", true)
1241fd87a68SDimitry Andric                                .Case("hidden_remainder_y", true)
1251fd87a68SDimitry Andric                                .Case("hidden_remainder_z", true)
1260b57cec5SDimitry Andric                                .Case("hidden_global_offset_x", true)
1270b57cec5SDimitry Andric                                .Case("hidden_global_offset_y", true)
1280b57cec5SDimitry Andric                                .Case("hidden_global_offset_z", true)
1291fd87a68SDimitry Andric                                .Case("hidden_grid_dims", true)
1300b57cec5SDimitry Andric                                .Case("hidden_none", true)
1310b57cec5SDimitry Andric                                .Case("hidden_printf_buffer", true)
132480093f4SDimitry Andric                                .Case("hidden_hostcall_buffer", true)
13381ad6265SDimitry Andric                                .Case("hidden_heap_v1", true)
1340b57cec5SDimitry Andric                                .Case("hidden_default_queue", true)
1350b57cec5SDimitry Andric                                .Case("hidden_completion_action", true)
1360b57cec5SDimitry Andric                                .Case("hidden_multigrid_sync_arg", true)
137*1db9f3b2SDimitry Andric                                .Case("hidden_dynamic_lds_size", true)
1381fd87a68SDimitry Andric                                .Case("hidden_private_base", true)
1391fd87a68SDimitry Andric                                .Case("hidden_shared_base", true)
1401fd87a68SDimitry Andric                                .Case("hidden_queue_ptr", true)
1410b57cec5SDimitry Andric                                .Default(false);
1420b57cec5SDimitry Andric                          }))
1430b57cec5SDimitry Andric     return false;
1440b57cec5SDimitry Andric   if (!verifyIntegerEntry(ArgsMap, ".pointee_align", false))
1450b57cec5SDimitry Andric     return false;
1460b57cec5SDimitry Andric   if (!verifyScalarEntry(ArgsMap, ".address_space", false,
1470b57cec5SDimitry Andric                          msgpack::Type::String,
1480b57cec5SDimitry Andric                          [](msgpack::DocNode &SNode) {
1490b57cec5SDimitry Andric                            return StringSwitch<bool>(SNode.getString())
1500b57cec5SDimitry Andric                                .Case("private", true)
1510b57cec5SDimitry Andric                                .Case("global", true)
1520b57cec5SDimitry Andric                                .Case("constant", true)
1530b57cec5SDimitry Andric                                .Case("local", true)
1540b57cec5SDimitry Andric                                .Case("generic", true)
1550b57cec5SDimitry Andric                                .Case("region", true)
1560b57cec5SDimitry Andric                                .Default(false);
1570b57cec5SDimitry Andric                          }))
1580b57cec5SDimitry Andric     return false;
1590b57cec5SDimitry Andric   if (!verifyScalarEntry(ArgsMap, ".access", false,
1600b57cec5SDimitry Andric                          msgpack::Type::String,
1610b57cec5SDimitry Andric                          [](msgpack::DocNode &SNode) {
1620b57cec5SDimitry Andric                            return StringSwitch<bool>(SNode.getString())
1630b57cec5SDimitry Andric                                .Case("read_only", true)
1640b57cec5SDimitry Andric                                .Case("write_only", true)
1650b57cec5SDimitry Andric                                .Case("read_write", true)
1660b57cec5SDimitry Andric                                .Default(false);
1670b57cec5SDimitry Andric                          }))
1680b57cec5SDimitry Andric     return false;
1690b57cec5SDimitry Andric   if (!verifyScalarEntry(ArgsMap, ".actual_access", false,
1700b57cec5SDimitry Andric                          msgpack::Type::String,
1710b57cec5SDimitry Andric                          [](msgpack::DocNode &SNode) {
1720b57cec5SDimitry Andric                            return StringSwitch<bool>(SNode.getString())
1730b57cec5SDimitry Andric                                .Case("read_only", true)
1740b57cec5SDimitry Andric                                .Case("write_only", true)
1750b57cec5SDimitry Andric                                .Case("read_write", true)
1760b57cec5SDimitry Andric                                .Default(false);
1770b57cec5SDimitry Andric                          }))
1780b57cec5SDimitry Andric     return false;
1790b57cec5SDimitry Andric   if (!verifyScalarEntry(ArgsMap, ".is_const", false,
1800b57cec5SDimitry Andric                          msgpack::Type::Boolean))
1810b57cec5SDimitry Andric     return false;
1820b57cec5SDimitry Andric   if (!verifyScalarEntry(ArgsMap, ".is_restrict", false,
1830b57cec5SDimitry Andric                          msgpack::Type::Boolean))
1840b57cec5SDimitry Andric     return false;
1850b57cec5SDimitry Andric   if (!verifyScalarEntry(ArgsMap, ".is_volatile", false,
1860b57cec5SDimitry Andric                          msgpack::Type::Boolean))
1870b57cec5SDimitry Andric     return false;
1880b57cec5SDimitry Andric   if (!verifyScalarEntry(ArgsMap, ".is_pipe", false,
1890b57cec5SDimitry Andric                          msgpack::Type::Boolean))
1900b57cec5SDimitry Andric     return false;
1910b57cec5SDimitry Andric 
1920b57cec5SDimitry Andric   return true;
1930b57cec5SDimitry Andric }
1940b57cec5SDimitry Andric 
verifyKernel(msgpack::DocNode & Node)1950b57cec5SDimitry Andric bool MetadataVerifier::verifyKernel(msgpack::DocNode &Node) {
1960b57cec5SDimitry Andric   if (!Node.isMap())
1970b57cec5SDimitry Andric     return false;
1980b57cec5SDimitry Andric   auto &KernelMap = Node.getMap();
1990b57cec5SDimitry Andric 
2000b57cec5SDimitry Andric   if (!verifyScalarEntry(KernelMap, ".name", true,
2010b57cec5SDimitry Andric                          msgpack::Type::String))
2020b57cec5SDimitry Andric     return false;
2030b57cec5SDimitry Andric   if (!verifyScalarEntry(KernelMap, ".symbol", true,
2040b57cec5SDimitry Andric                          msgpack::Type::String))
2050b57cec5SDimitry Andric     return false;
2060b57cec5SDimitry Andric   if (!verifyScalarEntry(KernelMap, ".language", false,
2070b57cec5SDimitry Andric                          msgpack::Type::String,
2080b57cec5SDimitry Andric                          [](msgpack::DocNode &SNode) {
2090b57cec5SDimitry Andric                            return StringSwitch<bool>(SNode.getString())
2100b57cec5SDimitry Andric                                .Case("OpenCL C", true)
2110b57cec5SDimitry Andric                                .Case("OpenCL C++", true)
2120b57cec5SDimitry Andric                                .Case("HCC", true)
2130b57cec5SDimitry Andric                                .Case("HIP", true)
2140b57cec5SDimitry Andric                                .Case("OpenMP", true)
2150b57cec5SDimitry Andric                                .Case("Assembler", true)
2160b57cec5SDimitry Andric                                .Default(false);
2170b57cec5SDimitry Andric                          }))
2180b57cec5SDimitry Andric     return false;
2190b57cec5SDimitry Andric   if (!verifyEntry(
2200b57cec5SDimitry Andric           KernelMap, ".language_version", false, [this](msgpack::DocNode &Node) {
2210b57cec5SDimitry Andric             return verifyArray(
2220b57cec5SDimitry Andric                 Node,
2230b57cec5SDimitry Andric                 [this](msgpack::DocNode &Node) { return verifyInteger(Node); }, 2);
2240b57cec5SDimitry Andric           }))
2250b57cec5SDimitry Andric     return false;
2260b57cec5SDimitry Andric   if (!verifyEntry(KernelMap, ".args", false, [this](msgpack::DocNode &Node) {
2270b57cec5SDimitry Andric         return verifyArray(Node, [this](msgpack::DocNode &Node) {
2280b57cec5SDimitry Andric           return verifyKernelArgs(Node);
2290b57cec5SDimitry Andric         });
2300b57cec5SDimitry Andric       }))
2310b57cec5SDimitry Andric     return false;
2320b57cec5SDimitry Andric   if (!verifyEntry(KernelMap, ".reqd_workgroup_size", false,
2330b57cec5SDimitry Andric                    [this](msgpack::DocNode &Node) {
2340b57cec5SDimitry Andric                      return verifyArray(Node,
2350b57cec5SDimitry Andric                                         [this](msgpack::DocNode &Node) {
2360b57cec5SDimitry Andric                                           return verifyInteger(Node);
2370b57cec5SDimitry Andric                                         },
2380b57cec5SDimitry Andric                                         3);
2390b57cec5SDimitry Andric                    }))
2400b57cec5SDimitry Andric     return false;
2410b57cec5SDimitry Andric   if (!verifyEntry(KernelMap, ".workgroup_size_hint", false,
2420b57cec5SDimitry Andric                    [this](msgpack::DocNode &Node) {
2430b57cec5SDimitry Andric                      return verifyArray(Node,
2440b57cec5SDimitry Andric                                         [this](msgpack::DocNode &Node) {
2450b57cec5SDimitry Andric                                           return verifyInteger(Node);
2460b57cec5SDimitry Andric                                         },
2470b57cec5SDimitry Andric                                         3);
2480b57cec5SDimitry Andric                    }))
2490b57cec5SDimitry Andric     return false;
2500b57cec5SDimitry Andric   if (!verifyScalarEntry(KernelMap, ".vec_type_hint", false,
2510b57cec5SDimitry Andric                          msgpack::Type::String))
2520b57cec5SDimitry Andric     return false;
2530b57cec5SDimitry Andric   if (!verifyScalarEntry(KernelMap, ".device_enqueue_symbol", false,
2540b57cec5SDimitry Andric                          msgpack::Type::String))
2550b57cec5SDimitry Andric     return false;
2560b57cec5SDimitry Andric   if (!verifyIntegerEntry(KernelMap, ".kernarg_segment_size", true))
2570b57cec5SDimitry Andric     return false;
2580b57cec5SDimitry Andric   if (!verifyIntegerEntry(KernelMap, ".group_segment_fixed_size", true))
2590b57cec5SDimitry Andric     return false;
2600b57cec5SDimitry Andric   if (!verifyIntegerEntry(KernelMap, ".private_segment_fixed_size", true))
2610b57cec5SDimitry Andric     return false;
262fcaf7f86SDimitry Andric   if (!verifyScalarEntry(KernelMap, ".uses_dynamic_stack", false,
263fcaf7f86SDimitry Andric                          msgpack::Type::Boolean))
264fcaf7f86SDimitry Andric     return false;
265bdd1243dSDimitry Andric   if (!verifyIntegerEntry(KernelMap, ".workgroup_processor_mode", false))
266bdd1243dSDimitry Andric     return false;
2670b57cec5SDimitry Andric   if (!verifyIntegerEntry(KernelMap, ".kernarg_segment_align", true))
2680b57cec5SDimitry Andric     return false;
2690b57cec5SDimitry Andric   if (!verifyIntegerEntry(KernelMap, ".wavefront_size", true))
2700b57cec5SDimitry Andric     return false;
2710b57cec5SDimitry Andric   if (!verifyIntegerEntry(KernelMap, ".sgpr_count", true))
2720b57cec5SDimitry Andric     return false;
2730b57cec5SDimitry Andric   if (!verifyIntegerEntry(KernelMap, ".vgpr_count", true))
2740b57cec5SDimitry Andric     return false;
2750b57cec5SDimitry Andric   if (!verifyIntegerEntry(KernelMap, ".max_flat_workgroup_size", true))
2760b57cec5SDimitry Andric     return false;
2770b57cec5SDimitry Andric   if (!verifyIntegerEntry(KernelMap, ".sgpr_spill_count", false))
2780b57cec5SDimitry Andric     return false;
2790b57cec5SDimitry Andric   if (!verifyIntegerEntry(KernelMap, ".vgpr_spill_count", false))
2800b57cec5SDimitry Andric     return false;
281bdd1243dSDimitry Andric   if (!verifyIntegerEntry(KernelMap, ".uniform_work_group_size", false))
282bdd1243dSDimitry Andric     return false;
283bdd1243dSDimitry Andric 
2840b57cec5SDimitry Andric 
2850b57cec5SDimitry Andric   return true;
2860b57cec5SDimitry Andric }
2870b57cec5SDimitry Andric 
verify(msgpack::DocNode & HSAMetadataRoot)2880b57cec5SDimitry Andric bool MetadataVerifier::verify(msgpack::DocNode &HSAMetadataRoot) {
2890b57cec5SDimitry Andric   if (!HSAMetadataRoot.isMap())
2900b57cec5SDimitry Andric     return false;
2910b57cec5SDimitry Andric   auto &RootMap = HSAMetadataRoot.getMap();
2920b57cec5SDimitry Andric 
2930b57cec5SDimitry Andric   if (!verifyEntry(
2940b57cec5SDimitry Andric           RootMap, "amdhsa.version", true, [this](msgpack::DocNode &Node) {
2950b57cec5SDimitry Andric             return verifyArray(
2960b57cec5SDimitry Andric                 Node,
2970b57cec5SDimitry Andric                 [this](msgpack::DocNode &Node) { return verifyInteger(Node); }, 2);
2980b57cec5SDimitry Andric           }))
2990b57cec5SDimitry Andric     return false;
3000b57cec5SDimitry Andric   if (!verifyEntry(
3010b57cec5SDimitry Andric           RootMap, "amdhsa.printf", false, [this](msgpack::DocNode &Node) {
3020b57cec5SDimitry Andric             return verifyArray(Node, [this](msgpack::DocNode &Node) {
3030b57cec5SDimitry Andric               return verifyScalar(Node, msgpack::Type::String);
3040b57cec5SDimitry Andric             });
3050b57cec5SDimitry Andric           }))
3060b57cec5SDimitry Andric     return false;
3070b57cec5SDimitry Andric   if (!verifyEntry(RootMap, "amdhsa.kernels", true,
3080b57cec5SDimitry Andric                    [this](msgpack::DocNode &Node) {
3090b57cec5SDimitry Andric                      return verifyArray(Node, [this](msgpack::DocNode &Node) {
3100b57cec5SDimitry Andric                        return verifyKernel(Node);
3110b57cec5SDimitry Andric                      });
3120b57cec5SDimitry Andric                    }))
3130b57cec5SDimitry Andric     return false;
3140b57cec5SDimitry Andric 
3150b57cec5SDimitry Andric   return true;
3160b57cec5SDimitry Andric }
3170b57cec5SDimitry Andric 
3180b57cec5SDimitry Andric } // end namespace V3
3190b57cec5SDimitry Andric } // end namespace HSAMD
3200b57cec5SDimitry Andric } // end namespace AMDGPU
3210b57cec5SDimitry Andric } // end namespace llvm
322