10b57cec5SDimitry Andric //===-lib/fp_extend.h - low precision -> high precision conversion -*- C 20b57cec5SDimitry Andric //-*-===// 30b57cec5SDimitry Andric // 40b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 50b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information. 60b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 70b57cec5SDimitry Andric // 80b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 90b57cec5SDimitry Andric // 100b57cec5SDimitry Andric // Set source and destination setting 110b57cec5SDimitry Andric // 120b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 130b57cec5SDimitry Andric 140b57cec5SDimitry Andric #ifndef FP_EXTEND_HEADER 150b57cec5SDimitry Andric #define FP_EXTEND_HEADER 160b57cec5SDimitry Andric 170b57cec5SDimitry Andric #include "int_lib.h" 180b57cec5SDimitry Andric 190b57cec5SDimitry Andric #if defined SRC_SINGLE 200b57cec5SDimitry Andric typedef float src_t; 210b57cec5SDimitry Andric typedef uint32_t src_rep_t; 220b57cec5SDimitry Andric #define SRC_REP_C UINT32_C 235f757f3fSDimitry Andric static const int srcBits = sizeof(src_t) * CHAR_BIT; 245f757f3fSDimitry Andric static const int srcSigFracBits = 23; 255f757f3fSDimitry Andric // -1 accounts for the sign bit. 265f757f3fSDimitry Andric // srcBits - srcSigFracBits - 1 275f757f3fSDimitry Andric static const int srcExpBits = 8; 285ffd83dbSDimitry Andric #define src_rep_t_clz clzsi 290b57cec5SDimitry Andric 300b57cec5SDimitry Andric #elif defined SRC_DOUBLE 310b57cec5SDimitry Andric typedef double src_t; 320b57cec5SDimitry Andric typedef uint64_t src_rep_t; 330b57cec5SDimitry Andric #define SRC_REP_C UINT64_C 345f757f3fSDimitry Andric static const int srcBits = sizeof(src_t) * CHAR_BIT; 355f757f3fSDimitry Andric static const int srcSigFracBits = 52; 365f757f3fSDimitry Andric // -1 accounts for the sign bit. 375f757f3fSDimitry Andric // srcBits - srcSigFracBits - 1 385f757f3fSDimitry Andric static const int srcExpBits = 11; 395f757f3fSDimitry Andric 40*0fca6ea1SDimitry Andric static inline int src_rep_t_clz_impl(src_rep_t a) { return __builtin_clzll(a); } 415f757f3fSDimitry Andric #define src_rep_t_clz src_rep_t_clz_impl 425f757f3fSDimitry Andric 435f757f3fSDimitry Andric #elif defined SRC_80 445f757f3fSDimitry Andric typedef xf_float src_t; 455f757f3fSDimitry Andric typedef __uint128_t src_rep_t; 465f757f3fSDimitry Andric #define SRC_REP_C (__uint128_t) 475f757f3fSDimitry Andric // sign bit, exponent and significand occupy the lower 80 bits. 485f757f3fSDimitry Andric static const int srcBits = 80; 495f757f3fSDimitry Andric static const int srcSigFracBits = 63; 505f757f3fSDimitry Andric // -1 accounts for the sign bit. 515f757f3fSDimitry Andric // -1 accounts for the explicitly stored integer bit. 525f757f3fSDimitry Andric // srcBits - srcSigFracBits - 1 - 1 535f757f3fSDimitry Andric static const int srcExpBits = 15; 540b57cec5SDimitry Andric 550b57cec5SDimitry Andric #elif defined SRC_HALF 56e8d8bef9SDimitry Andric #ifdef COMPILER_RT_HAS_FLOAT16 57e8d8bef9SDimitry Andric typedef _Float16 src_t; 58e8d8bef9SDimitry Andric #else 590b57cec5SDimitry Andric typedef uint16_t src_t; 60e8d8bef9SDimitry Andric #endif 610b57cec5SDimitry Andric typedef uint16_t src_rep_t; 620b57cec5SDimitry Andric #define SRC_REP_C UINT16_C 635f757f3fSDimitry Andric static const int srcBits = sizeof(src_t) * CHAR_BIT; 645f757f3fSDimitry Andric static const int srcSigFracBits = 10; 655f757f3fSDimitry Andric // -1 accounts for the sign bit. 665f757f3fSDimitry Andric // srcBits - srcSigFracBits - 1 675f757f3fSDimitry Andric static const int srcExpBits = 5; 685f757f3fSDimitry Andric 695f757f3fSDimitry Andric static inline int src_rep_t_clz_impl(src_rep_t a) { 705f757f3fSDimitry Andric return __builtin_clz(a) - 16; 715f757f3fSDimitry Andric } 725f757f3fSDimitry Andric 735f757f3fSDimitry Andric #define src_rep_t_clz src_rep_t_clz_impl 740b57cec5SDimitry Andric 75*0fca6ea1SDimitry Andric #elif defined SRC_BFLOAT16 76*0fca6ea1SDimitry Andric #ifdef COMPILER_RT_HAS_BFLOAT16 77*0fca6ea1SDimitry Andric typedef __bf16 src_t; 78*0fca6ea1SDimitry Andric #else 79*0fca6ea1SDimitry Andric typedef uint16_t src_t; 80*0fca6ea1SDimitry Andric #endif 81*0fca6ea1SDimitry Andric typedef uint16_t src_rep_t; 82*0fca6ea1SDimitry Andric #define SRC_REP_C UINT16_C 83*0fca6ea1SDimitry Andric static const int srcBits = sizeof(src_t) * CHAR_BIT; 84*0fca6ea1SDimitry Andric static const int srcSigFracBits = 7; 85*0fca6ea1SDimitry Andric // -1 accounts for the sign bit. 86*0fca6ea1SDimitry Andric // srcBits - srcSigFracBits - 1 87*0fca6ea1SDimitry Andric static const int srcExpBits = 8; 88*0fca6ea1SDimitry Andric #define src_rep_t_clz __builtin_clz 89*0fca6ea1SDimitry Andric 900b57cec5SDimitry Andric #else 910b57cec5SDimitry Andric #error Source should be half, single, or double precision! 920b57cec5SDimitry Andric #endif // end source precision 930b57cec5SDimitry Andric 940b57cec5SDimitry Andric #if defined DST_SINGLE 950b57cec5SDimitry Andric typedef float dst_t; 960b57cec5SDimitry Andric typedef uint32_t dst_rep_t; 970b57cec5SDimitry Andric #define DST_REP_C UINT32_C 985f757f3fSDimitry Andric static const int dstBits = sizeof(dst_t) * CHAR_BIT; 995f757f3fSDimitry Andric static const int dstSigFracBits = 23; 1005f757f3fSDimitry Andric // -1 accounts for the sign bit. 1015f757f3fSDimitry Andric // dstBits - dstSigFracBits - 1 1025f757f3fSDimitry Andric static const int dstExpBits = 8; 1030b57cec5SDimitry Andric 1040b57cec5SDimitry Andric #elif defined DST_DOUBLE 1050b57cec5SDimitry Andric typedef double dst_t; 1060b57cec5SDimitry Andric typedef uint64_t dst_rep_t; 1070b57cec5SDimitry Andric #define DST_REP_C UINT64_C 1085f757f3fSDimitry Andric static const int dstBits = sizeof(dst_t) * CHAR_BIT; 1095f757f3fSDimitry Andric static const int dstSigFracBits = 52; 1105f757f3fSDimitry Andric // -1 accounts for the sign bit. 1115f757f3fSDimitry Andric // dstBits - dstSigFracBits - 1 1125f757f3fSDimitry Andric static const int dstExpBits = 11; 1130b57cec5SDimitry Andric 1140b57cec5SDimitry Andric #elif defined DST_QUAD 1155f757f3fSDimitry Andric typedef tf_float dst_t; 1160b57cec5SDimitry Andric typedef __uint128_t dst_rep_t; 1170b57cec5SDimitry Andric #define DST_REP_C (__uint128_t) 1185f757f3fSDimitry Andric static const int dstBits = sizeof(dst_t) * CHAR_BIT; 1195f757f3fSDimitry Andric static const int dstSigFracBits = 112; 1205f757f3fSDimitry Andric // -1 accounts for the sign bit. 1215f757f3fSDimitry Andric // dstBits - dstSigFracBits - 1 1225f757f3fSDimitry Andric static const int dstExpBits = 15; 1230b57cec5SDimitry Andric 1240b57cec5SDimitry Andric #else 1250b57cec5SDimitry Andric #error Destination should be single, double, or quad precision! 1260b57cec5SDimitry Andric #endif // end destination precision 1270b57cec5SDimitry Andric 1285f757f3fSDimitry Andric // End of specialization parameters. 1290b57cec5SDimitry Andric 1305f757f3fSDimitry Andric // TODO: These helper routines should be placed into fp_lib.h 1315f757f3fSDimitry Andric // Currently they depend on macros/constants defined above. 1325f757f3fSDimitry Andric 1335f757f3fSDimitry Andric static inline src_rep_t extract_sign_from_src(src_rep_t x) { 1345f757f3fSDimitry Andric const src_rep_t srcSignMask = SRC_REP_C(1) << (srcBits - 1); 1355f757f3fSDimitry Andric return (x & srcSignMask) >> (srcBits - 1); 1365f757f3fSDimitry Andric } 1375f757f3fSDimitry Andric 1385f757f3fSDimitry Andric static inline src_rep_t extract_exp_from_src(src_rep_t x) { 1395f757f3fSDimitry Andric const int srcSigBits = srcBits - 1 - srcExpBits; 1405f757f3fSDimitry Andric const src_rep_t srcExpMask = ((SRC_REP_C(1) << srcExpBits) - 1) << srcSigBits; 1415f757f3fSDimitry Andric return (x & srcExpMask) >> srcSigBits; 1425f757f3fSDimitry Andric } 1435f757f3fSDimitry Andric 1445f757f3fSDimitry Andric static inline src_rep_t extract_sig_frac_from_src(src_rep_t x) { 1455f757f3fSDimitry Andric const src_rep_t srcSigFracMask = (SRC_REP_C(1) << srcSigFracBits) - 1; 1465f757f3fSDimitry Andric return x & srcSigFracMask; 1475f757f3fSDimitry Andric } 1485f757f3fSDimitry Andric 1495f757f3fSDimitry Andric #ifdef src_rep_t_clz 1505f757f3fSDimitry Andric static inline int clz_in_sig_frac(src_rep_t sigFrac) { 1515f757f3fSDimitry Andric const int skip = 1 + srcExpBits; 1525f757f3fSDimitry Andric return src_rep_t_clz(sigFrac) - skip; 1535f757f3fSDimitry Andric } 1545f757f3fSDimitry Andric #endif 1555f757f3fSDimitry Andric 1565f757f3fSDimitry Andric static inline dst_rep_t construct_dst_rep(dst_rep_t sign, dst_rep_t exp, dst_rep_t sigFrac) { 1575f757f3fSDimitry Andric return (sign << (dstBits - 1)) | (exp << (dstBits - 1 - dstExpBits)) | sigFrac; 1585f757f3fSDimitry Andric } 1595f757f3fSDimitry Andric 1605f757f3fSDimitry Andric // Two helper routines for conversion to and from the representation of 1615f757f3fSDimitry Andric // floating-point data as integer values follow. 1625f757f3fSDimitry Andric 1635f757f3fSDimitry Andric static inline src_rep_t srcToRep(src_t x) { 1640b57cec5SDimitry Andric const union { 1650b57cec5SDimitry Andric src_t f; 1660b57cec5SDimitry Andric src_rep_t i; 1670b57cec5SDimitry Andric } rep = {.f = x}; 1680b57cec5SDimitry Andric return rep.i; 1690b57cec5SDimitry Andric } 1700b57cec5SDimitry Andric 1715f757f3fSDimitry Andric static inline dst_t dstFromRep(dst_rep_t x) { 1720b57cec5SDimitry Andric const union { 1730b57cec5SDimitry Andric dst_t f; 1740b57cec5SDimitry Andric dst_rep_t i; 1750b57cec5SDimitry Andric } rep = {.i = x}; 1760b57cec5SDimitry Andric return rep.f; 1770b57cec5SDimitry Andric } 1780b57cec5SDimitry Andric // End helper routines. Conversion implementation follows. 1790b57cec5SDimitry Andric 1800b57cec5SDimitry Andric #endif // FP_EXTEND_HEADER 181