Remove custom printf from kelvin.h - Remove our custom printf from kelvin.h, in favor of libc printf everywhere. This allows us to get formatting for many more types! - Patch up format strings to fix warnings. - Add a "PrintfTraits" template type, that contains decimal and hex format strings for the parametrized type (mostly used to build format strings in templated tests). Change-Id: I36bd2841406e8f2b33c193637c468a2ff1b41a16
diff --git a/crt/BUILD b/crt/BUILD index 8689baf..58860a6 100644 --- a/crt/BUILD +++ b/crt/BUILD
@@ -35,5 +35,6 @@ hdrs = [ "kelvin.h", "kelvin_intrinsics.h", + "printf_traits.h", ], )
diff --git a/crt/kelvin.h b/crt/kelvin.h index cbf5578..cd7be88 100644 --- a/crt/kelvin.h +++ b/crt/kelvin.h
@@ -41,42 +41,4 @@ #define vm14 v56 #define vm15 v60 -// Stop printing the string when \0 is found in the word. -static inline bool WordHasZero(uint32_t data) { - return (((data >> 24) & 0xff) == 0) || (((data >> 16) & 0xff) == 0) || - (((data >> 8) & 0xff) == 0) || ((data & 0xff) == 0); -} - -template <typename T> -static inline void PrintArg(const T arg) { - if (std::is_same<T, const uint8_t *>::value || - std::is_same<T, const char *>::value) { - klog(arg); - } else if (std::is_same<T, uint8_t *>::value || - std::is_same<T, char *>::value) { - const uint32_t *p_str = reinterpret_cast<const uint32_t *>(arg); - uint32_t data = 0; - do { - data = *p_str; - p_str++; - clog(data); - } while (!WordHasZero(data)); - } else { // scalar argument. - slog(arg); - } -} - -// General printf helper function. The c++11 pack expansion + braced-init-list -// is used to support arbitrary variadic template. -// The unused list is initialized by expanding the arguments in order, and then -// processed by `PrintArg`. -template <typename... Types> -static inline void printf(const char *format, Types... args) { - constexpr auto size = sizeof...(args); - if (size > 0) { - __attribute__((unused)) int x[] = {0, ((void)PrintArg(args), 0)...}; - } - flog(format); -} - #endif // CRT_KELVIN_H_
diff --git a/crt/kelvin_gloss.cc b/crt/kelvin_gloss.cc index f8e608d..19308d8 100644 --- a/crt/kelvin_gloss.cc +++ b/crt/kelvin_gloss.cc
@@ -13,12 +13,14 @@ // limitations under the License. // // Syscall stubs for newlib on Kelvin -#include <errno.h> -#include <stdint.h> -#include <stdlib.h> #include <sys/stat.h> #include <unistd.h> +#include <cerrno> +#include <cstdint> +#include <cstdio> +#include <cstdlib> + #include "crt/kelvin.h" void* __dso_handle = reinterpret_cast<void*>(&__dso_handle); @@ -93,7 +95,7 @@ _write_line_buffer[len] = '\0'; } if ((_write_line_buffer[len] == '\0')) { - printf("%s", _write_line_buffer); + flog(_write_line_buffer); len = 0; } _write_line_buffer_len = len;
diff --git a/crt/printf_traits.h b/crt/printf_traits.h new file mode 100644 index 0000000..c7a6f1b --- /dev/null +++ b/crt/printf_traits.h
@@ -0,0 +1,53 @@ +// Copyright 2023 Google LLC +// Licensed under the Apache License, Version 2.0, see LICENSE for details. +// SPDX-License-Identifier: Apache-2.0 + +#ifndef CRT_PRINTF_TRAITS_H_ +#define CRT_PRINTF_TRAITS_H_ + +#include <cstdint> + +// Intentionally left empty, so that +// types without an implementation will cause +// a compile failure. +template <typename T> +struct PrintfTraits { +}; + +template <> +struct PrintfTraits<int8_t> { + static constexpr const char* kFmt = "%d"; + static constexpr const char* kFmtHex = "0x%hhx"; +}; + +template <> +struct PrintfTraits<int16_t> { + static constexpr const char* kFmt = "%hd"; + static constexpr const char* kFmtHex = "0x%hx"; +}; + +template <> +struct PrintfTraits<int32_t> { + static constexpr const char* kFmt = "%ld"; + static constexpr const char* kFmtHex = "0x%lx"; +}; + +template <> +struct PrintfTraits<uint8_t> { + static constexpr const char* kFmt = "%u"; + static constexpr const char* kFmtHex = "0x%hhx"; +}; + +template <> +struct PrintfTraits<uint16_t> { + static constexpr const char* kFmt = "%hu"; + static constexpr const char* kFmtHex = "0x%hx"; +}; + +template <> +struct PrintfTraits<uint32_t> { + static constexpr const char* kFmt = "%lu"; + static constexpr const char* kFmtHex = "0x%lx"; +}; + +#endif // CRT_PRINTF_TRAITS_H_
diff --git a/tests/cv/diff_test.cc b/tests/cv/diff_test.cc index 20d289e..cd20a77 100644 --- a/tests/cv/diff_test.cc +++ b/tests/cv/diff_test.cc
@@ -5,6 +5,7 @@ #include "tests/cv/diff.h" #include <cstdint> +#include <cstdio> #include "crt/kelvin.h" #include "tests/cv/test_helper.h"
diff --git a/tests/cv/downsample_test.cc b/tests/cv/downsample_test.cc index a1afa0b..f82a1cc 100644 --- a/tests/cv/downsample_test.cc +++ b/tests/cv/downsample_test.cc
@@ -6,6 +6,7 @@ #include "tests/cv/downsample.h" #include <cstdint> +#include <cstdio> #include "crt/kelvin.h" #include "tests/cv/test_helper.h"
diff --git a/tests/cv/extrema_test.cc b/tests/cv/extrema_test.cc index 81f0163..e6ff969 100644 --- a/tests/cv/extrema_test.cc +++ b/tests/cv/extrema_test.cc
@@ -5,6 +5,7 @@ #include "tests/cv/extrema.h" #include <cstdint> +#include <cstdio> #include "crt/kelvin.h" #include "tests/cv/test_helper.h"
diff --git a/tests/cv/gaussian.cc b/tests/cv/gaussian.cc index 520cfe8..f280746 100644 --- a/tests/cv/gaussian.cc +++ b/tests/cv/gaussian.cc
@@ -4,6 +4,8 @@ #include "tests/cv/gaussian.h" +#include <cstdio> + #include "crt/kelvin.h" // Note: separable kernel is vertical then horizontal. H then V with the
diff --git a/tests/cv/gaussian_test.cc b/tests/cv/gaussian_test.cc index e310b3e..cf6f3c4 100644 --- a/tests/cv/gaussian_test.cc +++ b/tests/cv/gaussian_test.cc
@@ -6,6 +6,7 @@ #include <algorithm> #include <cstdint> +#include <cstdio> #include "crt/kelvin.h" #include "tests/cv/test_helper.h"
diff --git a/tests/cv/shift_gaussian.cc b/tests/cv/shift_gaussian.cc index be5aa93..95f96f3 100644 --- a/tests/cv/shift_gaussian.cc +++ b/tests/cv/shift_gaussian.cc
@@ -5,6 +5,7 @@ #include "tests/cv/shift_gaussian.h" #include <cstdint> +#include <cstdio> #include "crt/kelvin.h"
diff --git a/tests/cv/shift_gaussian_test.cc b/tests/cv/shift_gaussian_test.cc index 813e50b..3ef8f2e 100644 --- a/tests/cv/shift_gaussian_test.cc +++ b/tests/cv/shift_gaussian_test.cc
@@ -6,6 +6,7 @@ #include <algorithm> #include <cstdint> +#include <cstdio> #include "crt/kelvin.h" #include "tests/cv/test_helper.h"
diff --git a/tests/cv/upsample_test.cc b/tests/cv/upsample_test.cc index c672575..fc8b628 100644 --- a/tests/cv/upsample_test.cc +++ b/tests/cv/upsample_test.cc
@@ -6,6 +6,7 @@ #include <algorithm> #include <cstdint> +#include <cstdio> #include "crt/kelvin.h" #include "tests/cv/test_helper.h"
diff --git a/tests/kelvin_isa/getvl_test.cc b/tests/kelvin_isa/getvl_test.cc index 8d547a1..dea0e75 100644 --- a/tests/kelvin_isa/getvl_test.cc +++ b/tests/kelvin_isa/getvl_test.cc
@@ -3,6 +3,8 @@ // SPDX-License-Identifier: Apache-2.0 // +#include <cstdio> + #include "tests/kelvin_isa/kelvin_test.h" // clang-format off
diff --git a/tests/kelvin_isa/vdwconv.cc b/tests/kelvin_isa/vdwconv.cc index 12e4f8e..ff941a1 100644 --- a/tests/kelvin_isa/vdwconv.cc +++ b/tests/kelvin_isa/vdwconv.cc
@@ -2,11 +2,11 @@ // Licensed under the Apache License, Version 2.0, see LICENSE for details. // SPDX-License-Identifier: Apache-2.0 -#include "tests/kelvin_isa/vdwconv_data.h" - -#include <string.h> +#include <cstdio> +#include <cstring> #include "tests/kelvin_isa/kelvin_test.h" +#include "tests/kelvin_isa/vdwconv_data.h" struct vdwconv_u8_t { uint32_t mode:2; // 1:0 @@ -35,7 +35,7 @@ #endif // TEST_GEN void dwconv(const vdwconv_u8_t& cmd, const uint8_t ina[3][kZlen], - const uint8_t inb[3][kZlen], uint32_t ref[4][kZlen / 4], + const uint8_t inb[3][kZlen], const uint32_t ref[4][kZlen / 4], uint32_t dut[4][kZlen / 4]) { uint32_t cmdw; memcpy(&cmdw, &cmd, 4); @@ -208,7 +208,7 @@ printf("{ "); for (int i = 0; i < 4; ++i) { for (int j = 0; j < kZlen / 4; ++j) { - printf("0x%08x, ", ref[i][j]); + printf("0x%lx, ", ref[i][j]); } } printf("} },\n"); @@ -222,7 +222,7 @@ printf("**error::test_dwconv(%d,%d)(%d,%d,%d,%d)[%d,%d] ", cmd.sparsity, cmd.regbase, cmd.sdata1, cmd.sdata2, cmd.sbias1, cmd.sbias2, i, j); - printf("%08x %08x\n", r, d); + printf("0x%lx 0x%lx\n", r, d); exit(-1); } } @@ -285,14 +285,14 @@ for (int i = 0; i < 4; ++i) { if (ref[i] != dut[i]) { - printf("**error::test_dwconv<%d,%d>[%d] %08x %08x\n", step, use_accum, i, - ref[i], dut[i]); + printf("**error::test_dwconv<%d,%d>[%d] 0x%lx 0x%lx\n", step, use_accum, + i, ref[i], dut[i]); exit(-1); } } } -void test_vdwconv(int sparsity, int regbase, test_dwconv_t& test) { +void test_vdwconv(int sparsity, int regbase, const test_dwconv_t& test) { uint32_t dut[4][kZlen / 4]; vdwconv_u8_t cmd; @@ -309,10 +309,10 @@ int main() { #ifdef TEST_GEN - uint32_t* pw_ina = (uint32_t*)ina_; - uint32_t* pw_inb = (uint32_t*)inb_; - uint8_t* pb_ina = (uint8_t*)ina_; - uint8_t* pb_inb = (uint8_t*)inb_; + uint32_t* pw_ina = reinterpret_cast<uint32_t*>(ina_); + uint32_t* pw_inb = reinterpret_cast<uint32_t*>(inb_); + uint8_t* pb_ina = reinterpret_cast<uint8_t*>(ina_); + uint8_t* pb_inb = reinterpret_cast<uint8_t*>(inb_); for (int i = 0; i < 3 * kZlen / 4; ++i) { pw_ina[i] = krand(); pw_inb[i] = krand();
diff --git a/tests/kelvin_isa/vld.cc b/tests/kelvin_isa/vld.cc index 0400921..0d8d5a3 100644 --- a/tests/kelvin_isa/vld.cc +++ b/tests/kelvin_isa/vld.cc
@@ -1,3 +1,10 @@ +// Copyright 2023 Google LLC +// Licensed under the Apache License, Version 2.0, see LICENSE for details. +// SPDX-License-Identifier: Apache-2.0 + +#include <cstdio> + +#include "crt/printf_traits.h" #include "tests/kelvin_isa/kelvin_test.h" inline uint8_t* vldp_data(uint8_t* data) { @@ -206,8 +213,8 @@ void* target = reinterpret_cast<void*>(read_data + offset); if (reinterpret_cast<void*>(dut) != target) { printf("Failed test_ldst_x for type %s:\n", TypeString<T>::type_str()); - printf(" expected dut=0x%x to be 0x%x\n", - reinterpret_cast<void*>(dut), target); + printf(" expected dut=%p to be %p\n", reinterpret_cast<void*>(dut), + target); exit(1); } @@ -222,7 +229,9 @@ for (int i = 0; i < size; i++) { if (result[i] != static_cast<T>(i)) { printf("Failed test_ldst_x for type %s:\n", TypeString<T>::type_str()); - printf(" expected %d at position %d/%d got %d\n", i, i, size, result[i]); + printf(" expected %d at position %d/%d got ", i, i, size); + printf(PrintfTraits<T>::kFmt, result[i]); + printf("\n"); exit(1); } } @@ -247,8 +256,8 @@ void* target = reinterpret_cast<void*>(read_data + (length * sizeof(T))); if (reinterpret_cast<void*>(dut) != target) { printf("Failed test_ldst_p_xx for type %s:\n", TypeString<T>::type_str()); - printf(" expected dut=%x to be %x\n", - reinterpret_cast<void*>(dut), target); + printf(" expected dut=%p to be %p\n", reinterpret_cast<void*>(dut), + target); exit(1); } @@ -263,7 +272,9 @@ for (int i = 0; i < size; i++) { if (result[i] != static_cast<T>(i)) { printf("Failed test_ldst_p_xx for type %s:\n", TypeString<T>::type_str()); - printf(" expected %d at position %d got %d\n", i, i, result[i]); + printf(" expected %d at position %d got ", i, i); + printf(PrintfTraits<T>::kFmt, result[i]); + printf("\n"); exit(1); } } @@ -299,8 +310,8 @@ (post_increment ? length * sizeof(T) : 0)); if (reinterpret_cast<void*>(dut) != target) { printf("Failed test_ldst_l_xx for type %s:\n", TypeString<T>::type_str()); - printf(" expected dut=%x to be %x\n", - reinterpret_cast<void*>(dut), target); + printf(" expected dut=%p to be %p\n", reinterpret_cast<void*>(dut), + target); exit(1); } @@ -316,14 +327,18 @@ for (; i < length; i++) { if (result[i] != static_cast<T>(i)) { printf("Failed test_ldst_l_xx for type %s:\n", TypeString<T>::type_str()); - printf(" expected %d at position %d/%d got %d\n", i, i, size, result[i]); + printf(" expected %d at position %d/%d got ", i, i, size); + printf(PrintfTraits<T>::kFmt, result[i]); + printf("\n"); exit(1); } } for (; i < size; i++) { if (result[i] != 0) { printf("Failed test_ldst_l_xx for type %s:\n", TypeString<T>::type_str()); - printf(" expected 0 at position %d/%d got %d\n", i, size, result[i]); + printf(" expected 0 at position %d/%d got ", i, size); + printf(PrintfTraits<T>::kFmt, result[i]); + printf("\n"); exit(1); } } @@ -359,8 +374,8 @@ void* target = reinterpret_cast<void*>(read_data + offset); if (reinterpret_cast<void*>(dut) != target) { printf("Failed test_ldst_s_xx for type %s:\n", TypeString<T>::type_str()); - printf(" expected dut=%x to be %x\n", - reinterpret_cast<void*>(dut), target); + printf(" expected dut=%p to be %p\n", reinterpret_cast<void*>(dut), + target); exit(1); } @@ -381,8 +396,11 @@ if (result_vector[i] != start_value + i) { printf("Failed test_ldst_s_xx for type %s:\n", TypeString<T>::type_str()); - printf(" expected %d at position %d got %d\n", - expected_value, i, result_vector[i]); + printf(" expected "); + printf(PrintfTraits<T>::kFmt, expected_value); + printf(" at position %ld got ", i); + printf(PrintfTraits<T>::kFmt, result_vector[i]); + printf("\n"); exit(1); } } @@ -408,8 +426,8 @@ void* target = reinterpret_cast<void*>(read_data + VLENB); if (reinterpret_cast<void*>(dut) != target) { printf("Failed test_ldst_tp_xx for type %s:\n", TypeString<T>::type_str()); - printf(" expected dut=%x to be %x\n", - reinterpret_cast<void*>(dut), target); + printf(" expected dut=%p to be %p\n", reinterpret_cast<void*>(dut), + target); exit(1); } @@ -430,8 +448,11 @@ if (result[i] != expected_value) { printf("Failed test_ldst_tp_xx for type %s:\n", TypeString<T>::type_str()); - printf(" expected %d at position %d got %d\n", - expected_value, i, result[i]); + printf(" expected "); + printf(PrintfTraits<T>::kFmt, expected_value); + printf(" at position %d got ", i); + printf(PrintfTraits<T>::kFmt, result[i]); + printf("\n"); exit(1); } } @@ -440,7 +461,9 @@ if (result[i] != 0) { printf("Failed test_ldst_tp_xx for type %s:\n", TypeString<T>::type_str()); - printf(" expected 0 at position %d got %d\n", i, result[i]); + printf(" expected 0 at position %d got ", i); + printf(PrintfTraits<T>::kFmt, result[i]); + printf("\n"); exit(1); } } @@ -474,7 +497,11 @@ for (int j = 0; j < vlen; ++j) { T ref = j < i ? j + 1 : 0; if (ref != dut[j]) { - printf("**error vld_l[%d,%d] %x %x\n", i, j, ref, dut[j]); + printf("**error vld_l[%d,%d] ", i, j); + printf(PrintfTraits<T>::kFmtHex, ref); + printf(" "); + printf(PrintfTraits<T>::kFmtHex, dut[j]); + printf("\n"); exit(-1); } }
diff --git a/tests/kelvin_isa/vpadd.cc b/tests/kelvin_isa/vpadd.cc index 4a856d0..d7bc2ed 100644 --- a/tests/kelvin_isa/vpadd.cc +++ b/tests/kelvin_isa/vpadd.cc
@@ -1,5 +1,8 @@ // Copyright 2023 Google LLC +#include <cstdio> + +#include "crt/printf_traits.h" #include "tests/kelvin_isa/kelvin_test.h" #define vpadd_v(T, Vd, Vs) \ @@ -58,8 +61,16 @@ for (int i = 0; i < lanes; ++i) { if (ref[i] != dut[i]) { - printf("**error vpadd_v[%d] %d %d\n", i, ref[i], dut[i]); - printf(" inputs: %d, %d\n", inp[2 * i + 0], inp[2 * i + 1]); + printf("**error vpadd_v[%d] ", i); + printf(PrintfTraits<T2>::kFmt, ref[i]); + printf(" "); + printf(PrintfTraits<T2>::kFmt, dut[i]); + printf("\n"); + printf(" inputs: "); + printf(PrintfTraits<T1>::kFmt, inp[2 * i + 0]); + printf(", "); + printf(PrintfTraits<T1>::kFmt, inp[2 * i + 1]); + printf("\n"); exit(-1); } } @@ -89,7 +100,11 @@ for (int i = 0; i < lanes; ++i) { if (ref[i] != dut[i]) { - printf("**error vpadd_v_m[%d] %x %x\n", i, ref[i], dut[i]); + printf("**error vpadd_v_m[%d] ", i); + printf(PrintfTraits<T2>::kFmtHex, ref[i]); + printf(" "); + printf(PrintfTraits<T2>::kFmtHex, dut[i]); + printf("\n"); exit(-1); } }
diff --git a/tests/riscv-tests/branch_div_test.cc b/tests/riscv-tests/branch_div_test.cc index a7a6514..95ba75d 100644 --- a/tests/riscv-tests/branch_div_test.cc +++ b/tests/riscv-tests/branch_div_test.cc
@@ -5,8 +5,9 @@ // Use the routine of finding the integer part of log_3 to stress test // branch/div op combinations. -#include <stdint.h> -#include <stdlib.h> +#include <cstdint> +#include <cstdio> +#include <cstdlib> #include "crt/kelvin.h" @@ -50,18 +51,18 @@ uint32_t uint32_input = rand_uint32_input(); int32_t int32_input = rand_int32_input(); auto uint32_log3 = get_int_log3<uint32_t>(uint32_input); - printf("Unsigned input: %u, integer log3: %u\n", uint32_input, uint32_log3); + printf("Unsigned input: %lu, integer log3: %lu\n", uint32_input, uint32_log3); auto test = int_pow3<uint32_t>(uint32_log3); // Make the check like this to prevent overflow if (!(test <= uint32_input && test >= uint32_input / 3)) { - printf("Invalid log_3 %u for %u\n", uint32_log3, uint32_input); + printf("Invalid log_3 %lu for %lu\n", uint32_log3, uint32_input); exit(-1); } auto int32_log3 = get_int_log3<int32_t>(int32_input); - printf("Signed intput:%d, integer log3: %d\n", int32_input, int32_log3); + printf("Signed intput:%ld, integer log3: %ld\n", int32_input, int32_log3); auto test1 = int_pow3<int32_t>(int32_log3); if (!(test1 <= int32_input && test1 >= int32_input / 3)) { - printf("Invalid log_3 %d for %d\n", int32_log3, int32_input); + printf("Invalid log_3 %ld for %ld\n", int32_log3, int32_input); exit(-1); } return 0;
diff --git a/tests/riscv-tests/branch_modulo_test.cc b/tests/riscv-tests/branch_modulo_test.cc index 8bd7743..faac704 100644 --- a/tests/riscv-tests/branch_modulo_test.cc +++ b/tests/riscv-tests/branch_modulo_test.cc
@@ -5,8 +5,9 @@ // Use greatest common denominator routine to stress test branch/modulo op // combinations. -#include <stdint.h> -#include <stdlib.h> +#include <cstdint> +#include <cstdio> +#include <cstdlib> #include "crt/kelvin.h" @@ -40,26 +41,26 @@ int32_t int32_a = rand_int32_input(); int32_t int32_b = rand_int32_input(); - printf("unsigned numbers: a:%u, b:%u\n", uint32_a, uint32_b); + printf("unsigned numbers: a:%lu, b:%lu\n", uint32_a, uint32_b); auto uint32_gcd = (uint32_a > uint32_b) ? get_gcd<uint32_t>(uint32_a, uint32_b) : get_gcd<uint32_t>(uint32_b, uint32_a); - printf("gcd: %u\n", uint32_gcd); + printf("gcd: %lu\n", uint32_gcd); if (!(uint32_a % uint32_gcd == 0 && uint32_b % uint32_gcd == 0)) { - printf("Invalid common denominator %u for %u and %u\n", uint32_gcd, + printf("Invalid common denominator %lu for %lu and %lu\n", uint32_gcd, uint32_a, uint32_b); exit(-1); } - printf("signed numbers: a:%d, b:%d\n", int32_a, int32_b); + printf("signed numbers: a:%ld, b:%ld\n", int32_a, int32_b); auto int32_gcd = (int32_a > int32_b) ? get_gcd<int32_t>(int32_a, int32_b) : get_gcd<int32_t>(int32_b, int32_a); - printf("gcd: %d\n", int32_gcd); + printf("gcd: %ld\n", int32_gcd); if (!(int32_a % int32_gcd == 0 && int32_b % int32_gcd == 0)) { - printf("Invalid common denominator %d for %d and %d\n", int32_gcd, int32_a, - int32_b); + printf("Invalid common denominator %ld for %ld and %ld\n", int32_gcd, + int32_a, int32_b); exit(-1); }