//===- Auto-generated file, part of the LLVM/Offload project --------------===//
//
// 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
//
//===----------------------------------------------------------------------===//

// Auto-generated file, do not manually edit.

#pragma once

#include <OffloadAPI.h>
#include <llvm/Support/raw_ostream.h>


template <typename T> inline ol_result_t printPtr(llvm::raw_ostream &os, const T *ptr);
template <typename T> inline void printTagged(llvm::raw_ostream &os, const void *ptr, T value, size_t size);
template <typename T> struct is_handle : std::false_type {};
template <> struct is_handle<ol_context_handle_t> : std::true_type {};
template <> struct is_handle<ol_device_handle_t> : std::true_type {};
template <> struct is_handle<ol_event_handle_t> : std::true_type {};
template <> struct is_handle<ol_platform_handle_t> : std::true_type {};
template <> struct is_handle<ol_program_handle_t> : std::true_type {};
template <> struct is_handle<ol_queue_handle_t> : std::true_type {};
template <> struct is_handle<ol_symbol_handle_t> : std::true_type {};
template <typename T> inline constexpr bool is_handle_v = is_handle<T>::value;

inline llvm::raw_ostream &operator<<(llvm::raw_ostream &os, enum ol_alloc_type_t value);
inline llvm::raw_ostream &operator<<(llvm::raw_ostream &os, enum ol_device_fp_capability_flag_t value);
inline llvm::raw_ostream &operator<<(llvm::raw_ostream &os, enum ol_device_info_t value);
inline llvm::raw_ostream &operator<<(llvm::raw_ostream &os, enum ol_device_type_t value);
inline llvm::raw_ostream &operator<<(llvm::raw_ostream &os, enum ol_errc_t value);
inline llvm::raw_ostream &operator<<(llvm::raw_ostream &os, enum ol_event_info_t value);
inline llvm::raw_ostream &operator<<(llvm::raw_ostream &os, enum ol_mem_info_t value);
inline llvm::raw_ostream &operator<<(llvm::raw_ostream &os, enum ol_platform_backend_t value);
inline llvm::raw_ostream &operator<<(llvm::raw_ostream &os, enum ol_platform_info_t value);
inline llvm::raw_ostream &operator<<(llvm::raw_ostream &os, enum ol_queue_info_t value);
inline llvm::raw_ostream &operator<<(llvm::raw_ostream &os, enum ol_symbol_info_t value);
inline llvm::raw_ostream &operator<<(llvm::raw_ostream &os, enum ol_symbol_kind_t value);
inline llvm::raw_ostream &operator<<(llvm::raw_ostream &os, const struct ol_code_location_t param);
inline llvm::raw_ostream &operator<<(llvm::raw_ostream &os, const struct ol_dimensions_t param);
inline llvm::raw_ostream &operator<<(llvm::raw_ostream &os, const struct ol_error_struct_t param);
inline llvm::raw_ostream &operator<<(llvm::raw_ostream &os, const struct ol_kernel_launch_size_args_t param);

///////////////////////////////////////////////////////////////////////////////
/// @brief Print operator for the ol_alloc_type_t type
/// @returns llvm::raw_ostream &
inline llvm::raw_ostream &operator<<(llvm::raw_ostream &os, enum ol_alloc_type_t value) {
  switch (value) {
  case OL_ALLOC_TYPE_HOST:
    os << "OL_ALLOC_TYPE_HOST";
    break;
  case OL_ALLOC_TYPE_DEVICE:
    os << "OL_ALLOC_TYPE_DEVICE";
    break;
  case OL_ALLOC_TYPE_MANAGED:
    os << "OL_ALLOC_TYPE_MANAGED";
    break;
  default:
    os << "unknown enumerator";
    break;
  }
  return os;
}

///////////////////////////////////////////////////////////////////////////////
/// @brief Print operator for the ol_device_fp_capability_flag_t type
/// @returns llvm::raw_ostream &
inline llvm::raw_ostream &operator<<(llvm::raw_ostream &os, enum ol_device_fp_capability_flag_t value) {
  switch (value) {
  case OL_DEVICE_FP_CAPABILITY_FLAG_CORRECTLY_ROUNDED_DIVIDE_SQRT:
    os << "OL_DEVICE_FP_CAPABILITY_FLAG_CORRECTLY_ROUNDED_DIVIDE_SQRT";
    break;
  case OL_DEVICE_FP_CAPABILITY_FLAG_ROUND_TO_NEAREST:
    os << "OL_DEVICE_FP_CAPABILITY_FLAG_ROUND_TO_NEAREST";
    break;
  case OL_DEVICE_FP_CAPABILITY_FLAG_ROUND_TO_ZERO:
    os << "OL_DEVICE_FP_CAPABILITY_FLAG_ROUND_TO_ZERO";
    break;
  case OL_DEVICE_FP_CAPABILITY_FLAG_ROUND_TO_INF:
    os << "OL_DEVICE_FP_CAPABILITY_FLAG_ROUND_TO_INF";
    break;
  case OL_DEVICE_FP_CAPABILITY_FLAG_INF_NAN:
    os << "OL_DEVICE_FP_CAPABILITY_FLAG_INF_NAN";
    break;
  case OL_DEVICE_FP_CAPABILITY_FLAG_DENORM:
    os << "OL_DEVICE_FP_CAPABILITY_FLAG_DENORM";
    break;
  case OL_DEVICE_FP_CAPABILITY_FLAG_FMA:
    os << "OL_DEVICE_FP_CAPABILITY_FLAG_FMA";
    break;
  case OL_DEVICE_FP_CAPABILITY_FLAG_SOFT_FLOAT:
    os << "OL_DEVICE_FP_CAPABILITY_FLAG_SOFT_FLOAT";
    break;
  default:
    os << "unknown enumerator";
    break;
  }
  return os;
}

