|
1 | 1 | // SPDX-License-Identifier: Apache-2.0 |
2 | 2 | // ---------------------------------------------------------------------------- |
3 | | -// Copyright 2011-2023 Arm Limited |
| 3 | +// Copyright 2011-2025 Arm Limited |
4 | 4 | // |
5 | 5 | // Licensed under the Apache License, Version 2.0 (the "License"); you may not |
6 | 6 | // use this file except in compliance with the License. You may obtain a copy |
@@ -40,6 +40,27 @@ static ASTCENC_SIMD_INLINE vint4 uncontract_color( |
40 | 40 | return select(input, bc0, mask); |
41 | 41 | } |
42 | 42 |
|
| 43 | +/** |
| 44 | + * @brief Signed left shift that allows all bits to be shifted out. |
| 45 | + * |
| 46 | + * Doing this directly on a 32-bit signed type results in undefined behavior |
| 47 | + * for many possible shifts although works in practice for most compilers. |
| 48 | + * |
| 49 | + * @param val The original value. |
| 50 | + * @param shift The left shift amount. |
| 51 | + * |
| 52 | + * @return The shifted value. |
| 53 | + */ |
| 54 | +static ASTCENC_SIMD_INLINE int32_t safe_signed_lsh(int32_t val, int shift) |
| 55 | +{ |
| 56 | + // Future: When we support C++20 can swap memcpy for std::bitcast |
| 57 | + uint32_t uval; |
| 58 | + std::memcpy(&uval, &val, sizeof(uint32_t)); |
| 59 | + uval <<= shift; |
| 60 | + std::memcpy(&val, &uval, sizeof(uint32_t)); |
| 61 | + return val; |
| 62 | +} |
| 63 | + |
43 | 64 | void rgba_delta_unpack( |
44 | 65 | vint4 input0, |
45 | 66 | vint4 input1, |
@@ -597,21 +618,23 @@ static void hdr_rgb_unpack( |
597 | 618 | int32_t d0x = d0; |
598 | 619 | int32_t d1x = d1; |
599 | 620 | int sx_shamt = 32 - dbits; |
600 | | - d0x <<= sx_shamt; |
| 621 | + |
| 622 | + d0x = safe_signed_lsh(d0x, sx_shamt); |
601 | 623 | d0x >>= sx_shamt; |
602 | | - d1x <<= sx_shamt; |
| 624 | + d1x = safe_signed_lsh(d1x, sx_shamt); |
603 | 625 | d1x >>= sx_shamt; |
| 626 | + |
604 | 627 | d0 = d0x; |
605 | 628 | d1 = d1x; |
606 | 629 |
|
607 | 630 | // expand all values to 12 bits, with left-shift as needed. |
608 | 631 | int val_shamt = (modeval >> 1) ^ 3; |
609 | | - a <<= val_shamt; |
610 | | - b0 <<= val_shamt; |
611 | | - b1 <<= val_shamt; |
612 | | - c <<= val_shamt; |
613 | | - d0 <<= val_shamt; |
614 | | - d1 <<= val_shamt; |
| 632 | + a = safe_signed_lsh(a, val_shamt); |
| 633 | + b0 = safe_signed_lsh(b0, val_shamt); |
| 634 | + b1 = safe_signed_lsh(b1, val_shamt); |
| 635 | + c = safe_signed_lsh(c, val_shamt); |
| 636 | + d0 = safe_signed_lsh(d0, val_shamt); |
| 637 | + d1 = safe_signed_lsh(d1, val_shamt); |
615 | 638 |
|
616 | 639 | // then compute the actual color values. |
617 | 640 | int red1 = a; |
|
0 commit comments