diff --git a/.gitignore b/.gitignore index 09a73277..1d768138 100644 --- a/.gitignore +++ b/.gitignore @@ -9,6 +9,7 @@ *.o *.a __pycache__ +pve Scratch Proto diff --git a/Source/astcenc_color_unquantize.cpp b/Source/astcenc_color_unquantize.cpp index 70f2deba..8aacee15 100644 --- a/Source/astcenc_color_unquantize.cpp +++ b/Source/astcenc_color_unquantize.cpp @@ -51,14 +51,11 @@ static ASTCENC_SIMD_INLINE vint4 uncontract_color( * * @return The shifted value. */ -static ASTCENC_SIMD_INLINE int32_t safe_signed_lsh(int32_t val, int shift) +static ASTCENC_SIMD_INLINE int safe_signed_lsh(int val, int shift) { - // Future: Can use std:bit_cast with C++20 - uint32_t uval; - std::memcpy(&uval, &val, sizeof(uint32_t)); + unsigned int uval = astc::int_as_uint(val); uval <<= shift; - std::memcpy(&val, &uval, sizeof(uint32_t)); - return val; + return astc::uint_as_int(uval); } void rgba_delta_unpack( diff --git a/Source/astcenc_decompress_symbolic.cpp b/Source/astcenc_decompress_symbolic.cpp index e7791eef..ee7b593a 100644 --- a/Source/astcenc_decompress_symbolic.cpp +++ b/Source/astcenc_decompress_symbolic.cpp @@ -1,6 +1,6 @@ // SPDX-License-Identifier: Apache-2.0 // ---------------------------------------------------------------------------- -// Copyright 2011-2024 Arm Limited +// Copyright 2011-2025 Arm Limited // // Licensed under the Apache License, Version 2.0 (the "License"); you may not // use this file except in compliance with the License. You may obtain a copy @@ -163,9 +163,7 @@ void unpack_weights( */ static float error_color_nan() { - if32 v; - v.u = 0xFFFFE000U; - return v.f; + return astc::uint_as_float(0xFFFFE000u); } /* See header for documentation. */ diff --git a/Source/astcenc_entry.cpp b/Source/astcenc_entry.cpp index 4023797a..a54b2cb6 100644 --- a/Source/astcenc_entry.cpp +++ b/Source/astcenc_entry.cpp @@ -136,19 +136,19 @@ static const std::array preset_configs_low {{ /** * @brief Validate CPU floating point meets assumptions made in the codec. * - * The codec is written with the assumption that a float threaded through the @c if32 union will be - * stored and reloaded as a 32-bit IEEE-754 float with round-to-nearest rounding. This is always the - * case in an IEEE-754 compliant system, however not every system or compilation mode is actually - * IEEE-754 compliant. This normally fails if the code is compiled with fast math enabled. + * The codec is written with the assumption that float bit patterns are valid + * IEEE754 values that are stored and reloaded with round-to-nearest rounding. + * This is always the case in an IEEE-754 compliant system, however not every + * system or compilation mode is actually IEEE-754 compliant. This normally + * fails if the code is compiled with fast math enabled, for example. * - * @return Return @c ASTCENC_SUCCESS if validated, otherwise an error on failure. + * @return Return @c ASTCENC_SUCCESS if validated, an error on failure. */ static astcenc_error validate_cpu_float() { - if32 p; volatile float xprec_testval = 2.51f; - p.f = xprec_testval + 12582912.0f; - float q = p.f - 12582912.0f; + float store = xprec_testval + 12582912.0f; + float q = store - 12582912.0f; if (q != 3.0f) { diff --git a/Source/astcenc_mathlib.h b/Source/astcenc_mathlib.h index 5fd296d6..1b9eb4a6 100644 --- a/Source/astcenc_mathlib.h +++ b/Source/astcenc_mathlib.h @@ -26,6 +26,7 @@ #include #include #include +#include #ifndef ASTCENC_POPCNT #if defined(__POPCNT__) @@ -123,14 +124,6 @@ to future vectorization. ============================================================================ */ -// Union for manipulation of float bit patterns -typedef union -{ - uint32_t u; - int32_t s; - float f; -} if32; - // These are namespaced to avoid colliding with C standard library functions. namespace astc { @@ -359,9 +352,10 @@ static inline int flt2int_rd(float v) */ static inline int float_as_int(float v) { - union { int a; float b; } u; - u.b = v; - return u.a; + // Future: Can use std:bit_cast with C++20 + int iv; + std::memcpy(&iv, &v, sizeof(float)); + return iv; } /** @@ -373,9 +367,70 @@ static inline int float_as_int(float v) */ static inline float int_as_float(int v) { - union { int a; float b; } u; - u.a = v; - return u.b; + // Future: Can use std:bit_cast with C++20 + float fv; + std::memcpy(&fv, &v, sizeof(int)); + return fv; +} + +/** + * @brief SP float bit-interpreted as an unsigned integer. + * + * @param v The value to bitcast. + * + * @return The converted value. + */ +static inline unsigned int float_as_uint(float v) +{ + // Future: Can use std:bit_cast with C++20 + unsigned int iv; + std::memcpy(&iv, &v, sizeof(float)); + return iv; +} + +/** + * @brief Unsigned integer bit-interpreted as an SP float. + * + * @param v The value to bitcast. + * + * @return The converted value. + */ +static inline float uint_as_float(unsigned int v) +{ + // Future: Can use std:bit_cast with C++20 + float fv; + std::memcpy(&fv, &v, sizeof(unsigned int)); + return fv; +} + +/** + * @brief Signed int bit-interpreted as an unsigned integer. + * + * @param v The value to bitcast. + * + * @return The converted value. + */ +static inline unsigned int int_as_uint(int v) +{ + // Future: Can use std:bit_cast with C++20 + unsigned int uv; + std::memcpy(&uv, &v, sizeof(int)); + return uv; +} + +/** + * @brief Unsigned integer bit-interpreted as a signed integer. + * + * @param v The value to bitcast. + * + * @return The converted value. + */ +static inline int uint_as_int(unsigned int v) +{ + // Future: Can use std:bit_cast with C++20git p + int sv; + std::memcpy(&sv, &v, sizeof(unsigned int)); + return sv; } /** @@ -412,11 +467,10 @@ static inline float sqrt(float v) */ static inline float frexp(float v, int* expo) { - if32 p; - p.f = v; - *expo = ((p.u >> 23) & 0xFF) - 126; - p.u = (p.u & 0x807fffff) | 0x3f000000; - return p.f; + unsigned int iv = astc::float_as_uint(v); + *expo = ((iv >> 23) & 0xFF) - 126; + iv = (iv & 0x807fffff) | 0x3f000000; + return astc::uint_as_float(iv); } /** diff --git a/Source/astcenc_mathlib_softfloat.cpp b/Source/astcenc_mathlib_softfloat.cpp index 42db7645..83d0dc38 100644 --- a/Source/astcenc_mathlib_softfloat.cpp +++ b/Source/astcenc_mathlib_softfloat.cpp @@ -395,17 +395,14 @@ static sf16 sf32_to_sf16(sf32 inp, roundmode rmode) /* convert from soft-float to native-float */ float sf16_to_float(uint16_t p) { - if32 i; - i.u = sf16_to_sf32(p); - return i.f; + return astc::uint_as_float(sf16_to_sf32(p)); } /* convert from native-float to soft-float */ uint16_t float_to_sf16(float p) { - if32 i; - i.f = p; - return sf32_to_sf16(i.u, SF_NEARESTEVEN); + unsigned int ip = astc::float_as_uint(p); + return sf32_to_sf16(ip, SF_NEARESTEVEN); } #endif diff --git a/Source/astcenccli_error_metrics.cpp b/Source/astcenccli_error_metrics.cpp index 828b7e07..1b4d11dd 100644 --- a/Source/astcenccli_error_metrics.cpp +++ b/Source/astcenccli_error_metrics.cpp @@ -68,16 +68,10 @@ static float mpsnr_operator( float val, int fstop ) { - // Future: Can use std:bit_cast with C++20 - // Fast implementation of pow(2.0, fstop), assuming IEEE float layout // Memcpy to uint avoids ubsan complaints shift of negative int - unsigned int fstopu; - std::memcpy(&fstopu, &fstop, sizeof(int)); - uint32_t uscale = 0x3f800000 + (fstopu << 23); - - float scale; - std::memcpy(&scale, &uscale, sizeof(float)); + unsigned int uscale = 0x3f800000u + (astc::int_as_uint(fstop) << 23); + float scale = astc::uint_as_float(uscale); val = powf(val * scale, (1.0f / 2.2f)); return astc::clamp(val * 255.0f, 0.0f, 255.0f); diff --git a/Source/cmake_core.cmake b/Source/cmake_core.cmake index 708aac5f..a5de6801 100644 --- a/Source/cmake_core.cmake +++ b/Source/cmake_core.cmake @@ -189,21 +189,26 @@ macro(astcenc_set_properties ASTCENC_TARGET_NAME ASTCENC_VENEER_TYPE) if(${ASTCENC_ASAN}) target_compile_options(${ASTCENC_TARGET_NAME} PRIVATE - $<${is_gnu_fe}:-fsanitize=address>) + $<${is_gnu_fe}:-fsanitize=address> + $<${is_gnu_fe}:-fno-sanitize-recover=all>) target_link_options(${ASTCENC_TARGET_NAME} PRIVATE - $<${is_gnu_fe}:-fsanitize=address>) + $<${is_gnu_fe}:-fsanitize=address> + $<${is_clang}:-fuse-ld=lld>) + endif() if(${ASTCENC_UBSAN}) target_compile_options(${ASTCENC_TARGET_NAME} PRIVATE - $<${is_gnu_fe}:-fsanitize=undefined>) + $<${is_gnu_fe}:-fsanitize=undefined> + $<${is_gnu_fe}:-fno-sanitize-recover=all>) target_link_options(${ASTCENC_TARGET_NAME} PRIVATE - $<${is_gnu_fe}:-fsanitize=undefined>) + $<${is_gnu_fe}:-fsanitize=undefined> + $<${is_clang}:-fuse-ld=lld>) endif() if(NOT ${ASTCENC_INVARIANCE})