///////////////////////////////////////////////////////////////////////////////
/// @brief Print operator for the ol_device_info_t type
/// @returns llvm::raw_ostream &
inline llvm::raw_ostream &operator<<(llvm::raw_ostream &os, enum ol_device_info_t value) {
  switch (value) {
  case OL_DEVICE_INFO_TYPE:
    os << "OL_DEVICE_INFO_TYPE";
    break;
  case OL_DEVICE_INFO_PLATFORM:
    os << "OL_DEVICE_INFO_PLATFORM";
    break;
  case OL_DEVICE_INFO_NAME:
    os << "OL_DEVICE_INFO_NAME";
    break;
  case OL_DEVICE_INFO_PRODUCT_NAME:
    os << "OL_DEVICE_INFO_PRODUCT_NAME";
    break;
  case OL_DEVICE_INFO_UID:
    os << "OL_DEVICE_INFO_UID";
    break;
  case OL_DEVICE_INFO_VENDOR:
    os << "OL_DEVICE_INFO_VENDOR";
    break;
  case OL_DEVICE_INFO_DRIVER_VERSION:
    os << "OL_DEVICE_INFO_DRIVER_VERSION";
    break;
  case OL_DEVICE_INFO_MAX_WORK_GROUP_SIZE:
    os << "OL_DEVICE_INFO_MAX_WORK_GROUP_SIZE";
    break;
  case OL_DEVICE_INFO_MAX_WORK_GROUP_SIZE_PER_DIMENSION:
    os << "OL_DEVICE_INFO_MAX_WORK_GROUP_SIZE_PER_DIMENSION";
    break;
  case OL_DEVICE_INFO_MAX_WORK_SIZE:
    os << "OL_DEVICE_INFO_MAX_WORK_SIZE";
    break;
  case OL_DEVICE_INFO_MAX_WORK_SIZE_PER_DIMENSION:
    os << "OL_DEVICE_INFO_MAX_WORK_SIZE_PER_DIMENSION";
    break;
  case OL_DEVICE_INFO_VENDOR_ID:
    os << "OL_DEVICE_INFO_VENDOR_ID";
    break;
  case OL_DEVICE_INFO_NUM_COMPUTE_UNITS:
    os << "OL_DEVICE_INFO_NUM_COMPUTE_UNITS";
    break;
  case OL_DEVICE_INFO_MAX_CLOCK_FREQUENCY:
    os << "OL_DEVICE_INFO_MAX_CLOCK_FREQUENCY";
    break;
  case OL_DEVICE_INFO_MEMORY_CLOCK_RATE:
    os << "OL_DEVICE_INFO_MEMORY_CLOCK_RATE";
    break;
  case OL_DEVICE_INFO_ADDRESS_BITS:
    os << "OL_DEVICE_INFO_ADDRESS_BITS";
    break;
  case OL_DEVICE_INFO_MAX_MEM_ALLOC_SIZE:
    os << "OL_DEVICE_INFO_MAX_MEM_ALLOC_SIZE";
    break;
  case OL_DEVICE_INFO_GLOBAL_MEM_SIZE:
    os << "OL_DEVICE_INFO_GLOBAL_MEM_SIZE";
    break;
  case OL_DEVICE_INFO_WORK_GROUP_LOCAL_MEM_SIZE:
    os << "OL_DEVICE_INFO_WORK_GROUP_LOCAL_MEM_SIZE";
    break;
  case OL_DEVICE_INFO_SINGLE_FP_CONFIG:
    os << "OL_DEVICE_INFO_SINGLE_FP_CONFIG";
    break;
  case OL_DEVICE_INFO_DOUBLE_FP_CONFIG:
    os << "OL_DEVICE_INFO_DOUBLE_FP_CONFIG";
    break;
  case OL_DEVICE_INFO_HALF_FP_CONFIG:
    os << "OL_DEVICE_INFO_HALF_FP_CONFIG";
    break;
  case OL_DEVICE_INFO_NATIVE_VECTOR_WIDTH_CHAR:
    os << "OL_DEVICE_INFO_NATIVE_VECTOR_WIDTH_CHAR";
    break;
  case OL_DEVICE_INFO_NATIVE_VECTOR_WIDTH_SHORT:
    os << "OL_DEVICE_INFO_NATIVE_VECTOR_WIDTH_SHORT";
    break;
  case OL_DEVICE_INFO_NATIVE_VECTOR_WIDTH_INT:
    os << "OL_DEVICE_INFO_NATIVE_VECTOR_WIDTH_INT";
    break;
  case OL_DEVICE_INFO_NATIVE_VECTOR_WIDTH_LONG:
    os << "OL_DEVICE_INFO_NATIVE_VECTOR_WIDTH_LONG";
    break;
  case OL_DEVICE_INFO_NATIVE_VECTOR_WIDTH_FLOAT:
    os << "OL_DEVICE_INFO_NATIVE_VECTOR_WIDTH_FLOAT";
    break;
  case OL_DEVICE_INFO_NATIVE_VECTOR_WIDTH_DOUBLE:
    os << "OL_DEVICE_INFO_NATIVE_VECTOR_WIDTH_DOUBLE";
    break;
  case OL_DEVICE_INFO_NATIVE_VECTOR_WIDTH_HALF:
    os << "OL_DEVICE_INFO_NATIVE_VECTOR_WIDTH_HALF";
    break;
  default:
    os << "unknown enumerator";
    break;
  }
  return os;
}

