10b57cec5SDimitry Andric//=-lib/fp_extend_impl.inc - low precision -> high precision conversion -*-- -// 20b57cec5SDimitry Andric// 30b57cec5SDimitry Andric// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 40b57cec5SDimitry Andric// See https://llvm.org/LICENSE.txt for license information. 50b57cec5SDimitry Andric// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 60b57cec5SDimitry Andric// 70b57cec5SDimitry Andric//===----------------------------------------------------------------------===// 80b57cec5SDimitry Andric// 90b57cec5SDimitry Andric// This file implements a fairly generic conversion from a narrower to a wider 100b57cec5SDimitry Andric// IEEE-754 floating-point type. The constants and types defined following the 110b57cec5SDimitry Andric// includes below parameterize the conversion. 120b57cec5SDimitry Andric// 130b57cec5SDimitry Andric// It does not support types that don't use the usual IEEE-754 interchange 140b57cec5SDimitry Andric// formats; specifically, some work would be needed to adapt it to 150b57cec5SDimitry Andric// (for example) the Intel 80-bit format or PowerPC double-double format. 160b57cec5SDimitry Andric// 170b57cec5SDimitry Andric// Note please, however, that this implementation is only intended to support 180b57cec5SDimitry Andric// *widening* operations; if you need to convert to a *narrower* floating-point 190b57cec5SDimitry Andric// type (e.g. double -> float), then this routine will not do what you want it 200b57cec5SDimitry Andric// to. 210b57cec5SDimitry Andric// 220b57cec5SDimitry Andric// It also requires that integer types at least as large as both formats 230b57cec5SDimitry Andric// are available on the target platform; this may pose a problem when trying 240b57cec5SDimitry Andric// to add support for quad on some 32-bit systems, for example. You also may 250b57cec5SDimitry Andric// run into trouble finding an appropriate CLZ function for wide source types; 260b57cec5SDimitry Andric// you will likely need to roll your own on some platforms. 270b57cec5SDimitry Andric// 280b57cec5SDimitry Andric// Finally, the following assumptions are made: 290b57cec5SDimitry Andric// 300b57cec5SDimitry Andric// 1. Floating-point types and integer types have the same endianness on the 310b57cec5SDimitry Andric// target platform. 320b57cec5SDimitry Andric// 330b57cec5SDimitry Andric// 2. Quiet NaNs, if supported, are indicated by the leading bit of the 340b57cec5SDimitry Andric// significand field being set. 350b57cec5SDimitry Andric// 360b57cec5SDimitry Andric//===----------------------------------------------------------------------===// 370b57cec5SDimitry Andric 380b57cec5SDimitry Andric#include "fp_extend.h" 390b57cec5SDimitry Andric 405f757f3fSDimitry Andric// The source type may use a usual IEEE-754 interchange format or Intel 80-bit 415f757f3fSDimitry Andric// format. In particular, for the source type srcSigFracBits may be not equal to 425f757f3fSDimitry Andric// srcSigBits. The destination type is assumed to be one of IEEE-754 standard 435f757f3fSDimitry Andric// types. 440b57cec5SDimitry Andricstatic __inline dst_t __extendXfYf2__(src_t a) { 450b57cec5SDimitry Andric // Various constants whose values follow from the type parameters. 460b57cec5SDimitry Andric // Any reasonable optimizer will fold and propagate all of these. 470b57cec5SDimitry Andric const int srcInfExp = (1 << srcExpBits) - 1; 480b57cec5SDimitry Andric const int srcExpBias = srcInfExp >> 1; 490b57cec5SDimitry Andric 500b57cec5SDimitry Andric const int dstInfExp = (1 << dstExpBits) - 1; 510b57cec5SDimitry Andric const int dstExpBias = dstInfExp >> 1; 520b57cec5SDimitry Andric 530b57cec5SDimitry Andric // Break a into a sign and representation of the absolute value. 540b57cec5SDimitry Andric const src_rep_t aRep = srcToRep(a); 555f757f3fSDimitry Andric const src_rep_t srcSign = extract_sign_from_src(aRep); 565f757f3fSDimitry Andric const src_rep_t srcExp = extract_exp_from_src(aRep); 575f757f3fSDimitry Andric const src_rep_t srcSigFrac = extract_sig_frac_from_src(aRep); 580b57cec5SDimitry Andric 595f757f3fSDimitry Andric dst_rep_t dstSign = srcSign; 605f757f3fSDimitry Andric dst_rep_t dstExp; 615f757f3fSDimitry Andric dst_rep_t dstSigFrac; 625f757f3fSDimitry Andric 63*7a6dacacSDimitry Andric if (srcExp >= 1 && srcExp < (src_rep_t)srcInfExp) { 640b57cec5SDimitry Andric // a is a normal number. 655f757f3fSDimitry Andric dstExp = (dst_rep_t)srcExp + (dst_rep_t)(dstExpBias - srcExpBias); 665f757f3fSDimitry Andric dstSigFrac = (dst_rep_t)srcSigFrac << (dstSigFracBits - srcSigFracBits); 670b57cec5SDimitry Andric } 680b57cec5SDimitry Andric 695f757f3fSDimitry Andric else if (srcExp == srcInfExp) { 700b57cec5SDimitry Andric // a is NaN or infinity. 715f757f3fSDimitry Andric dstExp = dstInfExp; 725f757f3fSDimitry Andric dstSigFrac = (dst_rep_t)srcSigFrac << (dstSigFracBits - srcSigFracBits); 730b57cec5SDimitry Andric } 740b57cec5SDimitry Andric 755f757f3fSDimitry Andric else if (srcSigFrac) { 760b57cec5SDimitry Andric // a is denormal. 775f757f3fSDimitry Andric if (srcExpBits == dstExpBits) { 785f757f3fSDimitry Andric // The exponent fields are identical and this is a denormal number, so all 795f757f3fSDimitry Andric // the non-significand bits are zero. In particular, this branch is always 805f757f3fSDimitry Andric // taken when we extend a denormal F80 to F128. 815f757f3fSDimitry Andric dstExp = 0; 825f757f3fSDimitry Andric dstSigFrac = ((dst_rep_t)srcSigFrac) << (dstSigFracBits - srcSigFracBits); 835f757f3fSDimitry Andric } else { 845f757f3fSDimitry Andric#ifndef src_rep_t_clz 855f757f3fSDimitry Andric // If src_rep_t_clz is not defined this branch must be unreachable. 865f757f3fSDimitry Andric __builtin_unreachable(); 875f757f3fSDimitry Andric#else 885f757f3fSDimitry Andric // Renormalize the significand and clear the leading bit. 895f757f3fSDimitry Andric // For F80 -> F128 this codepath is unused. 905f757f3fSDimitry Andric const int scale = clz_in_sig_frac(srcSigFrac) + 1; 915f757f3fSDimitry Andric dstExp = dstExpBias - srcExpBias - scale + 1; 925f757f3fSDimitry Andric dstSigFrac = (dst_rep_t)srcSigFrac 935f757f3fSDimitry Andric << (dstSigFracBits - srcSigFracBits + scale); 945f757f3fSDimitry Andric const dst_rep_t dstMinNormal = DST_REP_C(1) << (dstBits - 1 - dstExpBits); 955f757f3fSDimitry Andric dstSigFrac ^= dstMinNormal; 965f757f3fSDimitry Andric#endif 975f757f3fSDimitry Andric } 980b57cec5SDimitry Andric } 990b57cec5SDimitry Andric 1000b57cec5SDimitry Andric else { 1010b57cec5SDimitry Andric // a is zero. 1025f757f3fSDimitry Andric dstExp = 0; 1035f757f3fSDimitry Andric dstSigFrac = 0; 1040b57cec5SDimitry Andric } 1050b57cec5SDimitry Andric 1065f757f3fSDimitry Andric const dst_rep_t result = construct_dst_rep(dstSign, dstExp, dstSigFrac); 1070b57cec5SDimitry Andric return dstFromRep(result); 1080b57cec5SDimitry Andric} 109