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*5ffd83dbSDimitry Andric #include "llvm/ADT/StringSwitch.h" 160b57cec5SDimitry Andric #include "llvm/Support/AMDGPUMetadata.h" 170b57cec5SDimitry Andric 180b57cec5SDimitry Andric namespace llvm { 190b57cec5SDimitry Andric namespace AMDGPU { 200b57cec5SDimitry Andric namespace HSAMD { 210b57cec5SDimitry Andric namespace V3 { 220b57cec5SDimitry Andric 230b57cec5SDimitry Andric bool MetadataVerifier::verifyScalar( 240b57cec5SDimitry Andric msgpack::DocNode &Node, msgpack::Type SKind, 250b57cec5SDimitry Andric function_ref<bool(msgpack::DocNode &)> verifyValue) { 260b57cec5SDimitry Andric if (!Node.isScalar()) 270b57cec5SDimitry Andric return false; 280b57cec5SDimitry Andric if (Node.getKind() != SKind) { 290b57cec5SDimitry Andric if (Strict) 300b57cec5SDimitry Andric return false; 310b57cec5SDimitry Andric // If we are not strict, we interpret string values as "implicitly typed" 320b57cec5SDimitry Andric // and attempt to coerce them to the expected type here. 330b57cec5SDimitry Andric if (Node.getKind() != msgpack::Type::String) 340b57cec5SDimitry Andric return false; 350b57cec5SDimitry Andric StringRef StringValue = Node.getString(); 360b57cec5SDimitry Andric Node.fromString(StringValue); 370b57cec5SDimitry Andric if (Node.getKind() != SKind) 380b57cec5SDimitry Andric return false; 390b57cec5SDimitry Andric } 400b57cec5SDimitry Andric if (verifyValue) 410b57cec5SDimitry Andric return verifyValue(Node); 420b57cec5SDimitry Andric return true; 430b57cec5SDimitry Andric } 440b57cec5SDimitry Andric 450b57cec5SDimitry Andric bool MetadataVerifier::verifyInteger(msgpack::DocNode &Node) { 460b57cec5SDimitry Andric if (!verifyScalar(Node, msgpack::Type::UInt)) 470b57cec5SDimitry Andric if (!verifyScalar(Node, msgpack::Type::Int)) 480b57cec5SDimitry Andric return false; 490b57cec5SDimitry Andric return true; 500b57cec5SDimitry Andric } 510b57cec5SDimitry Andric 520b57cec5SDimitry Andric bool MetadataVerifier::verifyArray( 530b57cec5SDimitry Andric msgpack::DocNode &Node, function_ref<bool(msgpack::DocNode &)> verifyNode, 540b57cec5SDimitry Andric Optional<size_t> Size) { 550b57cec5SDimitry Andric if (!Node.isArray()) 560b57cec5SDimitry Andric return false; 570b57cec5SDimitry Andric auto &Array = Node.getArray(); 580b57cec5SDimitry Andric if (Size && Array.size() != *Size) 590b57cec5SDimitry Andric return false; 600b57cec5SDimitry Andric for (auto &Item : Array) 610b57cec5SDimitry Andric if (!verifyNode(Item)) 620b57cec5SDimitry Andric return false; 630b57cec5SDimitry Andric 640b57cec5SDimitry Andric return true; 650b57cec5SDimitry Andric } 660b57cec5SDimitry Andric 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 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 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 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; 1070b57cec5SDimitry Andric if (!verifyScalarEntry(ArgsMap, ".value_kind", true, 1080b57cec5SDimitry Andric 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) 1180b57cec5SDimitry Andric .Case("hidden_global_offset_x", true) 1190b57cec5SDimitry Andric .Case("hidden_global_offset_y", true) 1200b57cec5SDimitry Andric .Case("hidden_global_offset_z", true) 1210b57cec5SDimitry Andric .Case("hidden_none", true) 1220b57cec5SDimitry Andric .Case("hidden_printf_buffer", true) 123480093f4SDimitry Andric .Case("hidden_hostcall_buffer", true) 1240b57cec5SDimitry Andric .Case("hidden_default_queue", true) 1250b57cec5SDimitry Andric .Case("hidden_completion_action", true) 1260b57cec5SDimitry Andric .Case("hidden_multigrid_sync_arg", true) 1270b57cec5SDimitry Andric .Default(false); 1280b57cec5SDimitry Andric })) 1290b57cec5SDimitry Andric return false; 1300b57cec5SDimitry Andric if (!verifyIntegerEntry(ArgsMap, ".pointee_align", false)) 1310b57cec5SDimitry Andric return false; 1320b57cec5SDimitry Andric if (!verifyScalarEntry(ArgsMap, ".address_space", false, 1330b57cec5SDimitry Andric msgpack::Type::String, 1340b57cec5SDimitry Andric [](msgpack::DocNode &SNode) { 1350b57cec5SDimitry Andric return StringSwitch<bool>(SNode.getString()) 1360b57cec5SDimitry Andric .Case("private", true) 1370b57cec5SDimitry Andric .Case("global", true) 1380b57cec5SDimitry Andric .Case("constant", true) 1390b57cec5SDimitry Andric .Case("local", true) 1400b57cec5SDimitry Andric .Case("generic", true) 1410b57cec5SDimitry Andric .Case("region", true) 1420b57cec5SDimitry Andric .Default(false); 1430b57cec5SDimitry Andric })) 1440b57cec5SDimitry Andric return false; 1450b57cec5SDimitry Andric if (!verifyScalarEntry(ArgsMap, ".access", false, 1460b57cec5SDimitry Andric msgpack::Type::String, 1470b57cec5SDimitry Andric [](msgpack::DocNode &SNode) { 1480b57cec5SDimitry Andric return StringSwitch<bool>(SNode.getString()) 1490b57cec5SDimitry Andric .Case("read_only", true) 1500b57cec5SDimitry Andric .Case("write_only", true) 1510b57cec5SDimitry Andric .Case("read_write", true) 1520b57cec5SDimitry Andric .Default(false); 1530b57cec5SDimitry Andric })) 1540b57cec5SDimitry Andric return false; 1550b57cec5SDimitry Andric if (!verifyScalarEntry(ArgsMap, ".actual_access", false, 1560b57cec5SDimitry Andric msgpack::Type::String, 1570b57cec5SDimitry Andric [](msgpack::DocNode &SNode) { 1580b57cec5SDimitry Andric return StringSwitch<bool>(SNode.getString()) 1590b57cec5SDimitry Andric .Case("read_only", true) 1600b57cec5SDimitry Andric .Case("write_only", true) 1610b57cec5SDimitry Andric .Case("read_write", true) 1620b57cec5SDimitry Andric .Default(false); 1630b57cec5SDimitry Andric })) 1640b57cec5SDimitry Andric return false; 1650b57cec5SDimitry Andric if (!verifyScalarEntry(ArgsMap, ".is_const", false, 1660b57cec5SDimitry Andric msgpack::Type::Boolean)) 1670b57cec5SDimitry Andric return false; 1680b57cec5SDimitry Andric if (!verifyScalarEntry(ArgsMap, ".is_restrict", false, 1690b57cec5SDimitry Andric msgpack::Type::Boolean)) 1700b57cec5SDimitry Andric return false; 1710b57cec5SDimitry Andric if (!verifyScalarEntry(ArgsMap, ".is_volatile", false, 1720b57cec5SDimitry Andric msgpack::Type::Boolean)) 1730b57cec5SDimitry Andric return false; 1740b57cec5SDimitry Andric if (!verifyScalarEntry(ArgsMap, ".is_pipe", false, 1750b57cec5SDimitry Andric msgpack::Type::Boolean)) 1760b57cec5SDimitry Andric return false; 1770b57cec5SDimitry Andric 1780b57cec5SDimitry Andric return true; 1790b57cec5SDimitry Andric } 1800b57cec5SDimitry Andric 1810b57cec5SDimitry Andric bool MetadataVerifier::verifyKernel(msgpack::DocNode &Node) { 1820b57cec5SDimitry Andric if (!Node.isMap()) 1830b57cec5SDimitry Andric return false; 1840b57cec5SDimitry Andric auto &KernelMap = Node.getMap(); 1850b57cec5SDimitry Andric 1860b57cec5SDimitry Andric if (!verifyScalarEntry(KernelMap, ".name", true, 1870b57cec5SDimitry Andric msgpack::Type::String)) 1880b57cec5SDimitry Andric return false; 1890b57cec5SDimitry Andric if (!verifyScalarEntry(KernelMap, ".symbol", true, 1900b57cec5SDimitry Andric msgpack::Type::String)) 1910b57cec5SDimitry Andric return false; 1920b57cec5SDimitry Andric if (!verifyScalarEntry(KernelMap, ".language", false, 1930b57cec5SDimitry Andric msgpack::Type::String, 1940b57cec5SDimitry Andric [](msgpack::DocNode &SNode) { 1950b57cec5SDimitry Andric return StringSwitch<bool>(SNode.getString()) 1960b57cec5SDimitry Andric .Case("OpenCL C", true) 1970b57cec5SDimitry Andric .Case("OpenCL C++", true) 1980b57cec5SDimitry Andric .Case("HCC", true) 1990b57cec5SDimitry Andric .Case("HIP", true) 2000b57cec5SDimitry Andric .Case("OpenMP", true) 2010b57cec5SDimitry Andric .Case("Assembler", true) 2020b57cec5SDimitry Andric .Default(false); 2030b57cec5SDimitry Andric })) 2040b57cec5SDimitry Andric return false; 2050b57cec5SDimitry Andric if (!verifyEntry( 2060b57cec5SDimitry Andric KernelMap, ".language_version", false, [this](msgpack::DocNode &Node) { 2070b57cec5SDimitry Andric return verifyArray( 2080b57cec5SDimitry Andric Node, 2090b57cec5SDimitry Andric [this](msgpack::DocNode &Node) { return verifyInteger(Node); }, 2); 2100b57cec5SDimitry Andric })) 2110b57cec5SDimitry Andric return false; 2120b57cec5SDimitry Andric if (!verifyEntry(KernelMap, ".args", false, [this](msgpack::DocNode &Node) { 2130b57cec5SDimitry Andric return verifyArray(Node, [this](msgpack::DocNode &Node) { 2140b57cec5SDimitry Andric return verifyKernelArgs(Node); 2150b57cec5SDimitry Andric }); 2160b57cec5SDimitry Andric })) 2170b57cec5SDimitry Andric return false; 2180b57cec5SDimitry Andric if (!verifyEntry(KernelMap, ".reqd_workgroup_size", false, 2190b57cec5SDimitry Andric [this](msgpack::DocNode &Node) { 2200b57cec5SDimitry Andric return verifyArray(Node, 2210b57cec5SDimitry Andric [this](msgpack::DocNode &Node) { 2220b57cec5SDimitry Andric return verifyInteger(Node); 2230b57cec5SDimitry Andric }, 2240b57cec5SDimitry Andric 3); 2250b57cec5SDimitry Andric })) 2260b57cec5SDimitry Andric return false; 2270b57cec5SDimitry Andric if (!verifyEntry(KernelMap, ".workgroup_size_hint", false, 2280b57cec5SDimitry Andric [this](msgpack::DocNode &Node) { 2290b57cec5SDimitry Andric return verifyArray(Node, 2300b57cec5SDimitry Andric [this](msgpack::DocNode &Node) { 2310b57cec5SDimitry Andric return verifyInteger(Node); 2320b57cec5SDimitry Andric }, 2330b57cec5SDimitry Andric 3); 2340b57cec5SDimitry Andric })) 2350b57cec5SDimitry Andric return false; 2360b57cec5SDimitry Andric if (!verifyScalarEntry(KernelMap, ".vec_type_hint", false, 2370b57cec5SDimitry Andric msgpack::Type::String)) 2380b57cec5SDimitry Andric return false; 2390b57cec5SDimitry Andric if (!verifyScalarEntry(KernelMap, ".device_enqueue_symbol", false, 2400b57cec5SDimitry Andric msgpack::Type::String)) 2410b57cec5SDimitry Andric return false; 2420b57cec5SDimitry Andric if (!verifyIntegerEntry(KernelMap, ".kernarg_segment_size", true)) 2430b57cec5SDimitry Andric return false; 2440b57cec5SDimitry Andric if (!verifyIntegerEntry(KernelMap, ".group_segment_fixed_size", true)) 2450b57cec5SDimitry Andric return false; 2460b57cec5SDimitry Andric if (!verifyIntegerEntry(KernelMap, ".private_segment_fixed_size", true)) 2470b57cec5SDimitry Andric return false; 2480b57cec5SDimitry Andric if (!verifyIntegerEntry(KernelMap, ".kernarg_segment_align", true)) 2490b57cec5SDimitry Andric return false; 2500b57cec5SDimitry Andric if (!verifyIntegerEntry(KernelMap, ".wavefront_size", true)) 2510b57cec5SDimitry Andric return false; 2520b57cec5SDimitry Andric if (!verifyIntegerEntry(KernelMap, ".sgpr_count", true)) 2530b57cec5SDimitry Andric return false; 2540b57cec5SDimitry Andric if (!verifyIntegerEntry(KernelMap, ".vgpr_count", true)) 2550b57cec5SDimitry Andric return false; 2560b57cec5SDimitry Andric if (!verifyIntegerEntry(KernelMap, ".max_flat_workgroup_size", true)) 2570b57cec5SDimitry Andric return false; 2580b57cec5SDimitry Andric if (!verifyIntegerEntry(KernelMap, ".sgpr_spill_count", false)) 2590b57cec5SDimitry Andric return false; 2600b57cec5SDimitry Andric if (!verifyIntegerEntry(KernelMap, ".vgpr_spill_count", false)) 2610b57cec5SDimitry Andric return false; 2620b57cec5SDimitry Andric 2630b57cec5SDimitry Andric return true; 2640b57cec5SDimitry Andric } 2650b57cec5SDimitry Andric 2660b57cec5SDimitry Andric bool MetadataVerifier::verify(msgpack::DocNode &HSAMetadataRoot) { 2670b57cec5SDimitry Andric if (!HSAMetadataRoot.isMap()) 2680b57cec5SDimitry Andric return false; 2690b57cec5SDimitry Andric auto &RootMap = HSAMetadataRoot.getMap(); 2700b57cec5SDimitry Andric 2710b57cec5SDimitry Andric if (!verifyEntry( 2720b57cec5SDimitry Andric RootMap, "amdhsa.version", true, [this](msgpack::DocNode &Node) { 2730b57cec5SDimitry Andric return verifyArray( 2740b57cec5SDimitry Andric Node, 2750b57cec5SDimitry Andric [this](msgpack::DocNode &Node) { return verifyInteger(Node); }, 2); 2760b57cec5SDimitry Andric })) 2770b57cec5SDimitry Andric return false; 2780b57cec5SDimitry Andric if (!verifyEntry( 2790b57cec5SDimitry Andric RootMap, "amdhsa.printf", false, [this](msgpack::DocNode &Node) { 2800b57cec5SDimitry Andric return verifyArray(Node, [this](msgpack::DocNode &Node) { 2810b57cec5SDimitry Andric return verifyScalar(Node, msgpack::Type::String); 2820b57cec5SDimitry Andric }); 2830b57cec5SDimitry Andric })) 2840b57cec5SDimitry Andric return false; 2850b57cec5SDimitry Andric if (!verifyEntry(RootMap, "amdhsa.kernels", true, 2860b57cec5SDimitry Andric [this](msgpack::DocNode &Node) { 2870b57cec5SDimitry Andric return verifyArray(Node, [this](msgpack::DocNode &Node) { 2880b57cec5SDimitry Andric return verifyKernel(Node); 2890b57cec5SDimitry Andric }); 2900b57cec5SDimitry Andric })) 2910b57cec5SDimitry Andric return false; 2920b57cec5SDimitry Andric 2930b57cec5SDimitry Andric return true; 2940b57cec5SDimitry Andric } 2950b57cec5SDimitry Andric 2960b57cec5SDimitry Andric } // end namespace V3 2970b57cec5SDimitry Andric } // end namespace HSAMD 2980b57cec5SDimitry Andric } // end namespace AMDGPU 2990b57cec5SDimitry Andric } // end namespace llvm 300