///////////////////////////////////////////////////////////////////////////////
/// @brief Print type-tagged ol_device_info_t enum value
/// @returns llvm::raw_ostream &
template <>
inline void printTagged(llvm::raw_ostream &os, const void *ptr, ol_device_info_t value, size_t size) {
  if (ptr == NULL) {
    printPtr(os, ptr);
    return;
  }

  switch (value) {
  case OL_DEVICE_INFO_TYPE: {
    const ol_device_type_t * const tptr = (const ol_device_type_t * const)ptr;
    os << (const void *)tptr << " (";
    os << *tptr;
    os << ")";
    break;
  }
  case OL_DEVICE_INFO_PLATFORM: {
    const ol_platform_handle_t * const tptr = (const ol_platform_handle_t * const)ptr;
    os << (const void *)tptr << " (";
    os << *tptr;
    os << ")";
    break;
  }
  case OL_DEVICE_INFO_NAME: {
    printPtr(os, (const char*) ptr);
    break;
  }
  case OL_DEVICE_INFO_PRODUCT_NAME: {
    printPtr(os, (const char*) ptr);
    break;
  }
  case OL_DEVICE_INFO_UID: {
    printPtr(os, (const char*) ptr);
    break;
  }
  case OL_DEVICE_INFO_VENDOR: {
    printPtr(os, (const char*) ptr);
    break;
  }
  case OL_DEVICE_INFO_DRIVER_VERSION: {
    printPtr(os, (const char*) ptr);
    break;
  }
  case OL_DEVICE_INFO_MAX_WORK_GROUP_SIZE: {
    const uint32_t * const tptr = (const uint32_t * const)ptr;
    os << (const void *)tptr << " (";
    os << *tptr;
    os << ")";
    break;
  }
  case OL_DEVICE_INFO_MAX_WORK_GROUP_SIZE_PER_DIMENSION: {
    const ol_dimensions_t * const tptr = (const ol_dimensions_t * const)ptr;
    os << (const void *)tptr << " (";
    os << *tptr;
    os << ")";
    break;
  }
  case OL_DEVICE_INFO_MAX_WORK_SIZE: {
    const uint32_t * const tptr = (const uint32_t * const)ptr;
    os << (const void *)tptr << " (";
    os << *tptr;
    os << ")";
    break;
  }
  case OL_DEVICE_INFO_MAX_WORK_SIZE_PER_DIMENSION: {
    const ol_dimensions_t * const tptr = (const ol_dimensions_t * const)ptr;
    os << (const void *)tptr << " (";
    os << *tptr;
    os << ")";
    break;
  }
  case OL_DEVICE_INFO_VENDOR_ID: {
    const uint32_t * const tptr = (const uint32_t * const)ptr;
    os << (const void *)tptr << " (";
    os << *tptr;
    os << ")";
    break;
  }
  case OL_DEVICE_INFO_NUM_COMPUTE_UNITS: {
    const uint32_t * const tptr = (const uint32_t * const)ptr;
    os << (const void *)tptr << " (";
    os << *tptr;
    os << ")";
    break;
  }
  case OL_DEVICE_INFO_MAX_CLOCK_FREQUENCY: {
    const uint32_t * const tptr = (const uint32_t * const)ptr;
    os << (const void *)tptr << " (";
    os << *tptr;
    os << ")";
    break;
  }
  case OL_DEVICE_INFO_MEMORY_CLOCK_RATE: {
    const uint32_t * const tptr = (const uint32_t * const)ptr;
    os << (const void *)tptr << " (";
    os << *tptr;
    os << ")";
    break;
  }
  case OL_DEVICE_INFO_ADDRESS_BITS: {
    const uint32_t * const tptr = (const uint32_t * const)ptr;
    os << (const void *)tptr << " (";
    os << *tptr;
    os << ")";
    break;
  }
  case OL_DEVICE_INFO_MAX_MEM_ALLOC_SIZE: {
    const uint64_t * const tptr = (const uint64_t * const)ptr;
    os << (const void *)tptr << " (";
    os << *tptr;
    os << ")";
    break;
  }
  case OL_DEVICE_INFO_GLOBAL_MEM_SIZE: {
    const uint64_t * const tptr = (const uint64_t * const)ptr;
    os << (const void *)tptr << " (";
    os << *tptr;
    os << ")";
    break;
  }
  case OL_DEVICE_INFO_WORK_GROUP_LOCAL_MEM_SIZE: {
    const uint64_t * const tptr = (const uint64_t * const)ptr;
    os << (const void *)tptr << " (";
    os << *tptr;
    os << ")";
    break;
  }
  case OL_DEVICE_INFO_SINGLE_FP_CONFIG: {
    const ol_device_fp_capability_flags_t * const tptr = (const ol_device_fp_capability_flags_t * const)ptr;
    os << (const void *)tptr << " (";
    os << *tptr;
    os << ")";
    break;
  }
  case OL_DEVICE_INFO_DOUBLE_FP_CONFIG: {
    const ol_device_fp_capability_flags_t * const tptr = (const ol_device_fp_capability_flags_t * const)ptr;
    os << (const void *)tptr << " (";
    os << *tptr;
    os << ")";
    break;
  }
  case OL_DEVICE_INFO_HALF_FP_CONFIG: {
    const ol_device_fp_capability_flags_t * const tptr = (const ol_device_fp_capability_flags_t * const)ptr;
    os << (const void *)tptr << " (";
    os << *tptr;
    os << ")";
    break;
  }
  case OL_DEVICE_INFO_NATIVE_VECTOR_WIDTH_CHAR: {
    const uint32_t * const tptr = (const uint32_t * const)ptr;
    os << (const void *)tptr << " (";
    os << *tptr;
    os << ")";
    break;
  }
  case OL_DEVICE_INFO_NATIVE_VECTOR_WIDTH_SHORT: {
    const uint32_t * const tptr = (const uint32_t * const)ptr;
    os << (const void *)tptr << " (";
    os << *tptr;
    os << ")";
    break;
  }
  case OL_DEVICE_INFO_NATIVE_VECTOR_WIDTH_INT: {
    const uint32_t * const tptr = (const uint32_t * const)ptr;
    os << (const void *)tptr << " (";
    os << *tptr;
    os << ")";
    break;
  }
  case OL_DEVICE_INFO_NATIVE_VECTOR_WIDTH_LONG: {
    const uint32_t * const tptr = (const uint32_t * const)ptr;
    os << (const void *)tptr << " (";
    os << *tptr;
    os << ")";
    break;
  }
  case OL_DEVICE_INFO_NATIVE_VECTOR_WIDTH_FLOAT: {
    const uint32_t * const tptr = (const uint32_t * const)ptr;
    os << (const void *)tptr << " (";
    os << *tptr;
    os << ")";
    break;
  }
  case OL_DEVICE_INFO_NATIVE_VECTOR_WIDTH_DOUBLE: {
    const uint32_t * const tptr = (const uint32_t * const)ptr;
    os << (const void *)tptr << " (";
    os << *tptr;
    os << ")";
    break;
  }
  case OL_DEVICE_INFO_NATIVE_VECTOR_WIDTH_HALF: {
    const uint32_t * const tptr = (const uint32_t * const)ptr;
    os << (const void *)tptr << " (";
    os << *tptr;
    os << ")";
    break;
  }
  default:
    os << "unknown enumerator";
    break;
  }
}
///////////////////////////////////////////////////////////////////////////////
/// @brief Print operator for the ol_device_type_t type
/// @returns llvm::raw_ostream &
inline llvm::raw_ostream &operator<<(llvm::raw_ostream &os, enum ol_device_type_t value) {
  switch (value) {
  case OL_DEVICE_TYPE_DEFAULT:
    os << "OL_DEVICE_TYPE_DEFAULT";
    break;
  case OL_DEVICE_TYPE_ALL:
    os << "OL_DEVICE_TYPE_ALL";
    break;
  case OL_DEVICE_TYPE_GPU:
    os << "OL_DEVICE_TYPE_GPU";
    break;
  case OL_DEVICE_TYPE_CPU:
    os << "OL_DEVICE_TYPE_CPU";
    break;
  case OL_DEVICE_TYPE_HOST:
    os << "OL_DEVICE_TYPE_HOST";
    break;
  default:
    os << "unknown enumerator";
    break;
  }
  return os;
}

