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 <map> 2104eeddc0SDimitry Andric #include <utility> 220b57cec5SDimitry Andric 230b57cec5SDimitry Andric namespace llvm { 240b57cec5SDimitry Andric namespace AMDGPU { 250b57cec5SDimitry Andric namespace HSAMD { 260b57cec5SDimitry Andric namespace V3 { 270b57cec5SDimitry Andric 280b57cec5SDimitry Andric bool MetadataVerifier::verifyScalar( 290b57cec5SDimitry Andric msgpack::DocNode &Node, msgpack::Type SKind, 300b57cec5SDimitry Andric function_ref<bool(msgpack::DocNode &)> verifyValue) { 310b57cec5SDimitry Andric if (!Node.isScalar()) 320b57cec5SDimitry Andric return false; 330b57cec5SDimitry Andric if (Node.getKind() != SKind) { 340b57cec5SDimitry Andric if (Strict) 350b57cec5SDimitry Andric return false; 360b57cec5SDimitry Andric // If we are not strict, we interpret string values as "implicitly typed" 370b57cec5SDimitry Andric // and attempt to coerce them to the expected type here. 380b57cec5SDimitry Andric if (Node.getKind() != msgpack::Type::String) 390b57cec5SDimitry Andric return false; 400b57cec5SDimitry Andric StringRef StringValue = Node.getString(); 410b57cec5SDimitry Andric Node.fromString(StringValue); 420b57cec5SDimitry Andric if (Node.getKind() != SKind) 430b57cec5SDimitry Andric return false; 440b57cec5SDimitry Andric } 450b57cec5SDimitry Andric if (verifyValue) 460b57cec5SDimitry Andric return verifyValue(Node); 470b57cec5SDimitry Andric return true; 480b57cec5SDimitry Andric } 490b57cec5SDimitry Andric 500b57cec5SDimitry Andric bool MetadataVerifier::verifyInteger(msgpack::DocNode &Node) { 510b57cec5SDimitry Andric if (!verifyScalar(Node, msgpack::Type::UInt)) 520b57cec5SDimitry Andric if (!verifyScalar(Node, msgpack::Type::Int)) 530b57cec5SDimitry Andric return false; 540b57cec5SDimitry Andric return true; 550b57cec5SDimitry Andric } 560b57cec5SDimitry Andric 570b57cec5SDimitry Andric bool MetadataVerifier::verifyArray( 580b57cec5SDimitry Andric msgpack::DocNode &Node, function_ref<bool(msgpack::DocNode &)> verifyNode, 59*bdd1243dSDimitry Andric std::optional<size_t> Size) { 600b57cec5SDimitry Andric if (!Node.isArray()) 610b57cec5SDimitry Andric return false; 620b57cec5SDimitry Andric auto &Array = Node.getArray(); 630b57cec5SDimitry Andric if (Size && Array.size() != *Size) 640b57cec5SDimitry Andric return false; 650eae32dcSDimitry Andric return llvm::all_of(Array, verifyNode); 660b57cec5SDimitry Andric } 670b57cec5SDimitry Andric 680b57cec5SDimitry Andric bool MetadataVerifier::verifyEntry( 690b57cec5SDimitry Andric msgpack::MapDocNode &MapNode, StringRef Key, bool Required, 700b57cec5SDimitry Andric function_ref<bool(msgpack::DocNode &)> verifyNode) { 710b57cec5SDimitry Andric auto Entry = MapNode.find(Key); 720b57cec5SDimitry Andric if (Entry == MapNode.end()) 730b57cec5SDimitry Andric return !Required; 740b57cec5SDimitry Andric return verifyNode(Entry->second); 750b57cec5SDimitry Andric } 760b57cec5SDimitry Andric 770b57cec5SDimitry Andric bool MetadataVerifier::verifyScalarEntry( 780b57cec5SDimitry Andric msgpack::MapDocNode &MapNode, StringRef Key, bool Required, 790b57cec5SDimitry Andric msgpack::Type SKind, 800b57cec5SDimitry Andric function_ref<bool(msgpack::DocNode &)> verifyValue) { 810b57cec5SDimitry Andric return verifyEntry(MapNode, Key, Required, [=](msgpack::DocNode &Node) { 820b57cec5SDimitry Andric return verifyScalar(Node, SKind, verifyValue); 830b57cec5SDimitry Andric }); 840b57cec5SDimitry Andric } 850b57cec5SDimitry Andric 860b57cec5SDimitry Andric bool MetadataVerifier::verifyIntegerEntry(msgpack::MapDocNode &MapNode, 870b57cec5SDimitry Andric StringRef Key, bool Required) { 880b57cec5SDimitry Andric return verifyEntry(MapNode, Key, Required, [this](msgpack::DocNode &Node) { 890b57cec5SDimitry Andric return verifyInteger(Node); 900b57cec5SDimitry Andric }); 910b57cec5SDimitry Andric } 920b57cec5SDimitry Andric 930b57cec5SDimitry Andric bool MetadataVerifier::verifyKernelArgs(msgpack::DocNode &Node) { 940b57cec5SDimitry Andric if (!Node.isMap()) 950b57cec5SDimitry Andric return false; 960b57cec5SDimitry Andric auto &ArgsMap = Node.getMap(); 970b57cec5SDimitry Andric 980b57cec5SDimitry Andric if (!verifyScalarEntry(ArgsMap, ".name", false, 990b57cec5SDimitry Andric msgpack::Type::String)) 1000b57cec5SDimitry Andric return false; 1010b57cec5SDimitry Andric if (!verifyScalarEntry(ArgsMap, ".type_name", false, 1020b57cec5SDimitry Andric msgpack::Type::String)) 1030b57cec5SDimitry Andric return false; 1040b57cec5SDimitry Andric if (!verifyIntegerEntry(ArgsMap, ".size", true)) 1050b57cec5SDimitry Andric return false; 1060b57cec5SDimitry Andric if (!verifyIntegerEntry(ArgsMap, ".offset", true)) 1070b57cec5SDimitry Andric return false; 10881ad6265SDimitry Andric if (!verifyScalarEntry(ArgsMap, ".value_kind", true, msgpack::Type::String, 1090b57cec5SDimitry Andric [](msgpack::DocNode &SNode) { 1100b57cec5SDimitry Andric return StringSwitch<bool>(SNode.getString()) 1110b57cec5SDimitry Andric .Case("by_value", true) 1120b57cec5SDimitry Andric .Case("global_buffer", true) 1130b57cec5SDimitry Andric .Case("dynamic_shared_pointer", true) 1140b57cec5SDimitry Andric .Case("sampler", true) 1150b57cec5SDimitry Andric .Case("image", true) 1160b57cec5SDimitry Andric .Case("pipe", true) 1170b57cec5SDimitry Andric .Case("queue", true) 1181fd87a68SDimitry Andric .Case("hidden_block_count_x", true) 1191fd87a68SDimitry Andric .Case("hidden_block_count_y", true) 1201fd87a68SDimitry Andric .Case("hidden_block_count_z", true) 1211fd87a68SDimitry Andric .Case("hidden_group_size_x", true) 1221fd87a68SDimitry Andric .Case("hidden_group_size_y", true) 1231fd87a68SDimitry Andric .Case("hidden_group_size_z", true) 1241fd87a68SDimitry Andric .Case("hidden_remainder_x", true) 1251fd87a68SDimitry Andric .Case("hidden_remainder_y", true) 1261fd87a68SDimitry Andric .Case("hidden_remainder_z", true) 1270b57cec5SDimitry Andric .Case("hidden_global_offset_x", true) 1280b57cec5SDimitry Andric .Case("hidden_global_offset_y", true) 1290b57cec5SDimitry Andric .Case("hidden_global_offset_z", true) 1301fd87a68SDimitry Andric .Case("hidden_grid_dims", true) 1310b57cec5SDimitry Andric .Case("hidden_none", true) 1320b57cec5SDimitry Andric .Case("hidden_printf_buffer", true) 133480093f4SDimitry Andric .Case("hidden_hostcall_buffer", true) 13481ad6265SDimitry Andric .Case("hidden_heap_v1", true) 1350b57cec5SDimitry Andric .Case("hidden_default_queue", true) 1360b57cec5SDimitry Andric .Case("hidden_completion_action", true) 1370b57cec5SDimitry Andric .Case("hidden_multigrid_sync_arg", 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 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; 265*bdd1243dSDimitry Andric if (!verifyIntegerEntry(KernelMap, ".workgroup_processor_mode", false)) 266*bdd1243dSDimitry 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; 281*bdd1243dSDimitry Andric if (!verifyIntegerEntry(KernelMap, ".uniform_work_group_size", false)) 282*bdd1243dSDimitry Andric return false; 283*bdd1243dSDimitry Andric 2840b57cec5SDimitry Andric 2850b57cec5SDimitry Andric return true; 2860b57cec5SDimitry Andric } 2870b57cec5SDimitry Andric 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