198b9484cSchristos /* IEEE floating point support routines, for GDB, the GNU Debugger. 2*7e120ff0Schristos Copyright (C) 1991-2024 Free Software Foundation, Inc. 398b9484cSchristos 498b9484cSchristos This file is part of GDB. 598b9484cSchristos 698b9484cSchristos This program is free software; you can redistribute it and/or modify 798b9484cSchristos it under the terms of the GNU General Public License as published by 898b9484cSchristos the Free Software Foundation; either version 2 of the License, or 998b9484cSchristos (at your option) any later version. 1098b9484cSchristos 1198b9484cSchristos This program is distributed in the hope that it will be useful, 1298b9484cSchristos but WITHOUT ANY WARRANTY; without even the implied warranty of 1398b9484cSchristos MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 1498b9484cSchristos GNU General Public License for more details. 1598b9484cSchristos 1698b9484cSchristos You should have received a copy of the GNU General Public License 1798b9484cSchristos along with this program; if not, write to the Free Software 1898b9484cSchristos Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA. */ 1998b9484cSchristos 2098b9484cSchristos /* This is needed to pick up the NAN macro on some systems. */ 21212397c6Schristos #ifndef _GNU_SOURCE 2298b9484cSchristos #define _GNU_SOURCE 23212397c6Schristos #endif 2498b9484cSchristos 2598b9484cSchristos #ifdef HAVE_CONFIG_H 2698b9484cSchristos #include "config.h" 2798b9484cSchristos #endif 2898b9484cSchristos 2998b9484cSchristos #include <math.h> 3098b9484cSchristos 3198b9484cSchristos #ifdef HAVE_STRING_H 3298b9484cSchristos #include <string.h> 3398b9484cSchristos #endif 3498b9484cSchristos 3598b9484cSchristos /* On some platforms, <float.h> provides DBL_QNAN. */ 3698b9484cSchristos #ifdef STDC_HEADERS 3798b9484cSchristos #include <float.h> 3898b9484cSchristos #endif 3998b9484cSchristos 4098b9484cSchristos #include "ansidecl.h" 4198b9484cSchristos #include "libiberty.h" 4298b9484cSchristos #include "floatformat.h" 4398b9484cSchristos 4498b9484cSchristos #ifndef INFINITY 4598b9484cSchristos #ifdef HUGE_VAL 4698b9484cSchristos #define INFINITY HUGE_VAL 4798b9484cSchristos #else 4898b9484cSchristos #define INFINITY (1.0 / 0.0) 4998b9484cSchristos #endif 5098b9484cSchristos #endif 5198b9484cSchristos 5298b9484cSchristos #ifndef NAN 5398b9484cSchristos #ifdef DBL_QNAN 5498b9484cSchristos #define NAN DBL_QNAN 5598b9484cSchristos #else 5698b9484cSchristos #define NAN (0.0 / 0.0) 5798b9484cSchristos #endif 5898b9484cSchristos #endif 5998b9484cSchristos 6098b9484cSchristos static int mant_bits_set (const struct floatformat *, const unsigned char *); 6198b9484cSchristos static unsigned long get_field (const unsigned char *, 6298b9484cSchristos enum floatformat_byteorders, 6398b9484cSchristos unsigned int, 6498b9484cSchristos unsigned int, 6598b9484cSchristos unsigned int); 6698b9484cSchristos static int floatformat_always_valid (const struct floatformat *fmt, 6798b9484cSchristos const void *from); 6898b9484cSchristos 6998b9484cSchristos static int 7098b9484cSchristos floatformat_always_valid (const struct floatformat *fmt ATTRIBUTE_UNUSED, 7198b9484cSchristos const void *from ATTRIBUTE_UNUSED) 7298b9484cSchristos { 7398b9484cSchristos return 1; 7498b9484cSchristos } 7598b9484cSchristos 7698b9484cSchristos /* The odds that CHAR_BIT will be anything but 8 are low enough that I'm not 7798b9484cSchristos going to bother with trying to muck around with whether it is defined in 7898b9484cSchristos a system header, what we do if not, etc. */ 7998b9484cSchristos #define FLOATFORMAT_CHAR_BIT 8 8098b9484cSchristos 814b169a6bSchristos /* floatformats for IEEE half, single, double and quad, big and little endian. */ 8298b9484cSchristos const struct floatformat floatformat_ieee_half_big = 8398b9484cSchristos { 8498b9484cSchristos floatformat_big, 16, 0, 1, 5, 15, 31, 6, 10, 8598b9484cSchristos floatformat_intbit_no, 8698b9484cSchristos "floatformat_ieee_half_big", 8798b9484cSchristos floatformat_always_valid, 8898b9484cSchristos NULL 8998b9484cSchristos }; 9098b9484cSchristos const struct floatformat floatformat_ieee_half_little = 9198b9484cSchristos { 9298b9484cSchristos floatformat_little, 16, 0, 1, 5, 15, 31, 6, 10, 9398b9484cSchristos floatformat_intbit_no, 9498b9484cSchristos "floatformat_ieee_half_little", 9598b9484cSchristos floatformat_always_valid, 9698b9484cSchristos NULL 9798b9484cSchristos }; 9898b9484cSchristos const struct floatformat floatformat_ieee_single_big = 9998b9484cSchristos { 10098b9484cSchristos floatformat_big, 32, 0, 1, 8, 127, 255, 9, 23, 10198b9484cSchristos floatformat_intbit_no, 10298b9484cSchristos "floatformat_ieee_single_big", 10398b9484cSchristos floatformat_always_valid, 10498b9484cSchristos NULL 10598b9484cSchristos }; 10698b9484cSchristos const struct floatformat floatformat_ieee_single_little = 10798b9484cSchristos { 10898b9484cSchristos floatformat_little, 32, 0, 1, 8, 127, 255, 9, 23, 10998b9484cSchristos floatformat_intbit_no, 11098b9484cSchristos "floatformat_ieee_single_little", 11198b9484cSchristos floatformat_always_valid, 11298b9484cSchristos NULL 11398b9484cSchristos }; 11498b9484cSchristos const struct floatformat floatformat_ieee_double_big = 11598b9484cSchristos { 11698b9484cSchristos floatformat_big, 64, 0, 1, 11, 1023, 2047, 12, 52, 11798b9484cSchristos floatformat_intbit_no, 11898b9484cSchristos "floatformat_ieee_double_big", 11998b9484cSchristos floatformat_always_valid, 12098b9484cSchristos NULL 12198b9484cSchristos }; 12298b9484cSchristos const struct floatformat floatformat_ieee_double_little = 12398b9484cSchristos { 12498b9484cSchristos floatformat_little, 64, 0, 1, 11, 1023, 2047, 12, 52, 12598b9484cSchristos floatformat_intbit_no, 12698b9484cSchristos "floatformat_ieee_double_little", 12798b9484cSchristos floatformat_always_valid, 12898b9484cSchristos NULL 12998b9484cSchristos }; 1304b169a6bSchristos const struct floatformat floatformat_ieee_quad_big = 1314b169a6bSchristos { 1324b169a6bSchristos floatformat_big, 128, 0, 1, 15, 16383, 0x7fff, 16, 112, 1334b169a6bSchristos floatformat_intbit_no, 1344b169a6bSchristos "floatformat_ieee_quad_big", 1354b169a6bSchristos floatformat_always_valid, 1364b169a6bSchristos NULL 1374b169a6bSchristos }; 1384b169a6bSchristos const struct floatformat floatformat_ieee_quad_little = 1394b169a6bSchristos { 1404b169a6bSchristos floatformat_little, 128, 0, 1, 15, 16383, 0x7fff, 16, 112, 1414b169a6bSchristos floatformat_intbit_no, 1424b169a6bSchristos "floatformat_ieee_quad_little", 1434b169a6bSchristos floatformat_always_valid, 1444b169a6bSchristos NULL 1454b169a6bSchristos }; 14698b9484cSchristos 14798b9484cSchristos /* floatformat for IEEE double, little endian byte order, with big endian word 14898b9484cSchristos ordering, as on the ARM. */ 14998b9484cSchristos 15098b9484cSchristos const struct floatformat floatformat_ieee_double_littlebyte_bigword = 15198b9484cSchristos { 15298b9484cSchristos floatformat_littlebyte_bigword, 64, 0, 1, 11, 1023, 2047, 12, 52, 15398b9484cSchristos floatformat_intbit_no, 15498b9484cSchristos "floatformat_ieee_double_littlebyte_bigword", 15598b9484cSchristos floatformat_always_valid, 15698b9484cSchristos NULL 15798b9484cSchristos }; 15898b9484cSchristos 15998b9484cSchristos /* floatformat for VAX. Not quite IEEE, but close enough. */ 16098b9484cSchristos 16198b9484cSchristos const struct floatformat floatformat_vax_f = 16298b9484cSchristos { 16398b9484cSchristos floatformat_vax, 32, 0, 1, 8, 129, 0, 9, 23, 16498b9484cSchristos floatformat_intbit_no, 16598b9484cSchristos "floatformat_vax_f", 16698b9484cSchristos floatformat_always_valid, 16798b9484cSchristos NULL 16898b9484cSchristos }; 16998b9484cSchristos const struct floatformat floatformat_vax_d = 17098b9484cSchristos { 17198b9484cSchristos floatformat_vax, 64, 0, 1, 8, 129, 0, 9, 55, 17298b9484cSchristos floatformat_intbit_no, 17398b9484cSchristos "floatformat_vax_d", 17498b9484cSchristos floatformat_always_valid, 17598b9484cSchristos NULL 17698b9484cSchristos }; 17798b9484cSchristos const struct floatformat floatformat_vax_g = 17898b9484cSchristos { 17998b9484cSchristos floatformat_vax, 64, 0, 1, 11, 1025, 0, 12, 52, 18098b9484cSchristos floatformat_intbit_no, 18198b9484cSchristos "floatformat_vax_g", 18298b9484cSchristos floatformat_always_valid, 18398b9484cSchristos NULL 18498b9484cSchristos }; 18598b9484cSchristos 18698b9484cSchristos static int floatformat_i387_ext_is_valid (const struct floatformat *fmt, 18798b9484cSchristos const void *from); 18898b9484cSchristos 18998b9484cSchristos static int 19098b9484cSchristos floatformat_i387_ext_is_valid (const struct floatformat *fmt, const void *from) 19198b9484cSchristos { 19298b9484cSchristos /* In the i387 double-extended format, if the exponent is all ones, 19398b9484cSchristos then the integer bit must be set. If the exponent is neither 0 19498b9484cSchristos nor ~0, the intbit must also be set. Only if the exponent is 19598b9484cSchristos zero can it be zero, and then it must be zero. */ 19698b9484cSchristos unsigned long exponent, int_bit; 19798b9484cSchristos const unsigned char *ufrom = (const unsigned char *) from; 19898b9484cSchristos 19998b9484cSchristos exponent = get_field (ufrom, fmt->byteorder, fmt->totalsize, 20098b9484cSchristos fmt->exp_start, fmt->exp_len); 20198b9484cSchristos int_bit = get_field (ufrom, fmt->byteorder, fmt->totalsize, 20298b9484cSchristos fmt->man_start, 1); 20398b9484cSchristos 20498b9484cSchristos if ((exponent == 0) != (int_bit == 0)) 20598b9484cSchristos return 0; 20698b9484cSchristos else 20798b9484cSchristos return 1; 20898b9484cSchristos } 20998b9484cSchristos 21098b9484cSchristos const struct floatformat floatformat_i387_ext = 21198b9484cSchristos { 21298b9484cSchristos floatformat_little, 80, 0, 1, 15, 0x3fff, 0x7fff, 16, 64, 21398b9484cSchristos floatformat_intbit_yes, 21498b9484cSchristos "floatformat_i387_ext", 21598b9484cSchristos floatformat_i387_ext_is_valid, 21698b9484cSchristos NULL 21798b9484cSchristos }; 21898b9484cSchristos const struct floatformat floatformat_m68881_ext = 21998b9484cSchristos { 22098b9484cSchristos /* Note that the bits from 16 to 31 are unused. */ 22198b9484cSchristos floatformat_big, 96, 0, 1, 15, 0x3fff, 0x7fff, 32, 64, 22298b9484cSchristos floatformat_intbit_yes, 22398b9484cSchristos "floatformat_m68881_ext", 22498b9484cSchristos floatformat_always_valid, 22598b9484cSchristos NULL 22698b9484cSchristos }; 22798b9484cSchristos const struct floatformat floatformat_i960_ext = 22898b9484cSchristos { 22998b9484cSchristos /* Note that the bits from 0 to 15 are unused. */ 23098b9484cSchristos floatformat_little, 96, 16, 17, 15, 0x3fff, 0x7fff, 32, 64, 23198b9484cSchristos floatformat_intbit_yes, 23298b9484cSchristos "floatformat_i960_ext", 23398b9484cSchristos floatformat_always_valid, 23498b9484cSchristos NULL 23598b9484cSchristos }; 23698b9484cSchristos const struct floatformat floatformat_m88110_ext = 23798b9484cSchristos { 23898b9484cSchristos floatformat_big, 80, 0, 1, 15, 0x3fff, 0x7fff, 16, 64, 23998b9484cSchristos floatformat_intbit_yes, 24098b9484cSchristos "floatformat_m88110_ext", 24198b9484cSchristos floatformat_always_valid, 24298b9484cSchristos NULL 24398b9484cSchristos }; 24498b9484cSchristos const struct floatformat floatformat_m88110_harris_ext = 24598b9484cSchristos { 24698b9484cSchristos /* Harris uses raw format 128 bytes long, but the number is just an ieee 24798b9484cSchristos double, and the last 64 bits are wasted. */ 24898b9484cSchristos floatformat_big,128, 0, 1, 11, 0x3ff, 0x7ff, 12, 52, 24998b9484cSchristos floatformat_intbit_no, 25098b9484cSchristos "floatformat_m88110_ext_harris", 25198b9484cSchristos floatformat_always_valid, 25298b9484cSchristos NULL 25398b9484cSchristos }; 25498b9484cSchristos const struct floatformat floatformat_arm_ext_big = 25598b9484cSchristos { 25698b9484cSchristos /* Bits 1 to 16 are unused. */ 25798b9484cSchristos floatformat_big, 96, 0, 17, 15, 0x3fff, 0x7fff, 32, 64, 25898b9484cSchristos floatformat_intbit_yes, 25998b9484cSchristos "floatformat_arm_ext_big", 26098b9484cSchristos floatformat_always_valid, 26198b9484cSchristos NULL 26298b9484cSchristos }; 26398b9484cSchristos const struct floatformat floatformat_arm_ext_littlebyte_bigword = 26498b9484cSchristos { 26598b9484cSchristos /* Bits 1 to 16 are unused. */ 26698b9484cSchristos floatformat_littlebyte_bigword, 96, 0, 17, 15, 0x3fff, 0x7fff, 32, 64, 26798b9484cSchristos floatformat_intbit_yes, 26898b9484cSchristos "floatformat_arm_ext_littlebyte_bigword", 26998b9484cSchristos floatformat_always_valid, 27098b9484cSchristos NULL 27198b9484cSchristos }; 27298b9484cSchristos const struct floatformat floatformat_ia64_spill_big = 27398b9484cSchristos { 27498b9484cSchristos floatformat_big, 128, 0, 1, 17, 65535, 0x1ffff, 18, 64, 27598b9484cSchristos floatformat_intbit_yes, 27698b9484cSchristos "floatformat_ia64_spill_big", 27798b9484cSchristos floatformat_always_valid, 27898b9484cSchristos NULL 27998b9484cSchristos }; 28098b9484cSchristos const struct floatformat floatformat_ia64_spill_little = 28198b9484cSchristos { 28298b9484cSchristos floatformat_little, 128, 0, 1, 17, 65535, 0x1ffff, 18, 64, 28398b9484cSchristos floatformat_intbit_yes, 28498b9484cSchristos "floatformat_ia64_spill_little", 28598b9484cSchristos floatformat_always_valid, 28698b9484cSchristos NULL 28798b9484cSchristos }; 28898b9484cSchristos 28998b9484cSchristos static int 29098b9484cSchristos floatformat_ibm_long_double_is_valid (const struct floatformat *fmt, 29198b9484cSchristos const void *from) 29298b9484cSchristos { 29398b9484cSchristos const unsigned char *ufrom = (const unsigned char *) from; 29498b9484cSchristos const struct floatformat *hfmt = fmt->split_half; 29598b9484cSchristos long top_exp, bot_exp; 29698b9484cSchristos int top_nan = 0; 29798b9484cSchristos 29898b9484cSchristos top_exp = get_field (ufrom, hfmt->byteorder, hfmt->totalsize, 29998b9484cSchristos hfmt->exp_start, hfmt->exp_len); 30098b9484cSchristos bot_exp = get_field (ufrom + 8, hfmt->byteorder, hfmt->totalsize, 30198b9484cSchristos hfmt->exp_start, hfmt->exp_len); 30298b9484cSchristos 30398b9484cSchristos if ((unsigned long) top_exp == hfmt->exp_nan) 30498b9484cSchristos top_nan = mant_bits_set (hfmt, ufrom); 30598b9484cSchristos 30698b9484cSchristos /* A NaN is valid with any low part. */ 30798b9484cSchristos if (top_nan) 30898b9484cSchristos return 1; 30998b9484cSchristos 31098b9484cSchristos /* An infinity, zero or denormal requires low part 0 (positive or 31198b9484cSchristos negative). */ 31298b9484cSchristos if ((unsigned long) top_exp == hfmt->exp_nan || top_exp == 0) 31398b9484cSchristos { 31498b9484cSchristos if (bot_exp != 0) 31598b9484cSchristos return 0; 31698b9484cSchristos 31798b9484cSchristos return !mant_bits_set (hfmt, ufrom + 8); 31898b9484cSchristos } 31998b9484cSchristos 32098b9484cSchristos /* The top part is now a finite normal value. The long double value 32198b9484cSchristos is the sum of the two parts, and the top part must equal the 32298b9484cSchristos result of rounding the long double value to nearest double. Thus 32398b9484cSchristos the bottom part must be <= 0.5ulp of the top part in absolute 32498b9484cSchristos value, and if it is < 0.5ulp then the long double is definitely 32598b9484cSchristos valid. */ 32698b9484cSchristos if (bot_exp < top_exp - 53) 32798b9484cSchristos return 1; 32898b9484cSchristos if (bot_exp > top_exp - 53 && bot_exp != 0) 32998b9484cSchristos return 0; 33098b9484cSchristos if (bot_exp == 0) 33198b9484cSchristos { 33298b9484cSchristos /* The bottom part is 0 or denormal. Determine which, and if 33398b9484cSchristos denormal the first two set bits. */ 33498b9484cSchristos int first_bit = -1, second_bit = -1, cur_bit; 33598b9484cSchristos for (cur_bit = 0; (unsigned int) cur_bit < hfmt->man_len; cur_bit++) 33698b9484cSchristos if (get_field (ufrom + 8, hfmt->byteorder, hfmt->totalsize, 33798b9484cSchristos hfmt->man_start + cur_bit, 1)) 33898b9484cSchristos { 33998b9484cSchristos if (first_bit == -1) 34098b9484cSchristos first_bit = cur_bit; 34198b9484cSchristos else 34298b9484cSchristos { 34398b9484cSchristos second_bit = cur_bit; 34498b9484cSchristos break; 34598b9484cSchristos } 34698b9484cSchristos } 34798b9484cSchristos /* Bottom part 0 is OK. */ 34898b9484cSchristos if (first_bit == -1) 34998b9484cSchristos return 1; 35098b9484cSchristos /* The real exponent of the bottom part is -first_bit. */ 35198b9484cSchristos if (-first_bit < top_exp - 53) 35298b9484cSchristos return 1; 35398b9484cSchristos if (-first_bit > top_exp - 53) 35498b9484cSchristos return 0; 35598b9484cSchristos /* The bottom part is at least 0.5ulp of the top part. For this 35698b9484cSchristos to be OK, the bottom part must be exactly 0.5ulp (i.e. no 35798b9484cSchristos more bits set) and the top part must have last bit 0. */ 35898b9484cSchristos if (second_bit != -1) 35998b9484cSchristos return 0; 36098b9484cSchristos return !get_field (ufrom, hfmt->byteorder, hfmt->totalsize, 36198b9484cSchristos hfmt->man_start + hfmt->man_len - 1, 1); 36298b9484cSchristos } 36398b9484cSchristos else 36498b9484cSchristos { 36598b9484cSchristos /* The bottom part is at least 0.5ulp of the top part. For this 36698b9484cSchristos to be OK, it must be exactly 0.5ulp (i.e. no explicit bits 36798b9484cSchristos set) and the top part must have last bit 0. */ 36898b9484cSchristos if (get_field (ufrom, hfmt->byteorder, hfmt->totalsize, 36998b9484cSchristos hfmt->man_start + hfmt->man_len - 1, 1)) 37098b9484cSchristos return 0; 37198b9484cSchristos return !mant_bits_set (hfmt, ufrom + 8); 37298b9484cSchristos } 37398b9484cSchristos } 37498b9484cSchristos 37503467a24Schristos const struct floatformat floatformat_ibm_long_double_big = 37698b9484cSchristos { 37798b9484cSchristos floatformat_big, 128, 0, 1, 11, 1023, 2047, 12, 52, 37898b9484cSchristos floatformat_intbit_no, 37903467a24Schristos "floatformat_ibm_long_double_big", 38098b9484cSchristos floatformat_ibm_long_double_is_valid, 38198b9484cSchristos &floatformat_ieee_double_big 38298b9484cSchristos }; 38303467a24Schristos 38403467a24Schristos const struct floatformat floatformat_ibm_long_double_little = 38503467a24Schristos { 38603467a24Schristos floatformat_little, 128, 0, 1, 11, 1023, 2047, 12, 52, 38703467a24Schristos floatformat_intbit_no, 38803467a24Schristos "floatformat_ibm_long_double_little", 38903467a24Schristos floatformat_ibm_long_double_is_valid, 39003467a24Schristos &floatformat_ieee_double_little 39103467a24Schristos }; 3928dffb485Schristos 3938dffb485Schristos const struct floatformat floatformat_bfloat16_big = 3948dffb485Schristos { 3958dffb485Schristos floatformat_big, 16, 0, 1, 8, 127, 255, 9, 7, 3968dffb485Schristos floatformat_intbit_no, 3978dffb485Schristos "floatformat_bfloat16_big", 3988dffb485Schristos floatformat_always_valid, 3998dffb485Schristos NULL 4008dffb485Schristos }; 4018dffb485Schristos 4028dffb485Schristos const struct floatformat floatformat_bfloat16_little = 4038dffb485Schristos { 4048dffb485Schristos floatformat_little, 16, 0, 1, 8, 127, 255, 9, 7, 4058dffb485Schristos floatformat_intbit_no, 4068dffb485Schristos "floatformat_bfloat16_little", 4078dffb485Schristos floatformat_always_valid, 4088dffb485Schristos NULL 4098dffb485Schristos }; 41098b9484cSchristos 41198b9484cSchristos #ifndef min 41298b9484cSchristos #define min(a, b) ((a) < (b) ? (a) : (b)) 41398b9484cSchristos #endif 41498b9484cSchristos 41598b9484cSchristos /* Return 1 if any bits are explicitly set in the mantissa of UFROM, 41698b9484cSchristos format FMT, 0 otherwise. */ 41798b9484cSchristos static int 41898b9484cSchristos mant_bits_set (const struct floatformat *fmt, const unsigned char *ufrom) 41998b9484cSchristos { 42098b9484cSchristos unsigned int mant_bits, mant_off; 42198b9484cSchristos int mant_bits_left; 42298b9484cSchristos 42398b9484cSchristos mant_off = fmt->man_start; 42498b9484cSchristos mant_bits_left = fmt->man_len; 42598b9484cSchristos while (mant_bits_left > 0) 42698b9484cSchristos { 42798b9484cSchristos mant_bits = min (mant_bits_left, 32); 42898b9484cSchristos 42998b9484cSchristos if (get_field (ufrom, fmt->byteorder, fmt->totalsize, 43098b9484cSchristos mant_off, mant_bits) != 0) 43198b9484cSchristos return 1; 43298b9484cSchristos 43398b9484cSchristos mant_off += mant_bits; 43498b9484cSchristos mant_bits_left -= mant_bits; 43598b9484cSchristos } 43698b9484cSchristos return 0; 43798b9484cSchristos } 43898b9484cSchristos 43998b9484cSchristos /* Extract a field which starts at START and is LEN bits long. DATA and 44098b9484cSchristos TOTAL_LEN are the thing we are extracting it from, in byteorder ORDER. */ 44198b9484cSchristos static unsigned long 44298b9484cSchristos get_field (const unsigned char *data, enum floatformat_byteorders order, 44398b9484cSchristos unsigned int total_len, unsigned int start, unsigned int len) 44498b9484cSchristos { 44598b9484cSchristos unsigned long result = 0; 44698b9484cSchristos unsigned int cur_byte; 44798b9484cSchristos int lo_bit, hi_bit, cur_bitshift = 0; 44898b9484cSchristos int nextbyte = (order == floatformat_little) ? 1 : -1; 44998b9484cSchristos 45098b9484cSchristos /* Start is in big-endian bit order! Fix that first. */ 45198b9484cSchristos start = total_len - (start + len); 45298b9484cSchristos 45398b9484cSchristos /* Start at the least significant part of the field. */ 45498b9484cSchristos if (order == floatformat_little) 45598b9484cSchristos cur_byte = start / FLOATFORMAT_CHAR_BIT; 45698b9484cSchristos else 45798b9484cSchristos cur_byte = (total_len - start - 1) / FLOATFORMAT_CHAR_BIT; 45898b9484cSchristos 45998b9484cSchristos lo_bit = start % FLOATFORMAT_CHAR_BIT; 46098b9484cSchristos hi_bit = min (lo_bit + len, FLOATFORMAT_CHAR_BIT); 46198b9484cSchristos 46298b9484cSchristos do 46398b9484cSchristos { 46498b9484cSchristos unsigned int shifted = *(data + cur_byte) >> lo_bit; 46598b9484cSchristos unsigned int bits = hi_bit - lo_bit; 46698b9484cSchristos unsigned int mask = (1 << bits) - 1; 46798b9484cSchristos result |= (shifted & mask) << cur_bitshift; 46898b9484cSchristos len -= bits; 46998b9484cSchristos cur_bitshift += bits; 47098b9484cSchristos cur_byte += nextbyte; 47198b9484cSchristos lo_bit = 0; 47298b9484cSchristos hi_bit = min (len, FLOATFORMAT_CHAR_BIT); 47398b9484cSchristos } 47498b9484cSchristos while (len != 0); 47598b9484cSchristos 47698b9484cSchristos return result; 47798b9484cSchristos } 47898b9484cSchristos 47998b9484cSchristos /* Convert from FMT to a double. 48098b9484cSchristos FROM is the address of the extended float. 48198b9484cSchristos Store the double in *TO. */ 48298b9484cSchristos 48398b9484cSchristos void 48498b9484cSchristos floatformat_to_double (const struct floatformat *fmt, 48598b9484cSchristos const void *from, double *to) 48698b9484cSchristos { 48798b9484cSchristos const unsigned char *ufrom = (const unsigned char *) from; 48898b9484cSchristos double dto; 48998b9484cSchristos long exponent; 49098b9484cSchristos unsigned long mant; 49198b9484cSchristos unsigned int mant_bits, mant_off; 49298b9484cSchristos int mant_bits_left; 49398b9484cSchristos 49498b9484cSchristos /* Split values are not handled specially, since the top half has 49598b9484cSchristos the correctly rounded double value (in the only supported case of 49698b9484cSchristos split values). */ 49798b9484cSchristos 49898b9484cSchristos exponent = get_field (ufrom, fmt->byteorder, fmt->totalsize, 49998b9484cSchristos fmt->exp_start, fmt->exp_len); 50098b9484cSchristos 50198b9484cSchristos /* If the exponent indicates a NaN, we don't have information to 50298b9484cSchristos decide what to do. So we handle it like IEEE, except that we 50398b9484cSchristos don't try to preserve the type of NaN. FIXME. */ 50498b9484cSchristos if ((unsigned long) exponent == fmt->exp_nan) 50598b9484cSchristos { 50698b9484cSchristos int nan = mant_bits_set (fmt, ufrom); 50798b9484cSchristos 50898b9484cSchristos /* On certain systems (such as GNU/Linux), the use of the 50998b9484cSchristos INFINITY macro below may generate a warning that cannot be 51098b9484cSchristos silenced due to a bug in GCC (PR preprocessor/11931). The 51198b9484cSchristos preprocessor fails to recognise the __extension__ keyword in 51298b9484cSchristos conjunction with the GNU/C99 extension for hexadecimal 51398b9484cSchristos floating point constants and will issue a warning when 51498b9484cSchristos compiling with -pedantic. */ 51598b9484cSchristos if (nan) 51698b9484cSchristos dto = NAN; 51798b9484cSchristos else 51898b9484cSchristos dto = INFINITY; 51998b9484cSchristos 52098b9484cSchristos if (get_field (ufrom, fmt->byteorder, fmt->totalsize, fmt->sign_start, 1)) 52198b9484cSchristos dto = -dto; 52298b9484cSchristos 52398b9484cSchristos *to = dto; 52498b9484cSchristos 52598b9484cSchristos return; 52698b9484cSchristos } 52798b9484cSchristos 52898b9484cSchristos mant_bits_left = fmt->man_len; 52998b9484cSchristos mant_off = fmt->man_start; 53098b9484cSchristos dto = 0.0; 53198b9484cSchristos 53298b9484cSchristos /* Build the result algebraically. Might go infinite, underflow, etc; 53398b9484cSchristos who cares. */ 53498b9484cSchristos 535a2e2270fSchristos /* For denorms use minimum exponent. */ 536a2e2270fSchristos if (exponent == 0) 537a2e2270fSchristos exponent = 1 - fmt->exp_bias; 538a2e2270fSchristos else 53998b9484cSchristos { 540a2e2270fSchristos exponent -= fmt->exp_bias; 541a2e2270fSchristos 542a2e2270fSchristos /* If this format uses a hidden bit, explicitly add it in now. 543a2e2270fSchristos Otherwise, increment the exponent by one to account for the 544a2e2270fSchristos integer bit. */ 545a2e2270fSchristos 54698b9484cSchristos if (fmt->intbit == floatformat_intbit_no) 54798b9484cSchristos dto = ldexp (1.0, exponent); 54898b9484cSchristos else 54998b9484cSchristos exponent++; 55098b9484cSchristos } 55198b9484cSchristos 55298b9484cSchristos while (mant_bits_left > 0) 55398b9484cSchristos { 55498b9484cSchristos mant_bits = min (mant_bits_left, 32); 55598b9484cSchristos 55698b9484cSchristos mant = get_field (ufrom, fmt->byteorder, fmt->totalsize, 55798b9484cSchristos mant_off, mant_bits); 55898b9484cSchristos 55998b9484cSchristos dto += ldexp ((double) mant, exponent - mant_bits); 56098b9484cSchristos exponent -= mant_bits; 56198b9484cSchristos mant_off += mant_bits; 56298b9484cSchristos mant_bits_left -= mant_bits; 56398b9484cSchristos } 56498b9484cSchristos 56598b9484cSchristos /* Negate it if negative. */ 56698b9484cSchristos if (get_field (ufrom, fmt->byteorder, fmt->totalsize, fmt->sign_start, 1)) 56798b9484cSchristos dto = -dto; 56898b9484cSchristos *to = dto; 56998b9484cSchristos } 57098b9484cSchristos 57198b9484cSchristos static void put_field (unsigned char *, enum floatformat_byteorders, 57298b9484cSchristos unsigned int, 57398b9484cSchristos unsigned int, 57498b9484cSchristos unsigned int, 57598b9484cSchristos unsigned long); 57698b9484cSchristos 57798b9484cSchristos /* Set a field which starts at START and is LEN bits long. DATA and 57898b9484cSchristos TOTAL_LEN are the thing we are extracting it from, in byteorder ORDER. */ 57998b9484cSchristos static void 58098b9484cSchristos put_field (unsigned char *data, enum floatformat_byteorders order, 58198b9484cSchristos unsigned int total_len, unsigned int start, unsigned int len, 58298b9484cSchristos unsigned long stuff_to_put) 58398b9484cSchristos { 58498b9484cSchristos unsigned int cur_byte; 58598b9484cSchristos int lo_bit, hi_bit; 58698b9484cSchristos int nextbyte = (order == floatformat_little) ? 1 : -1; 58798b9484cSchristos 58898b9484cSchristos /* Start is in big-endian bit order! Fix that first. */ 58998b9484cSchristos start = total_len - (start + len); 59098b9484cSchristos 59198b9484cSchristos /* Start at the least significant part of the field. */ 59298b9484cSchristos if (order == floatformat_little) 59398b9484cSchristos cur_byte = start / FLOATFORMAT_CHAR_BIT; 59498b9484cSchristos else 59598b9484cSchristos cur_byte = (total_len - start - 1) / FLOATFORMAT_CHAR_BIT; 59698b9484cSchristos 59798b9484cSchristos lo_bit = start % FLOATFORMAT_CHAR_BIT; 59898b9484cSchristos hi_bit = min (lo_bit + len, FLOATFORMAT_CHAR_BIT); 59998b9484cSchristos 60098b9484cSchristos do 60198b9484cSchristos { 60298b9484cSchristos unsigned char *byte_ptr = data + cur_byte; 60398b9484cSchristos unsigned int bits = hi_bit - lo_bit; 60498b9484cSchristos unsigned int mask = ((1 << bits) - 1) << lo_bit; 60598b9484cSchristos *byte_ptr = (*byte_ptr & ~mask) | ((stuff_to_put << lo_bit) & mask); 60698b9484cSchristos stuff_to_put >>= bits; 60798b9484cSchristos len -= bits; 60898b9484cSchristos cur_byte += nextbyte; 60998b9484cSchristos lo_bit = 0; 61098b9484cSchristos hi_bit = min (len, FLOATFORMAT_CHAR_BIT); 61198b9484cSchristos } 61298b9484cSchristos while (len != 0); 61398b9484cSchristos } 61498b9484cSchristos 61598b9484cSchristos /* The converse: convert the double *FROM to an extended float 61698b9484cSchristos and store where TO points. Neither FROM nor TO have any alignment 61798b9484cSchristos restrictions. */ 61898b9484cSchristos 61998b9484cSchristos void 62098b9484cSchristos floatformat_from_double (const struct floatformat *fmt, 62198b9484cSchristos const double *from, void *to) 62298b9484cSchristos { 62398b9484cSchristos double dfrom; 62498b9484cSchristos int exponent; 62598b9484cSchristos double mant; 62698b9484cSchristos unsigned int mant_bits, mant_off; 62798b9484cSchristos int mant_bits_left; 62898b9484cSchristos unsigned char *uto = (unsigned char *) to; 62998b9484cSchristos 63098b9484cSchristos dfrom = *from; 63198b9484cSchristos memset (uto, 0, fmt->totalsize / FLOATFORMAT_CHAR_BIT); 63298b9484cSchristos 63398b9484cSchristos /* Split values are not handled specially, since a bottom half of 63498b9484cSchristos zero is correct for any value representable as double (in the 63598b9484cSchristos only supported case of split values). */ 63698b9484cSchristos 63798b9484cSchristos /* If negative, set the sign bit. */ 63898b9484cSchristos if (dfrom < 0) 63998b9484cSchristos { 64098b9484cSchristos put_field (uto, fmt->byteorder, fmt->totalsize, fmt->sign_start, 1, 1); 64198b9484cSchristos dfrom = -dfrom; 64298b9484cSchristos } 64398b9484cSchristos 64498b9484cSchristos if (dfrom == 0) 64598b9484cSchristos { 64698b9484cSchristos /* 0.0. */ 64798b9484cSchristos return; 64898b9484cSchristos } 64998b9484cSchristos 65098b9484cSchristos if (dfrom != dfrom) 65198b9484cSchristos { 65298b9484cSchristos /* NaN. */ 65398b9484cSchristos put_field (uto, fmt->byteorder, fmt->totalsize, fmt->exp_start, 65498b9484cSchristos fmt->exp_len, fmt->exp_nan); 65598b9484cSchristos /* Be sure it's not infinity, but NaN value is irrelevant. */ 65698b9484cSchristos put_field (uto, fmt->byteorder, fmt->totalsize, fmt->man_start, 65798b9484cSchristos 32, 1); 65898b9484cSchristos return; 65998b9484cSchristos } 66098b9484cSchristos 66198b9484cSchristos if (dfrom + dfrom == dfrom) 66298b9484cSchristos { 66398b9484cSchristos /* This can only happen for an infinite value (or zero, which we 66498b9484cSchristos already handled above). */ 66598b9484cSchristos put_field (uto, fmt->byteorder, fmt->totalsize, fmt->exp_start, 66698b9484cSchristos fmt->exp_len, fmt->exp_nan); 66798b9484cSchristos return; 66898b9484cSchristos } 66998b9484cSchristos 67098b9484cSchristos mant = frexp (dfrom, &exponent); 67198b9484cSchristos if (exponent + fmt->exp_bias - 1 > 0) 67298b9484cSchristos put_field (uto, fmt->byteorder, fmt->totalsize, fmt->exp_start, 67398b9484cSchristos fmt->exp_len, exponent + fmt->exp_bias - 1); 67498b9484cSchristos else 67598b9484cSchristos { 67698b9484cSchristos /* Handle a denormalized number. FIXME: What should we do for 67798b9484cSchristos non-IEEE formats? */ 67898b9484cSchristos put_field (uto, fmt->byteorder, fmt->totalsize, fmt->exp_start, 67998b9484cSchristos fmt->exp_len, 0); 68098b9484cSchristos mant = ldexp (mant, exponent + fmt->exp_bias - 1); 68198b9484cSchristos } 68298b9484cSchristos 68398b9484cSchristos mant_bits_left = fmt->man_len; 68498b9484cSchristos mant_off = fmt->man_start; 68598b9484cSchristos while (mant_bits_left > 0) 68698b9484cSchristos { 68798b9484cSchristos unsigned long mant_long; 68898b9484cSchristos mant_bits = mant_bits_left < 32 ? mant_bits_left : 32; 68998b9484cSchristos 69098b9484cSchristos mant *= 4294967296.0; 69198b9484cSchristos mant_long = (unsigned long)mant; 69298b9484cSchristos mant -= mant_long; 69398b9484cSchristos 69498b9484cSchristos /* If the integer bit is implicit, and we are not creating a 69598b9484cSchristos denormalized number, then we need to discard it. */ 69698b9484cSchristos if ((unsigned int) mant_bits_left == fmt->man_len 69798b9484cSchristos && fmt->intbit == floatformat_intbit_no 69898b9484cSchristos && exponent + fmt->exp_bias - 1 > 0) 69998b9484cSchristos { 70098b9484cSchristos mant_long &= 0x7fffffff; 70198b9484cSchristos mant_bits -= 1; 70298b9484cSchristos } 70398b9484cSchristos else if (mant_bits < 32) 70498b9484cSchristos { 70598b9484cSchristos /* The bits we want are in the most significant MANT_BITS bits of 70698b9484cSchristos mant_long. Move them to the least significant. */ 70798b9484cSchristos mant_long >>= 32 - mant_bits; 70898b9484cSchristos } 70998b9484cSchristos 71098b9484cSchristos put_field (uto, fmt->byteorder, fmt->totalsize, 71198b9484cSchristos mant_off, mant_bits, mant_long); 71298b9484cSchristos mant_off += mant_bits; 71398b9484cSchristos mant_bits_left -= mant_bits; 71498b9484cSchristos } 71598b9484cSchristos } 71698b9484cSchristos 71798b9484cSchristos /* Return non-zero iff the data at FROM is a valid number in format FMT. */ 71898b9484cSchristos 71998b9484cSchristos int 72098b9484cSchristos floatformat_is_valid (const struct floatformat *fmt, const void *from) 72198b9484cSchristos { 72298b9484cSchristos return fmt->is_valid (fmt, from); 72398b9484cSchristos } 72498b9484cSchristos 72598b9484cSchristos 72698b9484cSchristos #ifdef IEEE_DEBUG 72798b9484cSchristos 72898b9484cSchristos #include <stdio.h> 72998b9484cSchristos 73098b9484cSchristos /* This is to be run on a host which uses IEEE floating point. */ 73198b9484cSchristos 73298b9484cSchristos void 73398b9484cSchristos ieee_test (double n) 73498b9484cSchristos { 73598b9484cSchristos double result; 73698b9484cSchristos 73798b9484cSchristos floatformat_to_double (&floatformat_ieee_double_little, &n, &result); 73898b9484cSchristos if ((n != result && (! isnan (n) || ! isnan (result))) 73998b9484cSchristos || (n < 0 && result >= 0) 74098b9484cSchristos || (n >= 0 && result < 0)) 74198b9484cSchristos printf ("Differ(to): %.20g -> %.20g\n", n, result); 74298b9484cSchristos 74398b9484cSchristos floatformat_from_double (&floatformat_ieee_double_little, &n, &result); 74498b9484cSchristos if ((n != result && (! isnan (n) || ! isnan (result))) 74598b9484cSchristos || (n < 0 && result >= 0) 74698b9484cSchristos || (n >= 0 && result < 0)) 74798b9484cSchristos printf ("Differ(from): %.20g -> %.20g\n", n, result); 74898b9484cSchristos 74998b9484cSchristos #if 0 75098b9484cSchristos { 75198b9484cSchristos char exten[16]; 75298b9484cSchristos 75398b9484cSchristos floatformat_from_double (&floatformat_m68881_ext, &n, exten); 75498b9484cSchristos floatformat_to_double (&floatformat_m68881_ext, exten, &result); 75598b9484cSchristos if (n != result) 75698b9484cSchristos printf ("Differ(to+from): %.20g -> %.20g\n", n, result); 75798b9484cSchristos } 75898b9484cSchristos #endif 75998b9484cSchristos 76098b9484cSchristos #if IEEE_DEBUG > 1 76198b9484cSchristos /* This is to be run on a host which uses 68881 format. */ 76298b9484cSchristos { 76398b9484cSchristos long double ex = *(long double *)exten; 76498b9484cSchristos if (ex != n) 76598b9484cSchristos printf ("Differ(from vs. extended): %.20g\n", n); 76698b9484cSchristos } 76798b9484cSchristos #endif 76898b9484cSchristos } 76998b9484cSchristos 77098b9484cSchristos int 77198b9484cSchristos main (void) 77298b9484cSchristos { 77398b9484cSchristos ieee_test (0.0); 77498b9484cSchristos ieee_test (0.5); 775a2e2270fSchristos ieee_test (1.1); 77698b9484cSchristos ieee_test (256.0); 77798b9484cSchristos ieee_test (0.12345); 77898b9484cSchristos ieee_test (234235.78907234); 77998b9484cSchristos ieee_test (-512.0); 78098b9484cSchristos ieee_test (-0.004321); 78198b9484cSchristos ieee_test (1.2E-70); 78298b9484cSchristos ieee_test (1.2E-316); 78398b9484cSchristos ieee_test (4.9406564584124654E-324); 78498b9484cSchristos ieee_test (- 4.9406564584124654E-324); 78598b9484cSchristos ieee_test (- 0.0); 78698b9484cSchristos ieee_test (- INFINITY); 78798b9484cSchristos ieee_test (- NAN); 78898b9484cSchristos ieee_test (INFINITY); 78998b9484cSchristos ieee_test (NAN); 79098b9484cSchristos return 0; 79198b9484cSchristos } 79298b9484cSchristos #endif 793