///////////////////////////////////////////////////////////////////////////////
/// @brief Print operator for the ol_errc_t type
/// @returns llvm::raw_ostream &
inline llvm::raw_ostream &operator<<(llvm::raw_ostream &os, enum ol_errc_t value) {
  switch (value) {
  case OL_ERRC_SUCCESS:
    os << "OL_ERRC_SUCCESS";
    break;
  case OL_ERRC_UNKNOWN:
    os << "OL_ERRC_UNKNOWN";
    break;
  case OL_ERRC_HOST_IO:
    os << "OL_ERRC_HOST_IO";
    break;
  case OL_ERRC_INVALID_BINARY:
    os << "OL_ERRC_INVALID_BINARY";
    break;
  case OL_ERRC_INVALID_NULL_POINTER:
    os << "OL_ERRC_INVALID_NULL_POINTER";
    break;
  case OL_ERRC_INVALID_ARGUMENT:
    os << "OL_ERRC_INVALID_ARGUMENT";
    break;
  case OL_ERRC_NOT_FOUND:
    os << "OL_ERRC_NOT_FOUND";
    break;
  case OL_ERRC_OUT_OF_RESOURCES:
    os << "OL_ERRC_OUT_OF_RESOURCES";
    break;
  case OL_ERRC_INVALID_SIZE:
    os << "OL_ERRC_INVALID_SIZE";
    break;
  case OL_ERRC_INVALID_ENUMERATION:
    os << "OL_ERRC_INVALID_ENUMERATION";
    break;
  case OL_ERRC_HOST_TOOL_NOT_FOUND:
    os << "OL_ERRC_HOST_TOOL_NOT_FOUND";
    break;
  case OL_ERRC_INVALID_VALUE:
    os << "OL_ERRC_INVALID_VALUE";
    break;
  case OL_ERRC_UNIMPLEMENTED:
    os << "OL_ERRC_UNIMPLEMENTED";
    break;
  case OL_ERRC_UNSUPPORTED:
    os << "OL_ERRC_UNSUPPORTED";
    break;
  case OL_ERRC_ASSEMBLE_FAILURE:
    os << "OL_ERRC_ASSEMBLE_FAILURE";
    break;
  case OL_ERRC_COMPILE_FAILURE:
    os << "OL_ERRC_COMPILE_FAILURE";
    break;
  case OL_ERRC_LINK_FAILURE:
    os << "OL_ERRC_LINK_FAILURE";
    break;
  case OL_ERRC_BACKEND_FAILURE:
    os << "OL_ERRC_BACKEND_FAILURE";
    break;
  case OL_ERRC_UNINITIALIZED:
    os << "OL_ERRC_UNINITIALIZED";
    break;
  case OL_ERRC_INVALID_NULL_HANDLE:
    os << "OL_ERRC_INVALID_NULL_HANDLE";
    break;
  case OL_ERRC_INVALID_PLATFORM:
    os << "OL_ERRC_INVALID_PLATFORM";
    break;
  case OL_ERRC_INVALID_DEVICE:
    os << "OL_ERRC_INVALID_DEVICE";
    break;
  case OL_ERRC_INVALID_QUEUE:
    os << "OL_ERRC_INVALID_QUEUE";
    break;
  case OL_ERRC_INVALID_EVENT:
    os << "OL_ERRC_INVALID_EVENT";
    break;
  case OL_ERRC_SYMBOL_KIND:
    os << "OL_ERRC_SYMBOL_KIND";
    break;
  default:
    os << "unknown enumerator";
    break;
  }
  return os;
}

///////////////////////////////////////////////////////////////////////////////
/// @brief Print operator for the ol_event_info_t type
/// @returns llvm::raw_ostream &
inline llvm::raw_ostream &operator<<(llvm::raw_ostream &os, enum ol_event_info_t value) {
  switch (value) {
  case OL_EVENT_INFO_QUEUE:
    os << "OL_EVENT_INFO_QUEUE";
    break;
  case OL_EVENT_INFO_IS_COMPLETE:
    os << "OL_EVENT_INFO_IS_COMPLETE";
    break;
  default:
    os << "unknown enumerator";
    break;
  }
  return os;
}

///////////////////////////////////////////////////////////////////////////////
/// @brief Print type-tagged ol_event_info_t enum value
/// @returns llvm::raw_ostream &
template <>
inline void printTagged(llvm::raw_ostream &os, const void *ptr, ol_event_info_t value, size_t size) {
  if (ptr == NULL) {
    printPtr(os, ptr);
    return;
  }

  switch (value) {
  case OL_EVENT_INFO_QUEUE: {
    const ol_queue_handle_t * const tptr = (const ol_queue_handle_t * const)ptr;
    os << (const void *)tptr << " (";
    os << *tptr;
    os << ")";
    break;
  }
  case OL_EVENT_INFO_IS_COMPLETE: {
    const bool * const tptr = (const bool * const)ptr;
    os << (const void *)tptr << " (";
    os << *tptr;
    os << ")";
    break;
  }
  default:
    os << "unknown enumerator";
    break;
  }
}
///////////////////////////////////////////////////////////////////////////////
/// @brief Print operator for the ol_mem_info_t type
/// @returns llvm::raw_ostream &
inline llvm::raw_ostream &operator<<(llvm::raw_ostream &os, enum ol_mem_info_t value) {
  switch (value) {
  case OL_MEM_INFO_DEVICE:
    os << "OL_MEM_INFO_DEVICE";
    break;
  case OL_MEM_INFO_BASE:
    os << "OL_MEM_INFO_BASE";
    break;
  case OL_MEM_INFO_SIZE:
    os << "OL_MEM_INFO_SIZE";
    break;
  case OL_MEM_INFO_TYPE:
    os << "OL_MEM_INFO_TYPE";
    break;
  default:
    os << "unknown enumerator";
    break;
  }
  return os;
}

