300 lines
		
	
	
		
			11 KiB
		
	
	
	
		
			C++
		
	
	
	
			
		
		
	
	
			300 lines
		
	
	
		
			11 KiB
		
	
	
	
		
			C++
		
	
	
	
//===- AMDGPUMetadataVerifier.cpp - MsgPack Types ---------------*- C++ -*-===//
 | 
						|
//
 | 
						|
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
 | 
						|
// See https://llvm.org/LICENSE.txt for license information.
 | 
						|
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
 | 
						|
//
 | 
						|
//===----------------------------------------------------------------------===//
 | 
						|
//
 | 
						|
/// \file
 | 
						|
/// Implements a verifier for AMDGPU HSA metadata.
 | 
						|
//
 | 
						|
//===----------------------------------------------------------------------===//
 | 
						|
 | 
						|
#include "llvm/BinaryFormat/AMDGPUMetadataVerifier.h"
 | 
						|
#include "llvm/ADT/StringSwitch.h"
 | 
						|
#include "llvm/Support/AMDGPUMetadata.h"
 | 
						|
 | 
						|
namespace llvm {
 | 
						|
namespace AMDGPU {
 | 
						|
namespace HSAMD {
 | 
						|
namespace V3 {
 | 
						|
 | 
						|
bool MetadataVerifier::verifyScalar(
 | 
						|
    msgpack::DocNode &Node, msgpack::Type SKind,
 | 
						|
    function_ref<bool(msgpack::DocNode &)> verifyValue) {
 | 
						|
  if (!Node.isScalar())
 | 
						|
    return false;
 | 
						|
  if (Node.getKind() != SKind) {
 | 
						|
    if (Strict)
 | 
						|
      return false;
 | 
						|
    // If we are not strict, we interpret string values as "implicitly typed"
 | 
						|
    // and attempt to coerce them to the expected type here.
 | 
						|
    if (Node.getKind() != msgpack::Type::String)
 | 
						|
      return false;
 | 
						|
    StringRef StringValue = Node.getString();
 | 
						|
    Node.fromString(StringValue);
 | 
						|
    if (Node.getKind() != SKind)
 | 
						|
      return false;
 | 
						|
  }
 | 
						|
  if (verifyValue)
 | 
						|
    return verifyValue(Node);
 | 
						|
  return true;
 | 
						|
}
 | 
						|
 | 
						|
bool MetadataVerifier::verifyInteger(msgpack::DocNode &Node) {
 | 
						|
  if (!verifyScalar(Node, msgpack::Type::UInt))
 | 
						|
    if (!verifyScalar(Node, msgpack::Type::Int))
 | 
						|
      return false;
 | 
						|
  return true;
 | 
						|
}
 | 
						|
 | 
						|
bool MetadataVerifier::verifyArray(
 | 
						|
    msgpack::DocNode &Node, function_ref<bool(msgpack::DocNode &)> verifyNode,
 | 
						|
    Optional<size_t> Size) {
 | 
						|
  if (!Node.isArray())
 | 
						|
    return false;
 | 
						|
  auto &Array = Node.getArray();
 | 
						|
  if (Size && Array.size() != *Size)
 | 
						|
    return false;
 | 
						|
  for (auto &Item : Array)
 | 
						|
    if (!verifyNode(Item))
 | 
						|
      return false;
 | 
						|
 | 
						|
  return true;
 | 
						|
}
 | 
						|
 | 
						|
bool MetadataVerifier::verifyEntry(
 | 
						|
    msgpack::MapDocNode &MapNode, StringRef Key, bool Required,
 | 
						|
    function_ref<bool(msgpack::DocNode &)> verifyNode) {
 | 
						|
  auto Entry = MapNode.find(Key);
 | 
						|
  if (Entry == MapNode.end())
 | 
						|
    return !Required;
 | 
						|
  return verifyNode(Entry->second);
 | 
						|
}
 | 
						|
 | 
						|
bool MetadataVerifier::verifyScalarEntry(
 | 
						|
    msgpack::MapDocNode &MapNode, StringRef Key, bool Required,
 | 
						|
    msgpack::Type SKind,
 | 
						|
    function_ref<bool(msgpack::DocNode &)> verifyValue) {
 | 
						|
  return verifyEntry(MapNode, Key, Required, [=](msgpack::DocNode &Node) {
 | 
						|
    return verifyScalar(Node, SKind, verifyValue);
 | 
						|
  });
 | 
						|
}
 | 
						|
 | 
						|
bool MetadataVerifier::verifyIntegerEntry(msgpack::MapDocNode &MapNode,
 | 
						|
                                          StringRef Key, bool Required) {
 | 
						|
  return verifyEntry(MapNode, Key, Required, [this](msgpack::DocNode &Node) {
 | 
						|
    return verifyInteger(Node);
 | 
						|
  });
 | 
						|
}
 | 
						|
 | 
						|
bool MetadataVerifier::verifyKernelArgs(msgpack::DocNode &Node) {
 | 
						|
  if (!Node.isMap())
 | 
						|
    return false;
 | 
						|
  auto &ArgsMap = Node.getMap();
 | 
						|
 | 
						|
  if (!verifyScalarEntry(ArgsMap, ".name", false,
 | 
						|
                         msgpack::Type::String))
 | 
						|
    return false;
 | 
						|
  if (!verifyScalarEntry(ArgsMap, ".type_name", false,
 | 
						|
                         msgpack::Type::String))
 | 
						|
    return false;
 | 
						|
  if (!verifyIntegerEntry(ArgsMap, ".size", true))
 | 
						|
    return false;
 | 
						|
  if (!verifyIntegerEntry(ArgsMap, ".offset", true))
 | 
						|
    return false;
 | 
						|
  if (!verifyScalarEntry(ArgsMap, ".value_kind", true,
 | 
						|
                         msgpack::Type::String,
 | 
						|
                         [](msgpack::DocNode &SNode) {
 | 
						|
                           return StringSwitch<bool>(SNode.getString())
 | 
						|
                               .Case("by_value", true)
 | 
						|
                               .Case("global_buffer", true)
 | 
						|
                               .Case("dynamic_shared_pointer", true)
 | 
						|
                               .Case("sampler", true)
 | 
						|
                               .Case("image", true)
 | 
						|
                               .Case("pipe", true)
 | 
						|
                               .Case("queue", true)
 | 
						|
                               .Case("hidden_global_offset_x", true)
 | 
						|
                               .Case("hidden_global_offset_y", true)
 | 
						|
                               .Case("hidden_global_offset_z", true)
 | 
						|
                               .Case("hidden_none", true)
 | 
						|
                               .Case("hidden_printf_buffer", true)
 | 
						|
                               .Case("hidden_hostcall_buffer", true)
 | 
						|
                               .Case("hidden_default_queue", true)
 | 
						|
                               .Case("hidden_completion_action", true)
 | 
						|
                               .Case("hidden_multigrid_sync_arg", true)
 | 
						|
                               .Default(false);
 | 
						|
                         }))
 | 
						|
    return false;
 | 
						|
  if (!verifyIntegerEntry(ArgsMap, ".pointee_align", false))
 | 
						|
    return false;
 | 
						|
  if (!verifyScalarEntry(ArgsMap, ".address_space", false,
 | 
						|
                         msgpack::Type::String,
 | 
						|
                         [](msgpack::DocNode &SNode) {
 | 
						|
                           return StringSwitch<bool>(SNode.getString())
 | 
						|
                               .Case("private", true)
 | 
						|
                               .Case("global", true)
 | 
						|
                               .Case("constant", true)
 | 
						|
                               .Case("local", true)
 | 
						|
                               .Case("generic", true)
 | 
						|
                               .Case("region", true)
 | 
						|
                               .Default(false);
 | 
						|
                         }))
 | 
						|
    return false;
 | 
						|
  if (!verifyScalarEntry(ArgsMap, ".access", false,
 | 
						|
                         msgpack::Type::String,
 | 
						|
                         [](msgpack::DocNode &SNode) {
 | 
						|
                           return StringSwitch<bool>(SNode.getString())
 | 
						|
                               .Case("read_only", true)
 | 
						|
                               .Case("write_only", true)
 | 
						|
                               .Case("read_write", true)
 | 
						|
                               .Default(false);
 | 
						|
                         }))
 | 
						|
    return false;
 | 
						|
  if (!verifyScalarEntry(ArgsMap, ".actual_access", false,
 | 
						|
                         msgpack::Type::String,
 | 
						|
                         [](msgpack::DocNode &SNode) {
 | 
						|
                           return StringSwitch<bool>(SNode.getString())
 | 
						|
                               .Case("read_only", true)
 | 
						|
                               .Case("write_only", true)
 | 
						|
                               .Case("read_write", true)
 | 
						|
                               .Default(false);
 | 
						|
                         }))
 | 
						|
    return false;
 | 
						|
  if (!verifyScalarEntry(ArgsMap, ".is_const", false,
 | 
						|
                         msgpack::Type::Boolean))
 | 
						|
    return false;
 | 
						|
  if (!verifyScalarEntry(ArgsMap, ".is_restrict", false,
 | 
						|
                         msgpack::Type::Boolean))
 | 
						|
    return false;
 | 
						|
  if (!verifyScalarEntry(ArgsMap, ".is_volatile", false,
 | 
						|
                         msgpack::Type::Boolean))
 | 
						|
    return false;
 | 
						|
  if (!verifyScalarEntry(ArgsMap, ".is_pipe", false,
 | 
						|
                         msgpack::Type::Boolean))
 | 
						|
    return false;
 | 
						|
 | 
						|
  return true;
 | 
						|
}
 | 
						|
 | 
						|
bool MetadataVerifier::verifyKernel(msgpack::DocNode &Node) {
 | 
						|
  if (!Node.isMap())
 | 
						|
    return false;
 | 
						|
  auto &KernelMap = Node.getMap();
 | 
						|
 | 
						|
  if (!verifyScalarEntry(KernelMap, ".name", true,
 | 
						|
                         msgpack::Type::String))
 | 
						|
    return false;
 | 
						|
  if (!verifyScalarEntry(KernelMap, ".symbol", true,
 | 
						|
                         msgpack::Type::String))
 | 
						|
    return false;
 | 
						|
  if (!verifyScalarEntry(KernelMap, ".language", false,
 | 
						|
                         msgpack::Type::String,
 | 
						|
                         [](msgpack::DocNode &SNode) {
 | 
						|
                           return StringSwitch<bool>(SNode.getString())
 | 
						|
                               .Case("OpenCL C", true)
 | 
						|
                               .Case("OpenCL C++", true)
 | 
						|
                               .Case("HCC", true)
 | 
						|
                               .Case("HIP", true)
 | 
						|
                               .Case("OpenMP", true)
 | 
						|
                               .Case("Assembler", true)
 | 
						|
                               .Default(false);
 | 
						|
                         }))
 | 
						|
    return false;
 | 
						|
  if (!verifyEntry(
 | 
						|
          KernelMap, ".language_version", false, [this](msgpack::DocNode &Node) {
 | 
						|
            return verifyArray(
 | 
						|
                Node,
 | 
						|
                [this](msgpack::DocNode &Node) { return verifyInteger(Node); }, 2);
 | 
						|
          }))
 | 
						|
    return false;
 | 
						|
  if (!verifyEntry(KernelMap, ".args", false, [this](msgpack::DocNode &Node) {
 | 
						|
        return verifyArray(Node, [this](msgpack::DocNode &Node) {
 | 
						|
          return verifyKernelArgs(Node);
 | 
						|
        });
 | 
						|
      }))
 | 
						|
    return false;
 | 
						|
  if (!verifyEntry(KernelMap, ".reqd_workgroup_size", false,
 | 
						|
                   [this](msgpack::DocNode &Node) {
 | 
						|
                     return verifyArray(Node,
 | 
						|
                                        [this](msgpack::DocNode &Node) {
 | 
						|
                                          return verifyInteger(Node);
 | 
						|
                                        },
 | 
						|
                                        3);
 | 
						|
                   }))
 | 
						|
    return false;
 | 
						|
  if (!verifyEntry(KernelMap, ".workgroup_size_hint", false,
 | 
						|
                   [this](msgpack::DocNode &Node) {
 | 
						|
                     return verifyArray(Node,
 | 
						|
                                        [this](msgpack::DocNode &Node) {
 | 
						|
                                          return verifyInteger(Node);
 | 
						|
                                        },
 | 
						|
                                        3);
 | 
						|
                   }))
 | 
						|
    return false;
 | 
						|
  if (!verifyScalarEntry(KernelMap, ".vec_type_hint", false,
 | 
						|
                         msgpack::Type::String))
 | 
						|
    return false;
 | 
						|
  if (!verifyScalarEntry(KernelMap, ".device_enqueue_symbol", false,
 | 
						|
                         msgpack::Type::String))
 | 
						|
    return false;
 | 
						|
  if (!verifyIntegerEntry(KernelMap, ".kernarg_segment_size", true))
 | 
						|
    return false;
 | 
						|
  if (!verifyIntegerEntry(KernelMap, ".group_segment_fixed_size", true))
 | 
						|
    return false;
 | 
						|
  if (!verifyIntegerEntry(KernelMap, ".private_segment_fixed_size", true))
 | 
						|
    return false;
 | 
						|
  if (!verifyIntegerEntry(KernelMap, ".kernarg_segment_align", true))
 | 
						|
    return false;
 | 
						|
  if (!verifyIntegerEntry(KernelMap, ".wavefront_size", true))
 | 
						|
    return false;
 | 
						|
  if (!verifyIntegerEntry(KernelMap, ".sgpr_count", true))
 | 
						|
    return false;
 | 
						|
  if (!verifyIntegerEntry(KernelMap, ".vgpr_count", true))
 | 
						|
    return false;
 | 
						|
  if (!verifyIntegerEntry(KernelMap, ".max_flat_workgroup_size", true))
 | 
						|
    return false;
 | 
						|
  if (!verifyIntegerEntry(KernelMap, ".sgpr_spill_count", false))
 | 
						|
    return false;
 | 
						|
  if (!verifyIntegerEntry(KernelMap, ".vgpr_spill_count", false))
 | 
						|
    return false;
 | 
						|
 | 
						|
  return true;
 | 
						|
}
 | 
						|
 | 
						|
bool MetadataVerifier::verify(msgpack::DocNode &HSAMetadataRoot) {
 | 
						|
  if (!HSAMetadataRoot.isMap())
 | 
						|
    return false;
 | 
						|
  auto &RootMap = HSAMetadataRoot.getMap();
 | 
						|
 | 
						|
  if (!verifyEntry(
 | 
						|
          RootMap, "amdhsa.version", true, [this](msgpack::DocNode &Node) {
 | 
						|
            return verifyArray(
 | 
						|
                Node,
 | 
						|
                [this](msgpack::DocNode &Node) { return verifyInteger(Node); }, 2);
 | 
						|
          }))
 | 
						|
    return false;
 | 
						|
  if (!verifyEntry(
 | 
						|
          RootMap, "amdhsa.printf", false, [this](msgpack::DocNode &Node) {
 | 
						|
            return verifyArray(Node, [this](msgpack::DocNode &Node) {
 | 
						|
              return verifyScalar(Node, msgpack::Type::String);
 | 
						|
            });
 | 
						|
          }))
 | 
						|
    return false;
 | 
						|
  if (!verifyEntry(RootMap, "amdhsa.kernels", true,
 | 
						|
                   [this](msgpack::DocNode &Node) {
 | 
						|
                     return verifyArray(Node, [this](msgpack::DocNode &Node) {
 | 
						|
                       return verifyKernel(Node);
 | 
						|
                     });
 | 
						|
                   }))
 | 
						|
    return false;
 | 
						|
 | 
						|
  return true;
 | 
						|
}
 | 
						|
 | 
						|
} // end namespace V3
 | 
						|
} // end namespace HSAMD
 | 
						|
} // end namespace AMDGPU
 | 
						|
} // end namespace llvm
 |