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" 15*04eeddc0SDimitry Andric 16*04eeddc0SDimitry Andric #include "llvm/ADT/STLExtras.h" 17*04eeddc0SDimitry Andric #include "llvm/ADT/STLForwardCompat.h" 185ffd83dbSDimitry Andric #include "llvm/ADT/StringSwitch.h" 19*04eeddc0SDimitry Andric #include "llvm/BinaryFormat/MsgPackDocument.h" 20*04eeddc0SDimitry Andric 21*04eeddc0SDimitry Andric #include <map> 22*04eeddc0SDimitry 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) 1200b57cec5SDimitry Andric .Case("hidden_global_offset_x", true) 1210b57cec5SDimitry Andric .Case("hidden_global_offset_y", true) 1220b57cec5SDimitry Andric .Case("hidden_global_offset_z", true) 1230b57cec5SDimitry Andric .Case("hidden_none", true) 1240b57cec5SDimitry Andric .Case("hidden_printf_buffer", true) 125480093f4SDimitry Andric .Case("hidden_hostcall_buffer", true) 1260b57cec5SDimitry Andric .Case("hidden_default_queue", true) 1270b57cec5SDimitry Andric .Case("hidden_completion_action", true) 1280b57cec5SDimitry Andric .Case("hidden_multigrid_sync_arg", true) 1290b57cec5SDimitry Andric .Default(false); 1300b57cec5SDimitry Andric })) 1310b57cec5SDimitry Andric return false; 1320b57cec5SDimitry Andric if (!verifyIntegerEntry(ArgsMap, ".pointee_align", false)) 1330b57cec5SDimitry Andric return false; 1340b57cec5SDimitry Andric if (!verifyScalarEntry(ArgsMap, ".address_space", false, 1350b57cec5SDimitry Andric msgpack::Type::String, 1360b57cec5SDimitry Andric [](msgpack::DocNode &SNode) { 1370b57cec5SDimitry Andric return StringSwitch<bool>(SNode.getString()) 1380b57cec5SDimitry Andric .Case("private", true) 1390b57cec5SDimitry Andric .Case("global", true) 1400b57cec5SDimitry Andric .Case("constant", true) 1410b57cec5SDimitry Andric .Case("local", true) 1420b57cec5SDimitry Andric .Case("generic", true) 1430b57cec5SDimitry Andric .Case("region", true) 1440b57cec5SDimitry Andric .Default(false); 1450b57cec5SDimitry Andric })) 1460b57cec5SDimitry Andric return false; 1470b57cec5SDimitry Andric if (!verifyScalarEntry(ArgsMap, ".access", false, 1480b57cec5SDimitry Andric msgpack::Type::String, 1490b57cec5SDimitry Andric [](msgpack::DocNode &SNode) { 1500b57cec5SDimitry Andric return StringSwitch<bool>(SNode.getString()) 1510b57cec5SDimitry Andric .Case("read_only", true) 1520b57cec5SDimitry Andric .Case("write_only", true) 1530b57cec5SDimitry Andric .Case("read_write", true) 1540b57cec5SDimitry Andric .Default(false); 1550b57cec5SDimitry Andric })) 1560b57cec5SDimitry Andric return false; 1570b57cec5SDimitry Andric if (!verifyScalarEntry(ArgsMap, ".actual_access", false, 1580b57cec5SDimitry Andric msgpack::Type::String, 1590b57cec5SDimitry Andric [](msgpack::DocNode &SNode) { 1600b57cec5SDimitry Andric return StringSwitch<bool>(SNode.getString()) 1610b57cec5SDimitry Andric .Case("read_only", true) 1620b57cec5SDimitry Andric .Case("write_only", true) 1630b57cec5SDimitry Andric .Case("read_write", true) 1640b57cec5SDimitry Andric .Default(false); 1650b57cec5SDimitry Andric })) 1660b57cec5SDimitry Andric return false; 1670b57cec5SDimitry Andric if (!verifyScalarEntry(ArgsMap, ".is_const", false, 1680b57cec5SDimitry Andric msgpack::Type::Boolean)) 1690b57cec5SDimitry Andric return false; 1700b57cec5SDimitry Andric if (!verifyScalarEntry(ArgsMap, ".is_restrict", false, 1710b57cec5SDimitry Andric msgpack::Type::Boolean)) 1720b57cec5SDimitry Andric return false; 1730b57cec5SDimitry Andric if (!verifyScalarEntry(ArgsMap, ".is_volatile", false, 1740b57cec5SDimitry Andric msgpack::Type::Boolean)) 1750b57cec5SDimitry Andric return false; 1760b57cec5SDimitry Andric if (!verifyScalarEntry(ArgsMap, ".is_pipe", false, 1770b57cec5SDimitry Andric msgpack::Type::Boolean)) 1780b57cec5SDimitry Andric return false; 1790b57cec5SDimitry Andric 1800b57cec5SDimitry Andric return true; 1810b57cec5SDimitry Andric } 1820b57cec5SDimitry Andric 1830b57cec5SDimitry Andric bool MetadataVerifier::verifyKernel(msgpack::DocNode &Node) { 1840b57cec5SDimitry Andric if (!Node.isMap()) 1850b57cec5SDimitry Andric return false; 1860b57cec5SDimitry Andric auto &KernelMap = Node.getMap(); 1870b57cec5SDimitry Andric 1880b57cec5SDimitry Andric if (!verifyScalarEntry(KernelMap, ".name", true, 1890b57cec5SDimitry Andric msgpack::Type::String)) 1900b57cec5SDimitry Andric return false; 1910b57cec5SDimitry Andric if (!verifyScalarEntry(KernelMap, ".symbol", true, 1920b57cec5SDimitry Andric msgpack::Type::String)) 1930b57cec5SDimitry Andric return false; 1940b57cec5SDimitry Andric if (!verifyScalarEntry(KernelMap, ".language", false, 1950b57cec5SDimitry Andric msgpack::Type::String, 1960b57cec5SDimitry Andric [](msgpack::DocNode &SNode) { 1970b57cec5SDimitry Andric return StringSwitch<bool>(SNode.getString()) 1980b57cec5SDimitry Andric .Case("OpenCL C", true) 1990b57cec5SDimitry Andric .Case("OpenCL C++", true) 2000b57cec5SDimitry Andric .Case("HCC", true) 2010b57cec5SDimitry Andric .Case("HIP", true) 2020b57cec5SDimitry Andric .Case("OpenMP", true) 2030b57cec5SDimitry Andric .Case("Assembler", true) 2040b57cec5SDimitry Andric .Default(false); 2050b57cec5SDimitry Andric })) 2060b57cec5SDimitry Andric return false; 2070b57cec5SDimitry Andric if (!verifyEntry( 2080b57cec5SDimitry Andric KernelMap, ".language_version", false, [this](msgpack::DocNode &Node) { 2090b57cec5SDimitry Andric return verifyArray( 2100b57cec5SDimitry Andric Node, 2110b57cec5SDimitry Andric [this](msgpack::DocNode &Node) { return verifyInteger(Node); }, 2); 2120b57cec5SDimitry Andric })) 2130b57cec5SDimitry Andric return false; 2140b57cec5SDimitry Andric if (!verifyEntry(KernelMap, ".args", false, [this](msgpack::DocNode &Node) { 2150b57cec5SDimitry Andric return verifyArray(Node, [this](msgpack::DocNode &Node) { 2160b57cec5SDimitry Andric return verifyKernelArgs(Node); 2170b57cec5SDimitry Andric }); 2180b57cec5SDimitry Andric })) 2190b57cec5SDimitry Andric return false; 2200b57cec5SDimitry Andric if (!verifyEntry(KernelMap, ".reqd_workgroup_size", false, 2210b57cec5SDimitry Andric [this](msgpack::DocNode &Node) { 2220b57cec5SDimitry Andric return verifyArray(Node, 2230b57cec5SDimitry Andric [this](msgpack::DocNode &Node) { 2240b57cec5SDimitry Andric return verifyInteger(Node); 2250b57cec5SDimitry Andric }, 2260b57cec5SDimitry Andric 3); 2270b57cec5SDimitry Andric })) 2280b57cec5SDimitry Andric return false; 2290b57cec5SDimitry Andric if (!verifyEntry(KernelMap, ".workgroup_size_hint", false, 2300b57cec5SDimitry Andric [this](msgpack::DocNode &Node) { 2310b57cec5SDimitry Andric return verifyArray(Node, 2320b57cec5SDimitry Andric [this](msgpack::DocNode &Node) { 2330b57cec5SDimitry Andric return verifyInteger(Node); 2340b57cec5SDimitry Andric }, 2350b57cec5SDimitry Andric 3); 2360b57cec5SDimitry Andric })) 2370b57cec5SDimitry Andric return false; 2380b57cec5SDimitry Andric if (!verifyScalarEntry(KernelMap, ".vec_type_hint", false, 2390b57cec5SDimitry Andric msgpack::Type::String)) 2400b57cec5SDimitry Andric return false; 2410b57cec5SDimitry Andric if (!verifyScalarEntry(KernelMap, ".device_enqueue_symbol", false, 2420b57cec5SDimitry Andric msgpack::Type::String)) 2430b57cec5SDimitry Andric return false; 2440b57cec5SDimitry Andric if (!verifyIntegerEntry(KernelMap, ".kernarg_segment_size", true)) 2450b57cec5SDimitry Andric return false; 2460b57cec5SDimitry Andric if (!verifyIntegerEntry(KernelMap, ".group_segment_fixed_size", true)) 2470b57cec5SDimitry Andric return false; 2480b57cec5SDimitry Andric if (!verifyIntegerEntry(KernelMap, ".private_segment_fixed_size", true)) 2490b57cec5SDimitry Andric return false; 2500b57cec5SDimitry Andric if (!verifyIntegerEntry(KernelMap, ".kernarg_segment_align", true)) 2510b57cec5SDimitry Andric return false; 2520b57cec5SDimitry Andric if (!verifyIntegerEntry(KernelMap, ".wavefront_size", true)) 2530b57cec5SDimitry Andric return false; 2540b57cec5SDimitry Andric if (!verifyIntegerEntry(KernelMap, ".sgpr_count", true)) 2550b57cec5SDimitry Andric return false; 2560b57cec5SDimitry Andric if (!verifyIntegerEntry(KernelMap, ".vgpr_count", true)) 2570b57cec5SDimitry Andric return false; 2580b57cec5SDimitry Andric if (!verifyIntegerEntry(KernelMap, ".max_flat_workgroup_size", true)) 2590b57cec5SDimitry Andric return false; 2600b57cec5SDimitry Andric if (!verifyIntegerEntry(KernelMap, ".sgpr_spill_count", false)) 2610b57cec5SDimitry Andric return false; 2620b57cec5SDimitry Andric if (!verifyIntegerEntry(KernelMap, ".vgpr_spill_count", false)) 2630b57cec5SDimitry Andric return false; 2640b57cec5SDimitry Andric 2650b57cec5SDimitry Andric return true; 2660b57cec5SDimitry Andric } 2670b57cec5SDimitry Andric 2680b57cec5SDimitry Andric bool MetadataVerifier::verify(msgpack::DocNode &HSAMetadataRoot) { 2690b57cec5SDimitry Andric if (!HSAMetadataRoot.isMap()) 2700b57cec5SDimitry Andric return false; 2710b57cec5SDimitry Andric auto &RootMap = HSAMetadataRoot.getMap(); 2720b57cec5SDimitry Andric 2730b57cec5SDimitry Andric if (!verifyEntry( 2740b57cec5SDimitry Andric RootMap, "amdhsa.version", true, [this](msgpack::DocNode &Node) { 2750b57cec5SDimitry Andric return verifyArray( 2760b57cec5SDimitry Andric Node, 2770b57cec5SDimitry Andric [this](msgpack::DocNode &Node) { return verifyInteger(Node); }, 2); 2780b57cec5SDimitry Andric })) 2790b57cec5SDimitry Andric return false; 2800b57cec5SDimitry Andric if (!verifyEntry( 2810b57cec5SDimitry Andric RootMap, "amdhsa.printf", false, [this](msgpack::DocNode &Node) { 2820b57cec5SDimitry Andric return verifyArray(Node, [this](msgpack::DocNode &Node) { 2830b57cec5SDimitry Andric return verifyScalar(Node, msgpack::Type::String); 2840b57cec5SDimitry Andric }); 2850b57cec5SDimitry Andric })) 2860b57cec5SDimitry Andric return false; 2870b57cec5SDimitry Andric if (!verifyEntry(RootMap, "amdhsa.kernels", true, 2880b57cec5SDimitry Andric [this](msgpack::DocNode &Node) { 2890b57cec5SDimitry Andric return verifyArray(Node, [this](msgpack::DocNode &Node) { 2900b57cec5SDimitry Andric return verifyKernel(Node); 2910b57cec5SDimitry Andric }); 2920b57cec5SDimitry Andric })) 2930b57cec5SDimitry Andric return false; 2940b57cec5SDimitry Andric 2950b57cec5SDimitry Andric return true; 2960b57cec5SDimitry Andric } 2970b57cec5SDimitry Andric 2980b57cec5SDimitry Andric } // end namespace V3 2990b57cec5SDimitry Andric } // end namespace HSAMD 3000b57cec5SDimitry Andric } // end namespace AMDGPU 3010b57cec5SDimitry Andric } // end namespace llvm 302