///////////////////////////////////////////////////////////////////////////////
/// @brief Print type-tagged ol_mem_info_t enum value
/// @returns llvm::raw_ostream &
template <>
inline void printTagged(llvm::raw_ostream &os, const void *ptr, ol_mem_info_t value, size_t size) {
  if (ptr == NULL) {
    printPtr(os, ptr);
    return;
  }

  switch (value) {
  case OL_MEM_INFO_DEVICE: {
    const ol_device_handle_t * const tptr = (const ol_device_handle_t * const)ptr;
    os << (const void *)tptr << " (";
    os << *tptr;
    os << ")";
    break;
  }
  case OL_MEM_INFO_BASE: {
    void * const * const tptr = (void * const * const)ptr;
    os << (const void *)tptr << " (";
    os << printPtr(os, tptr);
    os << ")";
    break;
  }
  case OL_MEM_INFO_SIZE: {
    const size_t * const tptr = (const size_t * const)ptr;
    os << (const void *)tptr << " (";
    os << *tptr;
    os << ")";
    break;
  }
  case OL_MEM_INFO_TYPE: {
    const ol_alloc_type_t * const tptr = (const ol_alloc_type_t * const)ptr;
    os << (const void *)tptr << " (";
    os << *tptr;
    os << ")";
    break;
  }
  default:
    os << "unknown enumerator";
    break;
  }
}
///////////////////////////////////////////////////////////////////////////////
/// @brief Print operator for the ol_platform_backend_t type
/// @returns llvm::raw_ostream &
inline llvm::raw_ostream &operator<<(llvm::raw_ostream &os, enum ol_platform_backend_t value) {
  switch (value) {
  case OL_PLATFORM_BACKEND_UNKNOWN:
    os << "OL_PLATFORM_BACKEND_UNKNOWN";
    break;
  case OL_PLATFORM_BACKEND_CUDA:
    os << "OL_PLATFORM_BACKEND_CUDA";
    break;
  case OL_PLATFORM_BACKEND_AMDGPU:
    os << "OL_PLATFORM_BACKEND_AMDGPU";
    break;
  case OL_PLATFORM_BACKEND_HOST:
    os << "OL_PLATFORM_BACKEND_HOST";
    break;
  default:
    os << "unknown enumerator";
    break;
  }
  return os;
}

///////////////////////////////////////////////////////////////////////////////
/// @brief Print operator for the ol_platform_info_t type
/// @returns llvm::raw_ostream &
inline llvm::raw_ostream &operator<<(llvm::raw_ostream &os, enum ol_platform_info_t value) {
  switch (value) {
  case OL_PLATFORM_INFO_NAME:
    os << "OL_PLATFORM_INFO_NAME";
    break;
  case OL_PLATFORM_INFO_VENDOR_NAME:
    os << "OL_PLATFORM_INFO_VENDOR_NAME";
    break;
  case OL_PLATFORM_INFO_VERSION:
    os << "OL_PLATFORM_INFO_VERSION";
    break;
  case OL_PLATFORM_INFO_BACKEND:
    os << "OL_PLATFORM_INFO_BACKEND";
    break;
  default:
    os << "unknown enumerator";
    break;
  }
  return os;
}

///////////////////////////////////////////////////////////////////////////////
/// @brief Print type-tagged ol_platform_info_t enum value
/// @returns llvm::raw_ostream &
template <>
inline void printTagged(llvm::raw_ostream &os, const void *ptr, ol_platform_info_t value, size_t size) {
  if (ptr == NULL) {
    printPtr(os, ptr);
    return;
  }

  switch (value) {
  case OL_PLATFORM_INFO_NAME: {
    printPtr(os, (const char*) ptr);
    break;
  }
  case OL_PLATFORM_INFO_VENDOR_NAME: {
    printPtr(os, (const char*) ptr);
    break;
  }
  case OL_PLATFORM_INFO_VERSION: {
    printPtr(os, (const char*) ptr);
    break;
  }
  case OL_PLATFORM_INFO_BACKEND: {
    const ol_platform_backend_t * const tptr = (const ol_platform_backend_t * const)ptr;
    os << (const void *)tptr << " (";
    os << *tptr;
    os << ")";
    break;
  }
  default:
    os << "unknown enumerator";
    break;
  }
}
///////////////////////////////////////////////////////////////////////////////
/// @brief Print operator for the ol_queue_info_t type
/// @returns llvm::raw_ostream &
inline llvm::raw_ostream &operator<<(llvm::raw_ostream &os, enum ol_queue_info_t value) {
  switch (value) {
  case OL_QUEUE_INFO_DEVICE:
    os << "OL_QUEUE_INFO_DEVICE";
    break;
  case OL_QUEUE_INFO_EMPTY:
    os << "OL_QUEUE_INFO_EMPTY";
    break;
  default:
    os << "unknown enumerator";
    break;
  }
  return os;
}

///////////////////////////////////////////////////////////////////////////////
/// @brief Print type-tagged ol_queue_info_t enum value
/// @returns llvm::raw_ostream &
template <>
inline void printTagged(llvm::raw_ostream &os, const void *ptr, ol_queue_info_t value, size_t size) {
  if (ptr == NULL) {
    printPtr(os, ptr);
    return;
  }

  switch (value) {
  case OL_QUEUE_INFO_DEVICE: {
    const ol_device_handle_t * const tptr = (const ol_device_handle_t * const)ptr;
    os << (const void *)tptr << " (";
    os << *tptr;
    os << ")";
    break;
  }
  case OL_QUEUE_INFO_EMPTY: {
    const bool * const tptr = (const bool * const)ptr;
    os << (const void *)tptr << " (";
    os << *tptr;
    os << ")";
    break;
  }
  default:
    os << "unknown enumerator";
    break;
  }
}
///////////////////////////////////////////////////////////////////////////////
/// @brief Print operator for the ol_symbol_info_t type
/// @returns llvm::raw_ostream &
inline llvm::raw_ostream &operator<<(llvm::raw_ostream &os, enum ol_symbol_info_t value) {
  switch (value) {
  case OL_SYMBOL_INFO_KIND:
    os << "OL_SYMBOL_INFO_KIND";
    break;
  case OL_SYMBOL_INFO_GLOBAL_VARIABLE_ADDRESS:
    os << "OL_SYMBOL_INFO_GLOBAL_VARIABLE_ADDRESS";
    break;
  case OL_SYMBOL_INFO_GLOBAL_VARIABLE_SIZE:
    os << "OL_SYMBOL_INFO_GLOBAL_VARIABLE_SIZE";
    break;
  default:
    os << "unknown enumerator";
    break;
  }
  return os;
}

