1f5b36e56SScott Linder //===- AMDGPUMetadataVerifier.cpp - MsgPack Types ---------------*- C++ -*-===// 2f5b36e56SScott Linder // 32946cd70SChandler Carruth // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 42946cd70SChandler Carruth // See https://llvm.org/LICENSE.txt for license information. 52946cd70SChandler Carruth // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6f5b36e56SScott Linder // 7f5b36e56SScott Linder //===----------------------------------------------------------------------===// 8f5b36e56SScott Linder // 9f5b36e56SScott Linder /// \file 10f5b36e56SScott Linder /// Implements a verifier for AMDGPU HSA metadata. 11f5b36e56SScott Linder // 12f5b36e56SScott Linder //===----------------------------------------------------------------------===// 13f5b36e56SScott Linder 14f5b36e56SScott Linder #include "llvm/BinaryFormat/AMDGPUMetadataVerifier.h" 15af450eabSReid Kleckner #include "llvm/ADT/StringSwitch.h" 16f5b36e56SScott Linder #include "llvm/Support/AMDGPUMetadata.h" 17f5b36e56SScott Linder 18f5b36e56SScott Linder namespace llvm { 19f5b36e56SScott Linder namespace AMDGPU { 20f5b36e56SScott Linder namespace HSAMD { 21f5b36e56SScott Linder namespace V3 { 22f5b36e56SScott Linder 23f5b36e56SScott Linder bool MetadataVerifier::verifyScalar( 24ed0b9af9STim Renouf msgpack::DocNode &Node, msgpack::Type SKind, 25ed0b9af9STim Renouf function_ref<bool(msgpack::DocNode &)> verifyValue) { 26ed0b9af9STim Renouf if (!Node.isScalar()) 27f5b36e56SScott Linder return false; 28ed0b9af9STim Renouf if (Node.getKind() != SKind) { 29f5b36e56SScott Linder if (Strict) 30f5b36e56SScott Linder return false; 31f5b36e56SScott Linder // If we are not strict, we interpret string values as "implicitly typed" 32f5b36e56SScott Linder // and attempt to coerce them to the expected type here. 33ed0b9af9STim Renouf if (Node.getKind() != msgpack::Type::String) 34f5b36e56SScott Linder return false; 35ed0b9af9STim Renouf StringRef StringValue = Node.getString(); 36ed0b9af9STim Renouf Node.fromString(StringValue); 37ed0b9af9STim Renouf if (Node.getKind() != SKind) 38f5b36e56SScott Linder return false; 39f5b36e56SScott Linder } 40f5b36e56SScott Linder if (verifyValue) 41ed0b9af9STim Renouf return verifyValue(Node); 42f5b36e56SScott Linder return true; 43f5b36e56SScott Linder } 44f5b36e56SScott Linder 45ed0b9af9STim Renouf bool MetadataVerifier::verifyInteger(msgpack::DocNode &Node) { 46ed0b9af9STim Renouf if (!verifyScalar(Node, msgpack::Type::UInt)) 47ed0b9af9STim Renouf if (!verifyScalar(Node, msgpack::Type::Int)) 48f5b36e56SScott Linder return false; 49f5b36e56SScott Linder return true; 50f5b36e56SScott Linder } 51f5b36e56SScott Linder 52f5b36e56SScott Linder bool MetadataVerifier::verifyArray( 53ed0b9af9STim Renouf msgpack::DocNode &Node, function_ref<bool(msgpack::DocNode &)> verifyNode, 54f5b36e56SScott Linder Optional<size_t> Size) { 55ed0b9af9STim Renouf if (!Node.isArray()) 56f5b36e56SScott Linder return false; 57ed0b9af9STim Renouf auto &Array = Node.getArray(); 58f5b36e56SScott Linder if (Size && Array.size() != *Size) 59f5b36e56SScott Linder return false; 60*c2bb9637SKazu Hirata return llvm::all_of(Array, verifyNode); 61f5b36e56SScott Linder } 62f5b36e56SScott Linder 63f5b36e56SScott Linder bool MetadataVerifier::verifyEntry( 64ed0b9af9STim Renouf msgpack::MapDocNode &MapNode, StringRef Key, bool Required, 65ed0b9af9STim Renouf function_ref<bool(msgpack::DocNode &)> verifyNode) { 66f5b36e56SScott Linder auto Entry = MapNode.find(Key); 67f5b36e56SScott Linder if (Entry == MapNode.end()) 68f5b36e56SScott Linder return !Required; 69ed0b9af9STim Renouf return verifyNode(Entry->second); 70f5b36e56SScott Linder } 71f5b36e56SScott Linder 72f5b36e56SScott Linder bool MetadataVerifier::verifyScalarEntry( 73ed0b9af9STim Renouf msgpack::MapDocNode &MapNode, StringRef Key, bool Required, 74ed0b9af9STim Renouf msgpack::Type SKind, 75ed0b9af9STim Renouf function_ref<bool(msgpack::DocNode &)> verifyValue) { 76ed0b9af9STim Renouf return verifyEntry(MapNode, Key, Required, [=](msgpack::DocNode &Node) { 77f5b36e56SScott Linder return verifyScalar(Node, SKind, verifyValue); 78f5b36e56SScott Linder }); 79f5b36e56SScott Linder } 80f5b36e56SScott Linder 81ed0b9af9STim Renouf bool MetadataVerifier::verifyIntegerEntry(msgpack::MapDocNode &MapNode, 82f5b36e56SScott Linder StringRef Key, bool Required) { 83ed0b9af9STim Renouf return verifyEntry(MapNode, Key, Required, [this](msgpack::DocNode &Node) { 84f5b36e56SScott Linder return verifyInteger(Node); 85f5b36e56SScott Linder }); 86f5b36e56SScott Linder } 87f5b36e56SScott Linder 88ed0b9af9STim Renouf bool MetadataVerifier::verifyKernelArgs(msgpack::DocNode &Node) { 89ed0b9af9STim Renouf if (!Node.isMap()) 90f5b36e56SScott Linder return false; 91ed0b9af9STim Renouf auto &ArgsMap = Node.getMap(); 92f5b36e56SScott Linder 93f5b36e56SScott Linder if (!verifyScalarEntry(ArgsMap, ".name", false, 94ed0b9af9STim Renouf msgpack::Type::String)) 95f5b36e56SScott Linder return false; 96f5b36e56SScott Linder if (!verifyScalarEntry(ArgsMap, ".type_name", false, 97ed0b9af9STim Renouf msgpack::Type::String)) 98f5b36e56SScott Linder return false; 99f5b36e56SScott Linder if (!verifyIntegerEntry(ArgsMap, ".size", true)) 100f5b36e56SScott Linder return false; 101f5b36e56SScott Linder if (!verifyIntegerEntry(ArgsMap, ".offset", true)) 102f5b36e56SScott Linder return false; 103f5b36e56SScott Linder if (!verifyScalarEntry(ArgsMap, ".value_kind", true, 104ed0b9af9STim Renouf msgpack::Type::String, 105ed0b9af9STim Renouf [](msgpack::DocNode &SNode) { 106f5b36e56SScott Linder return StringSwitch<bool>(SNode.getString()) 107f5b36e56SScott Linder .Case("by_value", true) 108f5b36e56SScott Linder .Case("global_buffer", true) 109f5b36e56SScott Linder .Case("dynamic_shared_pointer", true) 110f5b36e56SScott Linder .Case("sampler", true) 111f5b36e56SScott Linder .Case("image", true) 112f5b36e56SScott Linder .Case("pipe", true) 113f5b36e56SScott Linder .Case("queue", true) 114f5b36e56SScott Linder .Case("hidden_global_offset_x", true) 115f5b36e56SScott Linder .Case("hidden_global_offset_y", true) 116f5b36e56SScott Linder .Case("hidden_global_offset_z", true) 117f5b36e56SScott Linder .Case("hidden_none", true) 118f5b36e56SScott Linder .Case("hidden_printf_buffer", true) 11952c5014dSSameer Sahasrabuddhe .Case("hidden_hostcall_buffer", true) 120f5b36e56SScott Linder .Case("hidden_default_queue", true) 121f5b36e56SScott Linder .Case("hidden_completion_action", true) 122a6241352SYaxun Liu .Case("hidden_multigrid_sync_arg", true) 123f5b36e56SScott Linder .Default(false); 124f5b36e56SScott Linder })) 125f5b36e56SScott Linder return false; 126f5b36e56SScott Linder if (!verifyIntegerEntry(ArgsMap, ".pointee_align", false)) 127f5b36e56SScott Linder return false; 128f5b36e56SScott Linder if (!verifyScalarEntry(ArgsMap, ".address_space", false, 129ed0b9af9STim Renouf msgpack::Type::String, 130ed0b9af9STim Renouf [](msgpack::DocNode &SNode) { 131f5b36e56SScott Linder return StringSwitch<bool>(SNode.getString()) 132f5b36e56SScott Linder .Case("private", true) 133f5b36e56SScott Linder .Case("global", true) 134f5b36e56SScott Linder .Case("constant", true) 135f5b36e56SScott Linder .Case("local", true) 136f5b36e56SScott Linder .Case("generic", true) 137f5b36e56SScott Linder .Case("region", true) 138f5b36e56SScott Linder .Default(false); 139f5b36e56SScott Linder })) 140f5b36e56SScott Linder return false; 141f5b36e56SScott Linder if (!verifyScalarEntry(ArgsMap, ".access", false, 142ed0b9af9STim Renouf msgpack::Type::String, 143ed0b9af9STim Renouf [](msgpack::DocNode &SNode) { 144f5b36e56SScott Linder return StringSwitch<bool>(SNode.getString()) 145f5b36e56SScott Linder .Case("read_only", true) 146f5b36e56SScott Linder .Case("write_only", true) 147f5b36e56SScott Linder .Case("read_write", true) 148f5b36e56SScott Linder .Default(false); 149f5b36e56SScott Linder })) 150f5b36e56SScott Linder return false; 151f5b36e56SScott Linder if (!verifyScalarEntry(ArgsMap, ".actual_access", false, 152ed0b9af9STim Renouf msgpack::Type::String, 153ed0b9af9STim Renouf [](msgpack::DocNode &SNode) { 154f5b36e56SScott Linder return StringSwitch<bool>(SNode.getString()) 155f5b36e56SScott Linder .Case("read_only", true) 156f5b36e56SScott Linder .Case("write_only", true) 157f5b36e56SScott Linder .Case("read_write", true) 158f5b36e56SScott Linder .Default(false); 159f5b36e56SScott Linder })) 160f5b36e56SScott Linder return false; 161f5b36e56SScott Linder if (!verifyScalarEntry(ArgsMap, ".is_const", false, 162ed0b9af9STim Renouf msgpack::Type::Boolean)) 163f5b36e56SScott Linder return false; 164f5b36e56SScott Linder if (!verifyScalarEntry(ArgsMap, ".is_restrict", false, 165ed0b9af9STim Renouf msgpack::Type::Boolean)) 166f5b36e56SScott Linder return false; 167f5b36e56SScott Linder if (!verifyScalarEntry(ArgsMap, ".is_volatile", false, 168ed0b9af9STim Renouf msgpack::Type::Boolean)) 169f5b36e56SScott Linder return false; 170f5b36e56SScott Linder if (!verifyScalarEntry(ArgsMap, ".is_pipe", false, 171ed0b9af9STim Renouf msgpack::Type::Boolean)) 172f5b36e56SScott Linder return false; 173f5b36e56SScott Linder 174f5b36e56SScott Linder return true; 175f5b36e56SScott Linder } 176f5b36e56SScott Linder 177ed0b9af9STim Renouf bool MetadataVerifier::verifyKernel(msgpack::DocNode &Node) { 178ed0b9af9STim Renouf if (!Node.isMap()) 179f5b36e56SScott Linder return false; 180ed0b9af9STim Renouf auto &KernelMap = Node.getMap(); 181f5b36e56SScott Linder 182f5b36e56SScott Linder if (!verifyScalarEntry(KernelMap, ".name", true, 183ed0b9af9STim Renouf msgpack::Type::String)) 184f5b36e56SScott Linder return false; 185f5b36e56SScott Linder if (!verifyScalarEntry(KernelMap, ".symbol", true, 186ed0b9af9STim Renouf msgpack::Type::String)) 187f5b36e56SScott Linder return false; 188f5b36e56SScott Linder if (!verifyScalarEntry(KernelMap, ".language", false, 189ed0b9af9STim Renouf msgpack::Type::String, 190ed0b9af9STim Renouf [](msgpack::DocNode &SNode) { 191f5b36e56SScott Linder return StringSwitch<bool>(SNode.getString()) 192f5b36e56SScott Linder .Case("OpenCL C", true) 193f5b36e56SScott Linder .Case("OpenCL C++", true) 194f5b36e56SScott Linder .Case("HCC", true) 195f5b36e56SScott Linder .Case("HIP", true) 196f5b36e56SScott Linder .Case("OpenMP", true) 197f5b36e56SScott Linder .Case("Assembler", true) 198f5b36e56SScott Linder .Default(false); 199f5b36e56SScott Linder })) 200f5b36e56SScott Linder return false; 201f5b36e56SScott Linder if (!verifyEntry( 202ed0b9af9STim Renouf KernelMap, ".language_version", false, [this](msgpack::DocNode &Node) { 203f5b36e56SScott Linder return verifyArray( 204f5b36e56SScott Linder Node, 205ed0b9af9STim Renouf [this](msgpack::DocNode &Node) { return verifyInteger(Node); }, 2); 206f5b36e56SScott Linder })) 207f5b36e56SScott Linder return false; 208ed0b9af9STim Renouf if (!verifyEntry(KernelMap, ".args", false, [this](msgpack::DocNode &Node) { 209ed0b9af9STim Renouf return verifyArray(Node, [this](msgpack::DocNode &Node) { 210f5b36e56SScott Linder return verifyKernelArgs(Node); 211f5b36e56SScott Linder }); 212f5b36e56SScott Linder })) 213f5b36e56SScott Linder return false; 214f5b36e56SScott Linder if (!verifyEntry(KernelMap, ".reqd_workgroup_size", false, 215ed0b9af9STim Renouf [this](msgpack::DocNode &Node) { 216f5b36e56SScott Linder return verifyArray(Node, 217ed0b9af9STim Renouf [this](msgpack::DocNode &Node) { 218f5b36e56SScott Linder return verifyInteger(Node); 219f5b36e56SScott Linder }, 220f5b36e56SScott Linder 3); 221f5b36e56SScott Linder })) 222f5b36e56SScott Linder return false; 223f5b36e56SScott Linder if (!verifyEntry(KernelMap, ".workgroup_size_hint", false, 224ed0b9af9STim Renouf [this](msgpack::DocNode &Node) { 225f5b36e56SScott Linder return verifyArray(Node, 226ed0b9af9STim Renouf [this](msgpack::DocNode &Node) { 227f5b36e56SScott Linder return verifyInteger(Node); 228f5b36e56SScott Linder }, 229f5b36e56SScott Linder 3); 230f5b36e56SScott Linder })) 231f5b36e56SScott Linder return false; 232f5b36e56SScott Linder if (!verifyScalarEntry(KernelMap, ".vec_type_hint", false, 233ed0b9af9STim Renouf msgpack::Type::String)) 234f5b36e56SScott Linder return false; 235f5b36e56SScott Linder if (!verifyScalarEntry(KernelMap, ".device_enqueue_symbol", false, 236ed0b9af9STim Renouf msgpack::Type::String)) 237f5b36e56SScott Linder return false; 238f5b36e56SScott Linder if (!verifyIntegerEntry(KernelMap, ".kernarg_segment_size", true)) 239f5b36e56SScott Linder return false; 240f5b36e56SScott Linder if (!verifyIntegerEntry(KernelMap, ".group_segment_fixed_size", true)) 241f5b36e56SScott Linder return false; 242f5b36e56SScott Linder if (!verifyIntegerEntry(KernelMap, ".private_segment_fixed_size", true)) 243f5b36e56SScott Linder return false; 244f5b36e56SScott Linder if (!verifyIntegerEntry(KernelMap, ".kernarg_segment_align", true)) 245f5b36e56SScott Linder return false; 246f5b36e56SScott Linder if (!verifyIntegerEntry(KernelMap, ".wavefront_size", true)) 247f5b36e56SScott Linder return false; 248f5b36e56SScott Linder if (!verifyIntegerEntry(KernelMap, ".sgpr_count", true)) 249f5b36e56SScott Linder return false; 250f5b36e56SScott Linder if (!verifyIntegerEntry(KernelMap, ".vgpr_count", true)) 251f5b36e56SScott Linder return false; 252f5b36e56SScott Linder if (!verifyIntegerEntry(KernelMap, ".max_flat_workgroup_size", true)) 253f5b36e56SScott Linder return false; 254f5b36e56SScott Linder if (!verifyIntegerEntry(KernelMap, ".sgpr_spill_count", false)) 255f5b36e56SScott Linder return false; 256f5b36e56SScott Linder if (!verifyIntegerEntry(KernelMap, ".vgpr_spill_count", false)) 257f5b36e56SScott Linder return false; 258f5b36e56SScott Linder 259f5b36e56SScott Linder return true; 260f5b36e56SScott Linder } 261f5b36e56SScott Linder 262ed0b9af9STim Renouf bool MetadataVerifier::verify(msgpack::DocNode &HSAMetadataRoot) { 263ed0b9af9STim Renouf if (!HSAMetadataRoot.isMap()) 264f5b36e56SScott Linder return false; 265ed0b9af9STim Renouf auto &RootMap = HSAMetadataRoot.getMap(); 266f5b36e56SScott Linder 267f5b36e56SScott Linder if (!verifyEntry( 268ed0b9af9STim Renouf RootMap, "amdhsa.version", true, [this](msgpack::DocNode &Node) { 269f5b36e56SScott Linder return verifyArray( 270f5b36e56SScott Linder Node, 271ed0b9af9STim Renouf [this](msgpack::DocNode &Node) { return verifyInteger(Node); }, 2); 272f5b36e56SScott Linder })) 273f5b36e56SScott Linder return false; 274f5b36e56SScott Linder if (!verifyEntry( 275ed0b9af9STim Renouf RootMap, "amdhsa.printf", false, [this](msgpack::DocNode &Node) { 276ed0b9af9STim Renouf return verifyArray(Node, [this](msgpack::DocNode &Node) { 277ed0b9af9STim Renouf return verifyScalar(Node, msgpack::Type::String); 278f5b36e56SScott Linder }); 279f5b36e56SScott Linder })) 280f5b36e56SScott Linder return false; 281f5b36e56SScott Linder if (!verifyEntry(RootMap, "amdhsa.kernels", true, 282ed0b9af9STim Renouf [this](msgpack::DocNode &Node) { 283ed0b9af9STim Renouf return verifyArray(Node, [this](msgpack::DocNode &Node) { 284f5b36e56SScott Linder return verifyKernel(Node); 285f5b36e56SScott Linder }); 286f5b36e56SScott Linder })) 287f5b36e56SScott Linder return false; 288f5b36e56SScott Linder 289f5b36e56SScott Linder return true; 290f5b36e56SScott Linder } 291f5b36e56SScott Linder 292f5b36e56SScott Linder } // end namespace V3 293f5b36e56SScott Linder } // end namespace HSAMD 294f5b36e56SScott Linder } // end namespace AMDGPU 295f5b36e56SScott Linder } // end namespace llvm 296