* Copyright (c) 2026 Huawei Technologies Co., Ltd.
* This program is free software, you can redistribute it and/or modify it under the terms and conditions of
* CANN Open Software License Agreement Version 2.0 (the "License").
* Please refer to the License for details. You may not use this file except in compliance with the License.
* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED,
* INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY, OR FITNESS FOR A PARTICULAR PURPOSE.
* See LICENSE in the root of the software repository for the full text of the License.
*/
* \file asc_simd_printf_impl.h
* \brief
*/
#ifndef IMPL_UTILS_DEBUG_ASC_SIMD_PRINTF_IMPL_H
#define IMPL_UTILS_DEBUG_ASC_SIMD_PRINTF_IMPL_H
#include "impl/utils/sys_macros.h"
#ifndef ASCENDC_CPU_DEBUG
#include "impl/utils/debug/asc_debug_utils.h"
#include "impl/utils/debug/npu_arch_3510/asc_type_conversion_utils.h"
namespace __asc_simd_vf {
template <typename T>
__simd_callee__ inline void set_scalar_param_vf_impl(__ubuf__ uint8_t* param_addr, uint32_t param_idx, T scalar)
{
__ubuf__ uint64_t* scalar_addr = (__ubuf__ uint64_t*)param_addr + param_idx;
*scalar_addr = 0;
if constexpr (is_same_in_list<T, half, float>()) {
*((__ubuf__ float*)scalar_addr) = static_cast<float>(scalar);
} else if constexpr (is_same_in_list<T, double>()) {
*((__ubuf__ double*)scalar_addr) = static_cast<double>(scalar);
} else if constexpr (std::is_signed<T>::value) {
*((__ubuf__ int64_t*)scalar_addr) = static_cast<int64_t>(scalar);
} else if constexpr (std::is_unsigned<T>::value) {
*((__ubuf__ uint64_t*)scalar_addr) = static_cast<uint64_t>(scalar);
} else if constexpr (is_same_in_list<T, bfloat16_t, float8_e5m2_t, float8_e8m0_t, float8_e4m3_t, hifloat8_t>()) {
*((__ubuf__ float*)scalar_addr) = to_float(scalar);
} else if constexpr (std::is_pointer<T>::value) {
*((__ubuf__ uint64_t*)scalar_addr) = (uintptr_t)scalar;
} else if constexpr (std::is_enum<T>::value) {
*((__ubuf__ uint64_t*)scalar_addr) = static_cast<uint64_t>(scalar);
}
}
__simd_callee__ constexpr uint32_t align_print_tlv_len(const uint32_t data_len)
{
constexpr uint32_t align_bytes = 8;
return ((data_len + (align_bytes - 1)) & ~(align_bytes - 1)) + align_bytes;
}
template <typename T>
__simd_callee__ inline void set_scalar_param_vf(__ubuf__ uint8_t* param_addr, uint32_t param_idx, T scalar)
{
set_scalar_param_vf_impl(param_addr, param_idx, scalar);
}
__simd_callee__ inline void set_string_param_vf(
__ubuf__ uint8_t* param_addr, uint32_t param_idx, __ubuf__ const char* s, uint32_t& offset)
{
__ubuf__ uint64_t* string_addr = reinterpret_cast<__ubuf__ uint64_t*>(param_addr) + param_idx;
__ubuf__ uint8_t* dst_str_addr = param_addr + offset;
*string_addr = static_cast<uint64_t>(offset - sizeof(uint64_t) * param_idx);
uint32_t str_len = get_cstring_len_vf(s);
for (uint32_t i = 0; i < str_len; i++) {
*(dst_str_addr + i) = *(s + i);
}
offset += str_len;
}
__simd_callee__ inline void set_param_vf(__ubuf__ uint8_t* param_addr, uint32_t param_idx, uint32_t& offset)
{
(void)param_addr;
(void)param_idx;
(void)offset;
return;
}
template <typename... Args>
__simd_callee__ inline void set_param_vf(
__ubuf__ uint8_t* param_addr, uint32_t param_idx, uint32_t& offset, Args&&... args);
template <typename... Args>
__simd_callee__ inline void set_param_vf_impl(
__ubuf__ uint8_t* param_addr, uint32_t param_idx, uint32_t& offset, __ubuf__ const char* s, Args&&... args)
{
set_string_param_vf(param_addr, param_idx, s, offset);
set_param_vf(param_addr, param_idx + 1, offset, args...);
}
template <typename T, typename... Args>
__simd_callee__ inline void set_param_vf_impl(
__ubuf__ uint8_t* param_addr, uint32_t param_idx, uint32_t& offset, T scalar, Args&&... args)
{
set_scalar_param_vf(param_addr, param_idx, scalar);
set_param_vf(param_addr, param_idx + 1, offset, args...);
}
template <typename... Args>
__simd_callee__ inline void set_param_vf(
__ubuf__ uint8_t* param_addr, uint32_t param_idx, uint32_t& offset, Args&&... args)
{
set_param_vf_impl(param_addr, param_idx, offset, args...);
}
__simd_callee__ inline uint32_t get_args_len_vf(uint32_t& args_num)
{
(void)args_num;
return 0;
}
template <typename... Args>
__simd_callee__ inline uint32_t get_args_len_vf(uint32_t& args_num, Args&&... args);
template <typename... Args>
__simd_callee__ inline uint32_t get_args_len_vf_impl(uint32_t& args_num, __ubuf__ const char* s, Args&&... args)
{
constexpr uint32_t param_size = sizeof(uint64_t);
const uint32_t str_len = get_cstring_len_vf(s);
args_num += 1;
return param_size + str_len + get_args_len_vf(args_num, args...);
}
template <typename T, typename... Args>
__simd_callee__ inline uint32_t get_args_len_vf_impl(uint32_t& args_num, T scalar, Args&&... args)
{
constexpr uint32_t param_size = sizeof(uint64_t);
args_num += 1;
return param_size + get_args_len_vf(args_num, args...);
}
template <typename... Args>
__simd_callee__ inline uint32_t get_args_len_vf(uint32_t& args_num, Args&&... args)
{
return get_args_len_vf_impl(args_num, args...);
}
template <typename... Args>
__simd_callee__ inline uint32_t get_print_tlv_len_simd(
uint32_t& args_num, __ubuf__ const char* fmt, __ubuf__ const char* dump_head, Args&&... args)
{
constexpr uint32_t print_info_len = sizeof(PrintTlv);
const uint32_t args_len = get_args_len_vf(args_num, args...);
const uint32_t fmt_len = get_cstring_len_vf(fmt);
const uint32_t dump_head_len = get_cstring_len_vf(dump_head) - 1;
return align_print_tlv_len(print_info_len + args_len + fmt_len + dump_head_len);
}
__simd_callee__ inline void set_print_tlv_info_vf(
DumpType debug_type, __ubuf__ PrintTlv* print_tlv, const uint32_t& tlv_len, const uint32_t& args_num,
uint16_t block_idx)
{
print_tlv->type = static_cast<uint32_t>(debug_type);
print_tlv->length = tlv_len - sizeof(uint32_t[2]);
print_tlv->blockIdx = block_idx;
print_tlv->resv = static_cast<uint32_t>(0U);
print_tlv->fmtOffset = (args_num + 1) * sizeof(uint64_t);
}
__simd_callee__ inline void copy_fmt_to_ubuf(__ubuf__ uint8_t* dst, __ubuf__ const char* src, uint32_t len)
{
for (uint32_t i = 0; i < len; i += 2) {
dst[i] = src[i];
dst[i + 1] = src[i + 1];
}
}
template <typename... Args>
__simd_callee__ inline void set_print_tlv_data_vf(
__ubuf__ PrintTlv* print_tlv, __ubuf__ const char* fmt, __ubuf__ const char* dump_head, Args&&... args)
{
const uint32_t dump_head_len = get_cstring_len_vf(dump_head) - 1;
const uint32_t fmt_len = get_cstring_len_vf(fmt);
__ubuf__ uint8_t* param_addr = reinterpret_cast<__ubuf__ uint8_t*>(print_tlv + 1);
__ubuf__ uint8_t* dump_head_addr = param_addr + print_tlv->fmtOffset - sizeof(uint64_t);
__ubuf__ uint8_t* fmt_addr = dump_head_addr + dump_head_len;
copy_fmt_to_ubuf(dump_head_addr, dump_head, dump_head_len);
copy_fmt_to_ubuf(fmt_addr, fmt, fmt_len);
uint32_t str_param_offset = print_tlv->fmtOffset + dump_head_len + fmt_len;
set_param_vf(param_addr, 0, str_param_offset, args...);
}
template <class... Args>
__simd_callee__ inline void scalar_printf_impl(
DumpType debug_type, __ubuf__ const char* fmt, __ubuf__ const char* dump_head, Args&&... args)
{
__ubuf__ BlockVFBufInfo* block_info = get_printf_ubuf_addr(0);
if (block_info->flag != 0) {
return;
}
uint32_t args_num = 0;
const uint32_t tlv_len = get_print_tlv_len_simd(args_num, fmt, dump_head, args...);
uint32_t write_len = block_info->writeLen;
if (tlv_len > block_info->length || write_len > block_info->length) {
block_info->flag = 1;
return;
}
if (write_len + tlv_len > block_info->length) {
wait_vf_debug_buffer_drained_and_reset(block_info);
write_len = 0;
}
if (!reserve_debug_tlv(block_info, tlv_len)) {
return;
}
__ubuf__ PrintTlv* print_tlv =
reinterpret_cast<__ubuf__ PrintTlv*>((__ubuf__ uint8_t*)(block_info->buffer) + write_len);
set_print_tlv_info_vf(debug_type, print_tlv, tlv_len, args_num, block_info->blockIdx);
set_print_tlv_data_vf(print_tlv, fmt, dump_head, args...);
block_info->magic = ASCENDC_SIMD_VF_MAGIC_NUMBER;
block_info->writeLen = write_len + tlv_len;
}
template <class... Args>
__simd_callee__ inline void printf_impl(__ubuf__ const char* fmt, Args&&... args)
{
#if !(defined(ASCENDC_DUMP) && ASCENDC_DUMP == 0)
enable_asc_diagnostics();
scalar_printf_impl(DumpType::DUMP_SCALAR, fmt, "", args...);
#endif
}
template <class... Args>
__simd_callee__ inline void printf_impl_assert(__ubuf__ const char* fmt, Args&&... args)
{
#if !(defined(ASCENDC_DUMP) && ASCENDC_DUMP == 0)
enable_asc_assert();
scalar_printf_impl(DumpType::DUMP_ASSERT, fmt, "", args...);
#endif
}
template <class... Args>
__simd_callee__ inline void printf_impl_assert_msg(
__ubuf__ const char* assertion, __ubuf__ const char* file, unsigned int line, __ubuf__ const char* function,
__ubuf__ const char* fmt, Args&&... args)
{
#if !(defined(ASCENDC_DUMP) && ASCENDC_DUMP == 0)
enable_asc_assert();
scalar_printf_impl(
DumpType::DUMP_ASSERT, fmt, "[ASSERT] %s:%u: %s: Assertion '%s' failed. ", file, line, function, assertion,
args...);
#endif
}
template <class... Args>
__ASC_USE_RESERVED_UBUF__(3510, "printf is forbidden when compile option --cce-disable-asc-reserved-ubuf is enabled")
__simd_callee__ inline void printf(__ubuf__ const char* fmt, Args&&... args)
{
printf_impl(fmt, args...);
}
}
#else
#include <cstdio>
namespace __asc_simd_vf {
template <class... Args>
__simd_callee__ inline void printf_impl(__ubuf__ const char* fmt, Args&&... args)
{
#if !(defined(ASCENDC_DUMP) && ASCENDC_DUMP == 0)
std::printf(fmt, args...);
#endif
}
template <class... Args>
__simd_callee__ inline void printf(__ubuf__ const char* fmt, Args&&... args)
{
printf_impl(fmt, args...);
}
}
#endif
#endif