///////////////////////////////////////////////////////////////////////////////
/// @brief Print type-tagged ol_symbol_info_t enum value
/// @returns llvm::raw_ostream &
template <>
inline void printTagged(llvm::raw_ostream &os, const void *ptr, ol_symbol_info_t value, size_t size) {
  if (ptr == NULL) {
    printPtr(os, ptr);
    return;
  }

  switch (value) {
  case OL_SYMBOL_INFO_KIND: {
    const ol_symbol_kind_t * const tptr = (const ol_symbol_kind_t * const)ptr;
    os << (const void *)tptr << " (";
    os << *tptr;
    os << ")";
    break;
  }
  case OL_SYMBOL_INFO_GLOBAL_VARIABLE_ADDRESS: {
    void * const * const tptr = (void * const * const)ptr;
    os << (const void *)tptr << " (";
    os << printPtr(os, tptr);
    os << ")";
    break;
  }
  case OL_SYMBOL_INFO_GLOBAL_VARIABLE_SIZE: {
    const size_t * const tptr = (const size_t * const)ptr;
    os << (const void *)tptr << " (";
    os << *tptr;
    os << ")";
    break;
  }
  default:
    os << "unknown enumerator";
    break;
  }
}
///////////////////////////////////////////////////////////////////////////////
/// @brief Print operator for the ol_symbol_kind_t type
/// @returns llvm::raw_ostream &
inline llvm::raw_ostream &operator<<(llvm::raw_ostream &os, enum ol_symbol_kind_t value) {
  switch (value) {
  case OL_SYMBOL_KIND_KERNEL:
    os << "OL_SYMBOL_KIND_KERNEL";
    break;
  case OL_SYMBOL_KIND_GLOBAL_VARIABLE:
    os << "OL_SYMBOL_KIND_GLOBAL_VARIABLE";
    break;
  default:
    os << "unknown enumerator";
    break;
  }
  return os;
}


inline llvm::raw_ostream &operator<<(llvm::raw_ostream &os,
                                const ol_error_struct_t *Err) {
  if (Err == nullptr) {
    os << "OL_SUCCESS";
  } else {
    os << Err->Code;
  }
  return os;
}
///////////////////////////////////////////////////////////////////////////////
/// @brief Print operator for the ol_code_location_t type
/// @returns llvm::raw_ostream &

inline llvm::raw_ostream &operator<<(llvm::raw_ostream &os, const struct ol_code_location_t params) {
  os << "(struct ol_code_location_t){";
  os << ".FunctionName = ";
  printPtr(os, params.FunctionName);
  os << ", ";
  os << ".SourceFile = ";
  printPtr(os, params.SourceFile);
  os << ", ";
  os << ".LineNumber = ";
  os << params.LineNumber;
  os << ", ";
  os << ".ColumnNumber = ";
  os << params.ColumnNumber;
  os << "}";
  return os;
}
///////////////////////////////////////////////////////////////////////////////
/// @brief Print operator for the ol_dimensions_t type
/// @returns llvm::raw_ostream &

inline llvm::raw_ostream &operator<<(llvm::raw_ostream &os, const struct ol_dimensions_t params) {
  os << "(struct ol_dimensions_t){";
  os << ".x = ";
  os << params.x;
  os << ", ";
  os << ".y = ";
  os << params.y;
  os << ", ";
  os << ".z = ";
  os << params.z;
  os << "}";
  return os;
}
///////////////////////////////////////////////////////////////////////////////
/// @brief Print operator for the ol_kernel_launch_size_args_t type
/// @returns llvm::raw_ostream &

inline llvm::raw_ostream &operator<<(llvm::raw_ostream &os, const struct ol_kernel_launch_size_args_t params) {
  os << "(struct ol_kernel_launch_size_args_t){";
  os << ".Dimensions = ";
  os << params.Dimensions;
  os << ", ";
  os << ".NumGroups = ";
  os << params.NumGroups;
  os << ", ";
  os << ".GroupSize = ";
  os << params.GroupSize;
  os << ", ";
  os << ".DynSharedMemory = ";
  os << params.DynSharedMemory;
  os << "}";
  return os;
}

inline llvm::raw_ostream &operator<<(llvm::raw_ostream &os, const struct ol_calculate_optimal_occupancy_params_t *params) {
  os << ".Device = ";
  printPtr(os, *params->pDevice);
  os << ", ";
  os << ".Kernel = ";
  printPtr(os, *params->pKernel);
  os << ", ";
  os << ".SharedMemory = ";
  os << *params->pSharedMemory;
  os << ", ";
  os << ".GroupSize = ";
  printPtr(os, *params->pGroupSize);
  return os;
}

inline llvm::raw_ostream &operator<<(llvm::raw_ostream &os, const struct ol_create_event_params_t *params) {
  os << ".Queue = ";
  printPtr(os, *params->pQueue);
  os << ", ";
  os << ".Event = ";
  printPtr(os, *params->pEvent);
  return os;
}

inline llvm::raw_ostream &operator<<(llvm::raw_ostream &os, const struct ol_create_program_params_t *params) {
  os << ".Device = ";
  printPtr(os, *params->pDevice);
  os << ", ";
  os << ".ProgData = ";
  printPtr(os, *params->pProgData);
  os << ", ";
  os << ".ProgDataSize = ";
  os << *params->pProgDataSize;
  os << ", ";
  os << ".Program = ";
  printPtr(os, *params->pProgram);
  return os;
}

inline llvm::raw_ostream &operator<<(llvm::raw_ostream &os, const struct ol_create_queue_params_t *params) {
  os << ".Device = ";
  printPtr(os, *params->pDevice);
  os << ", ";
  os << ".Queue = ";
  printPtr(os, *params->pQueue);
  return os;
}

