Added tarval_sub_bits() fucntion to access the (binary) bitpattern of a tarval.
[libfirm] / ir / tv / fltcalc.c
1 /* fltcalc.c
2  * Authors: Matthias Heil
3  */
4
5 /*
6  * TODO:
7  *
8  * This code uses the C-type long double to respesent floating
9  * point values. This is bad because:
10  *
11  * 1.) It depends on IEEE arithmetic on the compilation engine (hardly a problem)
12  * 2.) The existance on the type and its bits size (may be identical to double or even float)
13  * 3.) Arithmetic operations will be done with "higher order" precision, which might be wrong
14  *
15  * Replace this code ASAP.
16  */
17 #include "fltcalc.h"
18 #include "ieee754.h"
19 #include <string.h>
20 #include <float.h>
21 #include <stdlib.h>
22 #include <stdio.h>
23
24 /********
25  * globals
26  ********/
27 static long double value;
28
29 #define CAST_IN(val) (*((long double *)((val))))
30 #define CAST_OUT(val) ((void *)&(val))
31
32 #define CLEAR_BUFFER() memset((char*)&value, 0, sizeof(long double))
33 /********
34  * private functions
35  ********/
36
37 /********
38  * functions defined in fltcalc.h
39  ********/
40 const void *fc_get_buffer(void)
41 {
42   return CAST_OUT(value);
43 }
44
45 const int fc_get_buffer_length(void)
46 {
47   return sizeof(long double);
48 }
49
50 void fc_val_from_str(const char *str, unsigned int len)
51 {
52   CLEAR_BUFFER();
53   value = strtold(str, NULL);
54 }
55
56 void fc_val_from_float(long double l)
57 {
58   CLEAR_BUFFER();
59   value = l;
60 }
61
62 long double fc_val_to_float(const void *val)
63 {
64   return CAST_IN(val);
65 }
66
67 void fc_get_min(unsigned int num_bits)
68 {
69   CLEAR_BUFFER();
70   switch (num_bits)
71   {
72     case 32:
73       value = FLT_MIN;
74       break;
75     case 64:
76       value = DBL_MIN;
77       break;
78     case 80:
79     default:
80       value = LDBL_MIN;
81       break;
82   }
83 }
84
85 void fc_get_max(unsigned int num_bits)
86 {
87   CLEAR_BUFFER();
88   switch (num_bits)
89   {
90     case 32:
91       value = FLT_MAX;
92       break;
93     case 64:
94       value = DBL_MAX;
95       break;
96     case 80:
97     default:
98       value = LDBL_MAX;
99       break;
100   }
101 }
102
103 void fc_get_nan(void)
104 {
105   /* nan: all exponent bit set, non-zero mantissa. not signalling wheni
106    * msb of mantissa is set (easily found using this struct */
107   union ieee854_long_double ld;
108
109   CLEAR_BUFFER();
110   ld.ieee_nan.negative = 0;
111   ld.ieee_nan.exponent = 0x7FFF;
112   ld.ieee_nan.quiet_nan = 1;
113   ld.ieee_nan.mantissa0 = 42;
114
115   value = ld.d;
116 }
117
118 void fc_get_inf(void)
119 {
120   /* +-inf: all exponent bit set, sign is easy, one is strange XXX */
121   union ieee854_long_double ld;
122
123   CLEAR_BUFFER();
124   ld.ieee_nan.negative = 0;
125   ld.ieee_nan.exponent = 0x7FFF;
126   ld.ieee_nan.quiet_nan = 0;
127   ld.ieee_nan.one = 1;
128   ld.ieee_nan.mantissa0 = 0;
129   ld.ieee_nan.mantissa1 = 0;
130
131   value = ld.d;
132 }
133
134 void fc_calc(const void *a, const void *b, int opcode)
135 {
136   CLEAR_BUFFER();
137   switch (opcode)
138   {
139     case FC_ADD:
140       value = CAST_IN(a) + CAST_IN(b);
141       break;
142     case FC_SUB:
143       value = CAST_IN(a) - CAST_IN(b);
144       break;
145     case FC_MUL:
146       value = CAST_IN(a) * CAST_IN(b);
147       break;
148     case FC_DIV:
149       value = CAST_IN(a) / CAST_IN(b);
150       break;
151     case FC_NEG:
152       value = -CAST_IN(a);
153   }
154 }
155
156 int fc_comp(const void *a, const void *b)
157 {
158   if (CAST_IN(a) == CAST_IN(b)) return 0;
159   else return (CAST_IN(a) > CAST_IN(b))?(1):(-1);
160 }
161
162 char *fc_print_dec(const void *a, char *buf, int buflen)
163 {
164   snprintf(buf, buflen, "%1.30Lg", CAST_IN(a));
165   return buf;
166 }
167
168 unsigned char fc_sub_bits(const void *value, unsigned num_bits, unsigned byte_ofs)
169 {
170   long double val = CAST_IN(value);
171   float f;
172   double d;
173
174   unsigned char *p;
175   unsigned len;
176
177   switch (num_bits) {
178   case 32:
179     f = (float)val;
180     p = (unsigned char *)&f;
181     len = 4;
182     break;
183
184   case 64:
185     d = (double)val;
186     p = (unsigned char *)&d;
187     len = 8;
188     break;
189
190   case 80:
191     p = (unsigned char *)&val;
192     len = 10;
193     break;
194
195   default:
196     return 0;
197   }
198
199   if (byte_ofs > len)
200     return 0;
201   return p[byte_ofs];
202 }