1/* 2 * Copyright (C) 2021 Alyssa Rosenzweig <alyssa@rosenzweig.io> 3 * 4 * Permission is hereby granted, free of charge, to any person obtaining a 5 * copy of this software and associated documentation files (the "Software"), 6 * to deal in the Software without restriction, including without limitation 7 * the rights to use, copy, modify, merge, publish, distribute, sublicense, 8 * and/or sell copies of the Software, and to permit persons to whom the 9 * Software is furnished to do so, subject to the following conditions: 10 * 11 * The above copyright notice and this permission notice (including the next 12 * paragraph) shall be included in all copies or substantial portions of the 13 * Software. 14 * 15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 18 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 * SOFTWARE. 22 */ 23 24#ifndef __AGX_MINIFLOAT_H_ 25#define __AGX_MINIFLOAT_H_ 26 27#include <math.h> 28#include "util/macros.h" 29 30/* AGX includes an 8-bit floating-point format for small dyadic immediates, 31 * consisting of 3 bits for the exponent, 4 bits for the mantissa, and 1-bit 32 * for sign, in the usual order. Zero exponent has special handling. */ 33 34static inline float 35agx_minifloat_decode(uint8_t imm) 36{ 37 float sign = (imm & 0x80) ? -1.0 : 1.0; 38 signed exp = (imm & 0x70) >> 4; 39 unsigned mantissa = (imm & 0xF); 40 41 if (exp) 42 return ldexpf(sign * (float) (mantissa | 0x10), exp - 7); 43 else 44 return ldexpf(sign * ((float) mantissa), -6); 45} 46 47/* Encodes a float. Results are only valid if the float can be represented 48 * exactly, if not the result of this function is UNDEFINED. signbit() is used 49 * to ensure -0.0 is handled correctly. */ 50 51static inline uint8_t 52agx_minifloat_encode(float f) 53{ 54 unsigned sign = signbit(f) ? 0x80 : 0; 55 f = fabsf(f); 56 57 /* frac is in [0.5, 1) and f = frac * 2^exp */ 58 int exp = 0; 59 float frac = frexpf(f, &exp); 60 61 if (f >= 0.25) { 62 unsigned mantissa = (frac * 32.0); 63 exp -= 5; /* 2^5 = 32 */ 64 exp = CLAMP(exp + 7, 0, 7); 65 66 assert(mantissa >= 0x10 && mantissa < 0x20); 67 assert(exp >= 1); 68 69 return sign | (exp << 4) | (mantissa & 0xF); 70 } else { 71 unsigned mantissa = (f * 64.0f); 72 assert(mantissa < 0x10); 73 74 return sign | mantissa; 75 } 76} 77 78static inline bool 79agx_minifloat_exact(float f) 80{ 81 float f_ = agx_minifloat_decode(agx_minifloat_encode(f)); 82 return memcmp(&f, &f_, sizeof(float)) == 0; 83} 84 85#endif 86