inline llvm::raw_ostream &operator<<(llvm::raw_ostream &os, const struct ol_destroy_event_params_t *params) {
  os << ".Event = ";
  printPtr(os, *params->pEvent);
  return os;
}

inline llvm::raw_ostream &operator<<(llvm::raw_ostream &os, const struct ol_destroy_program_params_t *params) {
  os << ".Program = ";
  printPtr(os, *params->pProgram);
  return os;
}

inline llvm::raw_ostream &operator<<(llvm::raw_ostream &os, const struct ol_destroy_queue_params_t *params) {
  os << ".Queue = ";
  printPtr(os, *params->pQueue);
  return os;
}

inline llvm::raw_ostream &operator<<(llvm::raw_ostream &os, const struct ol_get_device_info_params_t *params) {
  os << ".Device = ";
  printPtr(os, *params->pDevice);
  os << ", ";
  os << ".PropName = ";
  os << *params->pPropName;
  os << ", ";
  os << ".PropSize = ";
  os << *params->pPropSize;
  os << ", ";
  os << ".PropValue = ";
  printTagged(os, *params->pPropValue, *params->pPropName, *params->pPropSize);
  return os;
}

inline llvm::raw_ostream &operator<<(llvm::raw_ostream &os, const struct ol_get_device_info_size_params_t *params) {
  os << ".Device = ";
  printPtr(os, *params->pDevice);
  os << ", ";
  os << ".PropName = ";
  os << *params->pPropName;
  os << ", ";
  os << ".PropSizeRet = ";
  printPtr(os, *params->pPropSizeRet);
  return os;
}

inline llvm::raw_ostream &operator<<(llvm::raw_ostream &os, const struct ol_get_event_info_params_t *params) {
  os << ".Event = ";
  printPtr(os, *params->pEvent);
  os << ", ";
  os << ".PropName = ";
  os << *params->pPropName;
  os << ", ";
  os << ".PropSize = ";
  os << *params->pPropSize;
  os << ", ";
  os << ".PropValue = ";
  printTagged(os, *params->pPropValue, *params->pPropName, *params->pPropSize);
  return os;
}

inline llvm::raw_ostream &operator<<(llvm::raw_ostream &os, const struct ol_get_event_info_size_params_t *params) {
  os << ".Event = ";
  printPtr(os, *params->pEvent);
  os << ", ";
  os << ".PropName = ";
  os << *params->pPropName;
  os << ", ";
  os << ".PropSizeRet = ";
  printPtr(os, *params->pPropSizeRet);
  return os;
}

inline llvm::raw_ostream &operator<<(llvm::raw_ostream &os, const struct ol_get_mem_info_params_t *params) {
  os << ".Ptr = ";
  printPtr(os, *params->pPtr);
  os << ", ";
  os << ".PropName = ";
  os << *params->pPropName;
  os << ", ";
  os << ".PropSize = ";
  os << *params->pPropSize;
  os << ", ";
  os << ".PropValue = ";
  printTagged(os, *params->pPropValue, *params->pPropName, *params->pPropSize);
  return os;
}

inline llvm::raw_ostream &operator<<(llvm::raw_ostream &os, const struct ol_get_mem_info_size_params_t *params) {
  os << ".Ptr = ";
  printPtr(os, *params->pPtr);
  os << ", ";
  os << ".PropName = ";
  os << *params->pPropName;
  os << ", ";
  os << ".PropSizeRet = ";
  printPtr(os, *params->pPropSizeRet);
  return os;
}

inline llvm::raw_ostream &operator<<(llvm::raw_ostream &os, const struct ol_get_platform_info_params_t *params) {
  os << ".Platform = ";
  printPtr(os, *params->pPlatform);
  os << ", ";
  os << ".PropName = ";
  os << *params->pPropName;
  os << ", ";
  os << ".PropSize = ";
  os << *params->pPropSize;
  os << ", ";
  os << ".PropValue = ";
  printTagged(os, *params->pPropValue, *params->pPropName, *params->pPropSize);
  return os;
}

inline llvm::raw_ostream &operator<<(llvm::raw_ostream &os, const struct ol_get_platform_info_size_params_t *params) {
  os << ".Platform = ";
  printPtr(os, *params->pPlatform);
  os << ", ";
  os << ".PropName = ";
  os << *params->pPropName;
  os << ", ";
  os << ".PropSizeRet = ";
  printPtr(os, *params->pPropSizeRet);
  return os;
}

inline llvm::raw_ostream &operator<<(llvm::raw_ostream &os, const struct ol_get_queue_info_params_t *params) {
  os << ".Queue = ";
  printPtr(os, *params->pQueue);
  os << ", ";
  os << ".PropName = ";
  os << *params->pPropName;
  os << ", ";
  os << ".PropSize = ";
  os << *params->pPropSize;
  os << ", ";
  os << ".PropValue = ";
  printTagged(os, *params->pPropValue, *params->pPropName, *params->pPropSize);
  return os;
}

inline llvm::raw_ostream &operator<<(llvm::raw_ostream &os, const struct ol_get_queue_info_size_params_t *params) {
  os << ".Queue = ";
  printPtr(os, *params->pQueue);
  os << ", ";
  os << ".PropName = ";
  os << *params->pPropName;
  os << ", ";
  os << ".PropSizeRet = ";
  printPtr(os, *params->pPropSizeRet);
  return os;
}

inline llvm::raw_ostream &operator<<(llvm::raw_ostream &os, const struct ol_get_symbol_params_t *params) {
  os << ".Program = ";
  printPtr(os, *params->pProgram);
  os << ", ";
  os << ".Name = ";
  printPtr(os, *params->pName);
  os << ", ";
  os << ".Kind = ";
  os << *params->pKind;
  os << ", ";
  os << ".Symbol = ";
  printPtr(os, *params->pSymbol);
  return os;
}

inline llvm::raw_ostream &operator<<(llvm::raw_ostream &os, const struct ol_get_symbol_info_params_t *params) {
  os << ".Symbol = ";
  printPtr(os, *params->pSymbol);
  os << ", ";
  os << ".PropName = ";
  os << *params->pPropName;
  os << ", ";
  os << ".PropSize = ";
  os << *params->pPropSize;
  os << ", ";
  os << ".PropValue = ";
  printTagged(os, *params->pPropValue, *params->pPropName, *params->pPropSize);
  return os;
}

