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" 1704eeddc0SDimitry Andric #include "llvm/ADT/STLForwardCompat.h" 185ffd83dbSDimitry Andric #include "llvm/ADT/StringSwitch.h" 1904eeddc0SDimitry Andric #include "llvm/BinaryFormat/MsgPackDocument.h" 2004eeddc0SDimitry Andric 2104eeddc0SDimitry Andric #include <map> 2204eeddc0SDimitry Andric #include <utility> 230b57cec5SDimitry Andric 240b57cec5SDimitry Andric namespace llvm { 250b57cec5SDimitry Andric namespace AMDGPU { 260b57cec5SDimitry Andric namespace HSAMD { 270b57cec5SDimitry Andric namespace V3 { 280b57cec5SDimitry Andric 290b57cec5SDimitry Andric bool MetadataVerifier::verifyScalar( 300b57cec5SDimitry Andric msgpack::DocNode &Node, msgpack::Type SKind, 310b57cec5SDimitry Andric function_ref<bool(msgpack::DocNode &)> verifyValue) { 320b57cec5SDimitry Andric if (!Node.isScalar()) 330b57cec5SDimitry Andric return false; 340b57cec5SDimitry Andric if (Node.getKind() != SKind) { 350b57cec5SDimitry Andric if (Strict) 360b57cec5SDimitry Andric return false; 370b57cec5SDimitry Andric // If we are not strict, we interpret string values as "implicitly typed" 380b57cec5SDimitry Andric // and attempt to coerce them to the expected type here. 390b57cec5SDimitry Andric if (Node.getKind() != msgpack::Type::String) 400b57cec5SDimitry Andric return false; 410b57cec5SDimitry Andric StringRef StringValue = Node.getString(); 420b57cec5SDimitry Andric Node.fromString(StringValue); 430b57cec5SDimitry Andric if (Node.getKind() != SKind) 440b57cec5SDimitry Andric return false; 450b57cec5SDimitry Andric } 460b57cec5SDimitry Andric if (verifyValue) 470b57cec5SDimitry Andric return verifyValue(Node); 480b57cec5SDimitry Andric return true; 490b57cec5SDimitry Andric } 500b57cec5SDimitry Andric 510b57cec5SDimitry Andric bool MetadataVerifier::verifyInteger(msgpack::DocNode &Node) { 520b57cec5SDimitry Andric if (!verifyScalar(Node, msgpack::Type::UInt)) 530b57cec5SDimitry Andric if (!verifyScalar(Node, msgpack::Type::Int)) 540b57cec5SDimitry Andric return false; 550b57cec5SDimitry Andric return true; 560b57cec5SDimitry Andric } 570b57cec5SDimitry Andric 580b57cec5SDimitry Andric bool MetadataVerifier::verifyArray( 590b57cec5SDimitry Andric msgpack::DocNode &Node, function_ref<bool(msgpack::DocNode &)> verifyNode, 600b57cec5SDimitry Andric Optional<size_t> Size) { 610b57cec5SDimitry Andric if (!Node.isArray()) 620b57cec5SDimitry Andric return false; 630b57cec5SDimitry Andric auto &Array = Node.getArray(); 640b57cec5SDimitry Andric if (Size && Array.size() != *Size) 650b57cec5SDimitry Andric return false; 660eae32dcSDimitry Andric return llvm::all_of(Array, verifyNode); 670b57cec5SDimitry Andric } 680b57cec5SDimitry Andric 690b57cec5SDimitry Andric bool MetadataVerifier::verifyEntry( 700b57cec5SDimitry Andric msgpack::MapDocNode &MapNode, StringRef Key, bool Required, 710b57cec5SDimitry Andric function_ref<bool(msgpack::DocNode &)> verifyNode) { 720b57cec5SDimitry Andric auto Entry = MapNode.find(Key); 730b57cec5SDimitry Andric if (Entry == MapNode.end()) 740b57cec5SDimitry Andric return !Required; 750b57cec5SDimitry Andric return verifyNode(Entry->second); 760b57cec5SDimitry Andric } 770b57cec5SDimitry Andric 780b57cec5SDimitry Andric bool MetadataVerifier::verifyScalarEntry( 790b57cec5SDimitry Andric msgpack::MapDocNode &MapNode, StringRef Key, bool Required, 800b57cec5SDimitry Andric msgpack::Type SKind, 810b57cec5SDimitry Andric function_ref<bool(msgpack::DocNode &)> verifyValue) { 820b57cec5SDimitry Andric return verifyEntry(MapNode, Key, Required, [=](msgpack::DocNode &Node) { 830b57cec5SDimitry Andric return verifyScalar(Node, SKind, verifyValue); 840b57cec5SDimitry Andric }); 850b57cec5SDimitry Andric } 860b57cec5SDimitry Andric 870b57cec5SDimitry Andric bool MetadataVerifier::verifyIntegerEntry(msgpack::MapDocNode &MapNode, 880b57cec5SDimitry Andric StringRef Key, bool Required) { 890b57cec5SDimitry Andric return verifyEntry(MapNode, Key, Required, [this](msgpack::DocNode &Node) { 900b57cec5SDimitry Andric return verifyInteger(Node); 910b57cec5SDimitry Andric }); 920b57cec5SDimitry Andric } 930b57cec5SDimitry Andric 940b57cec5SDimitry Andric bool MetadataVerifier::verifyKernelArgs(msgpack::DocNode &Node) { 950b57cec5SDimitry Andric if (!Node.isMap()) 960b57cec5SDimitry Andric return false; 970b57cec5SDimitry Andric auto &ArgsMap = Node.getMap(); 980b57cec5SDimitry Andric 990b57cec5SDimitry Andric if (!verifyScalarEntry(ArgsMap, ".name", false, 1000b57cec5SDimitry Andric msgpack::Type::String)) 1010b57cec5SDimitry Andric return false; 1020b57cec5SDimitry Andric if (!verifyScalarEntry(ArgsMap, ".type_name", false, 1030b57cec5SDimitry Andric msgpack::Type::String)) 1040b57cec5SDimitry Andric return false; 1050b57cec5SDimitry Andric if (!verifyIntegerEntry(ArgsMap, ".size", true)) 1060b57cec5SDimitry Andric return false; 1070b57cec5SDimitry Andric if (!verifyIntegerEntry(ArgsMap, ".offset", true)) 1080b57cec5SDimitry Andric return false; 1090b57cec5SDimitry Andric if (!verifyScalarEntry(ArgsMap, ".value_kind", true, 1100b57cec5SDimitry Andric msgpack::Type::String, 1110b57cec5SDimitry Andric [](msgpack::DocNode &SNode) { 1120b57cec5SDimitry Andric return StringSwitch<bool>(SNode.getString()) 1130b57cec5SDimitry Andric .Case("by_value", true) 1140b57cec5SDimitry Andric .Case("global_buffer", true) 1150b57cec5SDimitry Andric .Case("dynamic_shared_pointer", true) 1160b57cec5SDimitry Andric .Case("sampler", true) 1170b57cec5SDimitry Andric .Case("image", true) 1180b57cec5SDimitry Andric .Case("pipe", true) 1190b57cec5SDimitry Andric .Case("queue", true) 120*1fd87a68SDimitry Andric .Case("hidden_block_count_x", true) 121*1fd87a68SDimitry Andric .Case("hidden_block_count_y", true) 122*1fd87a68SDimitry Andric .Case("hidden_block_count_z", true) 123*1fd87a68SDimitry Andric .Case("hidden_group_size_x", true) 124*1fd87a68SDimitry Andric .Case("hidden_group_size_y", true) 125*1fd87a68SDimitry Andric .Case("hidden_group_size_z", true) 126*1fd87a68SDimitry Andric .Case("hidden_remainder_x", true) 127*1fd87a68SDimitry Andric .Case("hidden_remainder_y", true) 128*1fd87a68SDimitry Andric .Case("hidden_remainder_z", true) 1290b57cec5SDimitry Andric .Case("hidden_global_offset_x", true) 1300b57cec5SDimitry Andric .Case("hidden_global_offset_y", true) 1310b57cec5SDimitry Andric .Case("hidden_global_offset_z", true) 132*1fd87a68SDimitry Andric .Case("hidden_grid_dims", true) 1330b57cec5SDimitry Andric .Case("hidden_none", true) 1340b57cec5SDimitry Andric .Case("hidden_printf_buffer", true) 135480093f4SDimitry Andric .Case("hidden_hostcall_buffer", true) 1360b57cec5SDimitry Andric .Case("hidden_default_queue", true) 1370b57cec5SDimitry Andric .Case("hidden_completion_action", true) 1380b57cec5SDimitry Andric .Case("hidden_multigrid_sync_arg", true) 139*1fd87a68SDimitry Andric .Case("hidden_private_base", true) 140*1fd87a68SDimitry Andric .Case("hidden_shared_base", true) 141*1fd87a68SDimitry Andric .Case("hidden_queue_ptr", true) 1420b57cec5SDimitry Andric .Default(false); 1430b57cec5SDimitry Andric })) 1440b57cec5SDimitry Andric return false; 1450b57cec5SDimitry Andric if (!verifyIntegerEntry(ArgsMap, ".pointee_align", false)) 1460b57cec5SDimitry Andric return false; 1470b57cec5SDimitry Andric if (!verifyScalarEntry(ArgsMap, ".address_space", false, 1480b57cec5SDimitry Andric msgpack::Type::String, 1490b57cec5SDimitry Andric [](msgpack::DocNode &SNode) { 1500b57cec5SDimitry Andric return StringSwitch<bool>(SNode.getString()) 1510b57cec5SDimitry Andric .Case("private", true) 1520b57cec5SDimitry Andric .Case("global", true) 1530b57cec5SDimitry Andric .Case("constant", true) 1540b57cec5SDimitry Andric .Case("local", true) 1550b57cec5SDimitry Andric .Case("generic", true) 1560b57cec5SDimitry Andric .Case("region", true) 1570b57cec5SDimitry Andric .Default(false); 1580b57cec5SDimitry Andric })) 1590b57cec5SDimitry Andric return false; 1600b57cec5SDimitry Andric if (!verifyScalarEntry(ArgsMap, ".access", false, 1610b57cec5SDimitry Andric msgpack::Type::String, 1620b57cec5SDimitry Andric [](msgpack::DocNode &SNode) { 1630b57cec5SDimitry Andric return StringSwitch<bool>(SNode.getString()) 1640b57cec5SDimitry Andric .Case("read_only", true) 1650b57cec5SDimitry Andric .Case("write_only", true) 1660b57cec5SDimitry Andric .Case("read_write", true) 1670b57cec5SDimitry Andric .Default(false); 1680b57cec5SDimitry Andric })) 1690b57cec5SDimitry Andric return false; 1700b57cec5SDimitry Andric if (!verifyScalarEntry(ArgsMap, ".actual_access", false, 1710b57cec5SDimitry Andric msgpack::Type::String, 1720b57cec5SDimitry Andric [](msgpack::DocNode &SNode) { 1730b57cec5SDimitry Andric return StringSwitch<bool>(SNode.getString()) 1740b57cec5SDimitry Andric .Case("read_only", true) 1750b57cec5SDimitry Andric .Case("write_only", true) 1760b57cec5SDimitry Andric .Case("read_write", true) 1770b57cec5SDimitry Andric .Default(false); 1780b57cec5SDimitry Andric })) 1790b57cec5SDimitry Andric return false; 1800b57cec5SDimitry Andric if (!verifyScalarEntry(ArgsMap, ".is_const", false, 1810b57cec5SDimitry Andric msgpack::Type::Boolean)) 1820b57cec5SDimitry Andric return false; 1830b57cec5SDimitry Andric if (!verifyScalarEntry(ArgsMap, ".is_restrict", false, 1840b57cec5SDimitry Andric msgpack::Type::Boolean)) 1850b57cec5SDimitry Andric return false; 1860b57cec5SDimitry Andric if (!verifyScalarEntry(ArgsMap, ".is_volatile", false, 1870b57cec5SDimitry Andric msgpack::Type::Boolean)) 1880b57cec5SDimitry Andric return false; 1890b57cec5SDimitry Andric if (!verifyScalarEntry(ArgsMap, ".is_pipe", false, 1900b57cec5SDimitry Andric msgpack::Type::Boolean)) 1910b57cec5SDimitry Andric return false; 1920b57cec5SDimitry Andric 1930b57cec5SDimitry Andric return true; 1940b57cec5SDimitry Andric } 1950b57cec5SDimitry Andric 1960b57cec5SDimitry Andric bool MetadataVerifier::verifyKernel(msgpack::DocNode &Node) { 1970b57cec5SDimitry Andric if (!Node.isMap()) 1980b57cec5SDimitry Andric return false; 1990b57cec5SDimitry Andric auto &KernelMap = Node.getMap(); 2000b57cec5SDimitry Andric 2010b57cec5SDimitry Andric if (!verifyScalarEntry(KernelMap, ".name", true, 2020b57cec5SDimitry Andric msgpack::Type::String)) 2030b57cec5SDimitry Andric return false; 2040b57cec5SDimitry Andric if (!verifyScalarEntry(KernelMap, ".symbol", true, 2050b57cec5SDimitry Andric msgpack::Type::String)) 2060b57cec5SDimitry Andric return false; 2070b57cec5SDimitry Andric if (!verifyScalarEntry(KernelMap, ".language", false, 2080b57cec5SDimitry Andric msgpack::Type::String, 2090b57cec5SDimitry Andric [](msgpack::DocNode &SNode) { 2100b57cec5SDimitry Andric return StringSwitch<bool>(SNode.getString()) 2110b57cec5SDimitry Andric .Case("OpenCL C", true) 2120b57cec5SDimitry Andric .Case("OpenCL C++", true) 2130b57cec5SDimitry Andric .Case("HCC", true) 2140b57cec5SDimitry Andric .Case("HIP", true) 2150b57cec5SDimitry Andric .Case("OpenMP", true) 2160b57cec5SDimitry Andric .Case("Assembler", true) 2170b57cec5SDimitry Andric .Default(false); 2180b57cec5SDimitry Andric })) 2190b57cec5SDimitry Andric return false; 2200b57cec5SDimitry Andric if (!verifyEntry( 2210b57cec5SDimitry Andric KernelMap, ".language_version", false, [this](msgpack::DocNode &Node) { 2220b57cec5SDimitry Andric return verifyArray( 2230b57cec5SDimitry Andric Node, 2240b57cec5SDimitry Andric [this](msgpack::DocNode &Node) { return verifyInteger(Node); }, 2); 2250b57cec5SDimitry Andric })) 2260b57cec5SDimitry Andric return false; 2270b57cec5SDimitry Andric if (!verifyEntry(KernelMap, ".args", false, [this](msgpack::DocNode &Node) { 2280b57cec5SDimitry Andric return verifyArray(Node, [this](msgpack::DocNode &Node) { 2290b57cec5SDimitry Andric return verifyKernelArgs(Node); 2300b57cec5SDimitry Andric }); 2310b57cec5SDimitry Andric })) 2320b57cec5SDimitry Andric return false; 2330b57cec5SDimitry Andric if (!verifyEntry(KernelMap, ".reqd_workgroup_size", false, 2340b57cec5SDimitry Andric [this](msgpack::DocNode &Node) { 2350b57cec5SDimitry Andric return verifyArray(Node, 2360b57cec5SDimitry Andric [this](msgpack::DocNode &Node) { 2370b57cec5SDimitry Andric return verifyInteger(Node); 2380b57cec5SDimitry Andric }, 2390b57cec5SDimitry Andric 3); 2400b57cec5SDimitry Andric })) 2410b57cec5SDimitry Andric return false; 2420b57cec5SDimitry Andric if (!verifyEntry(KernelMap, ".workgroup_size_hint", false, 2430b57cec5SDimitry Andric [this](msgpack::DocNode &Node) { 2440b57cec5SDimitry Andric return verifyArray(Node, 2450b57cec5SDimitry Andric [this](msgpack::DocNode &Node) { 2460b57cec5SDimitry Andric return verifyInteger(Node); 2470b57cec5SDimitry Andric }, 2480b57cec5SDimitry Andric 3); 2490b57cec5SDimitry Andric })) 2500b57cec5SDimitry Andric return false; 2510b57cec5SDimitry Andric if (!verifyScalarEntry(KernelMap, ".vec_type_hint", false, 2520b57cec5SDimitry Andric msgpack::Type::String)) 2530b57cec5SDimitry Andric return false; 2540b57cec5SDimitry Andric if (!verifyScalarEntry(KernelMap, ".device_enqueue_symbol", false, 2550b57cec5SDimitry Andric msgpack::Type::String)) 2560b57cec5SDimitry Andric return false; 2570b57cec5SDimitry Andric if (!verifyIntegerEntry(KernelMap, ".kernarg_segment_size", true)) 2580b57cec5SDimitry Andric return false; 2590b57cec5SDimitry Andric if (!verifyIntegerEntry(KernelMap, ".group_segment_fixed_size", true)) 2600b57cec5SDimitry Andric return false; 2610b57cec5SDimitry Andric if (!verifyIntegerEntry(KernelMap, ".private_segment_fixed_size", true)) 2620b57cec5SDimitry Andric return false; 2630b57cec5SDimitry Andric if (!verifyIntegerEntry(KernelMap, ".kernarg_segment_align", true)) 2640b57cec5SDimitry Andric return false; 2650b57cec5SDimitry Andric if (!verifyIntegerEntry(KernelMap, ".wavefront_size", true)) 2660b57cec5SDimitry Andric return false; 2670b57cec5SDimitry Andric if (!verifyIntegerEntry(KernelMap, ".sgpr_count", true)) 2680b57cec5SDimitry Andric return false; 2690b57cec5SDimitry Andric if (!verifyIntegerEntry(KernelMap, ".vgpr_count", true)) 2700b57cec5SDimitry Andric return false; 2710b57cec5SDimitry Andric if (!verifyIntegerEntry(KernelMap, ".max_flat_workgroup_size", true)) 2720b57cec5SDimitry Andric return false; 2730b57cec5SDimitry Andric if (!verifyIntegerEntry(KernelMap, ".sgpr_spill_count", false)) 2740b57cec5SDimitry Andric return false; 2750b57cec5SDimitry Andric if (!verifyIntegerEntry(KernelMap, ".vgpr_spill_count", false)) 2760b57cec5SDimitry Andric return false; 2770b57cec5SDimitry Andric 2780b57cec5SDimitry Andric return true; 2790b57cec5SDimitry Andric } 2800b57cec5SDimitry Andric 2810b57cec5SDimitry Andric bool MetadataVerifier::verify(msgpack::DocNode &HSAMetadataRoot) { 2820b57cec5SDimitry Andric if (!HSAMetadataRoot.isMap()) 2830b57cec5SDimitry Andric return false; 2840b57cec5SDimitry Andric auto &RootMap = HSAMetadataRoot.getMap(); 2850b57cec5SDimitry Andric 2860b57cec5SDimitry Andric if (!verifyEntry( 2870b57cec5SDimitry Andric RootMap, "amdhsa.version", true, [this](msgpack::DocNode &Node) { 2880b57cec5SDimitry Andric return verifyArray( 2890b57cec5SDimitry Andric Node, 2900b57cec5SDimitry Andric [this](msgpack::DocNode &Node) { return verifyInteger(Node); }, 2); 2910b57cec5SDimitry Andric })) 2920b57cec5SDimitry Andric return false; 2930b57cec5SDimitry Andric if (!verifyEntry( 2940b57cec5SDimitry Andric RootMap, "amdhsa.printf", false, [this](msgpack::DocNode &Node) { 2950b57cec5SDimitry Andric return verifyArray(Node, [this](msgpack::DocNode &Node) { 2960b57cec5SDimitry Andric return verifyScalar(Node, msgpack::Type::String); 2970b57cec5SDimitry Andric }); 2980b57cec5SDimitry Andric })) 2990b57cec5SDimitry Andric return false; 3000b57cec5SDimitry Andric if (!verifyEntry(RootMap, "amdhsa.kernels", true, 3010b57cec5SDimitry Andric [this](msgpack::DocNode &Node) { 3020b57cec5SDimitry Andric return verifyArray(Node, [this](msgpack::DocNode &Node) { 3030b57cec5SDimitry Andric return verifyKernel(Node); 3040b57cec5SDimitry Andric }); 3050b57cec5SDimitry Andric })) 3060b57cec5SDimitry Andric return false; 3070b57cec5SDimitry Andric 3080b57cec5SDimitry Andric return true; 3090b57cec5SDimitry Andric } 3100b57cec5SDimitry Andric 3110b57cec5SDimitry Andric } // end namespace V3 3120b57cec5SDimitry Andric } // end namespace HSAMD 3130b57cec5SDimitry Andric } // end namespace AMDGPU 3140b57cec5SDimitry Andric } // end namespace llvm 315