inline llvm::raw_ostream &operator<<(llvm::raw_ostream &os, const struct ol_get_symbol_info_size_params_t *params) {
  os << ".Symbol = ";
  printPtr(os, *params->pSymbol);
  os << ", ";
  os << ".PropName = ";
  os << *params->pPropName;
  os << ", ";
  os << ".PropSizeRet = ";
  printPtr(os, *params->pPropSizeRet);
  return os;
}

inline llvm::raw_ostream &operator<<(llvm::raw_ostream &os, const struct ol_is_valid_binary_params_t *params) {
  os << ".Device = ";
  printPtr(os, *params->pDevice);
  os << ", ";
  os << ".ProgData = ";
  printPtr(os, *params->pProgData);
  os << ", ";
  os << ".ProgDataSize = ";
  os << *params->pProgDataSize;
  os << ", ";
  os << ".Valid = ";
  printPtr(os, *params->pValid);
  return os;
}

inline llvm::raw_ostream &operator<<(llvm::raw_ostream &os, const struct ol_iterate_devices_params_t *params) {
  os << ".Callback = ";
  os << reinterpret_cast<void*>(*params->pCallback);
  os << ", ";
  os << ".UserData = ";
  printPtr(os, *params->pUserData);
  return os;
}

inline llvm::raw_ostream &operator<<(llvm::raw_ostream &os, const struct ol_launch_host_function_params_t *params) {
  os << ".Queue = ";
  printPtr(os, *params->pQueue);
  os << ", ";
  os << ".Callback = ";
  os << reinterpret_cast<void*>(*params->pCallback);
  os << ", ";
  os << ".UserData = ";
  printPtr(os, *params->pUserData);
  return os;
}

inline llvm::raw_ostream &operator<<(llvm::raw_ostream &os, const struct ol_launch_kernel_params_t *params) {
  os << ".Queue = ";
  printPtr(os, *params->pQueue);
  os << ", ";
  os << ".Device = ";
  printPtr(os, *params->pDevice);
  os << ", ";
  os << ".Kernel = ";
  printPtr(os, *params->pKernel);
  os << ", ";
  os << ".ArgumentsData = ";
  printPtr(os, *params->pArgumentsData);
  os << ", ";
  os << ".ArgumentsSize = ";
  os << *params->pArgumentsSize;
  os << ", ";
  os << ".LaunchSizeArgs = ";
  printPtr(os, *params->pLaunchSizeArgs);
  return os;
}

inline llvm::raw_ostream &operator<<(llvm::raw_ostream &os, const struct ol_mem_alloc_params_t *params) {
  os << ".Device = ";
  printPtr(os, *params->pDevice);
  os << ", ";
  os << ".Type = ";
  os << *params->pType;
  os << ", ";
  os << ".Size = ";
  os << *params->pSize;
  os << ", ";
  os << ".AllocationOut = ";
  printPtr(os, *params->pAllocationOut);
  return os;
}

inline llvm::raw_ostream &operator<<(llvm::raw_ostream &os, const struct ol_mem_fill_params_t *params) {
  os << ".Queue = ";
  printPtr(os, *params->pQueue);
  os << ", ";
  os << ".Ptr = ";
  printPtr(os, *params->pPtr);
  os << ", ";
  os << ".PatternSize = ";
  os << *params->pPatternSize;
  os << ", ";
  os << ".PatternPtr = ";
  printPtr(os, *params->pPatternPtr);
  os << ", ";
  os << ".FillSize = ";
  os << *params->pFillSize;
  return os;
}

inline llvm::raw_ostream &operator<<(llvm::raw_ostream &os, const struct ol_mem_free_params_t *params) {
  os << ".Address = ";
  printPtr(os, *params->pAddress);
  return os;
}

inline llvm::raw_ostream &operator<<(llvm::raw_ostream &os, const struct ol_memcpy_params_t *params) {
  os << ".Queue = ";
  printPtr(os, *params->pQueue);
  os << ", ";
  os << ".DstPtr = ";
  printPtr(os, *params->pDstPtr);
  os << ", ";
  os << ".DstDevice = ";
  printPtr(os, *params->pDstDevice);
  os << ", ";
  os << ".SrcPtr = ";
  printPtr(os, *params->pSrcPtr);
  os << ", ";
  os << ".SrcDevice = ";
  printPtr(os, *params->pSrcDevice);
  os << ", ";
  os << ".Size = ";
  os << *params->pSize;
  return os;
}

inline llvm::raw_ostream &operator<<(llvm::raw_ostream &os, const struct ol_sync_event_params_t *params) {
  os << ".Event = ";
  printPtr(os, *params->pEvent);
  return os;
}

inline llvm::raw_ostream &operator<<(llvm::raw_ostream &os, const struct ol_sync_queue_params_t *params) {
  os << ".Queue = ";
  printPtr(os, *params->pQueue);
  return os;
}

inline llvm::raw_ostream &operator<<(llvm::raw_ostream &os, const struct ol_wait_events_params_t *params) {
  os << ".Queue = ";
  printPtr(os, *params->pQueue);
  os << ", ";
  os << ".Events = ";
  printPtr(os, *params->pEvents);
  os << ", ";
  os << ".NumEvents = ";
  os << *params->pNumEvents;
  return os;
}

///////////////////////////////////////////////////////////////////////////////
// @brief Print pointer value
template <typename T> inline ol_result_t printPtr(llvm::raw_ostream &os, const T *ptr) {
    if (ptr == nullptr) {
        os << "nullptr";
    } else if constexpr (std::is_pointer_v<T>) {
        os << (const void *)(ptr) << " (";
        printPtr(os, *ptr);
        os << ")";
    } else if constexpr (std::is_void_v<T> || is_handle_v<T *>) {
        os << (const void *)ptr;
    } else if constexpr (std::is_same_v<std::remove_cv_t< T >, char>) {
        os << (const void *)(ptr) << " (";
        os << ptr;
        os << ")";
    } else {
        os << (const void *)(ptr) << " (";
        os << *ptr;
        os << ")";
    }

    return OL_SUCCESS;
}
  