Fixed floting point computation, other small fixes
[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 xxx = *(long double *)(val); printf("CAST to %Lg\n", xxx); xxx; })
30
31 //#define CAST_IN(val) (*((long double *)((val))))
32 #define CAST_OUT(val) ((void *)&(val))
33
34 #define CLEAR_BUFFER() memset((char*)&value, 0, sizeof(long double))
35 /********
36  * private functions
37  ********/
38
39 /********
40  * functions defined in fltcalc.h
41  ********/
42 const void *fc_get_buffer(void)
43 {
44   return CAST_OUT(value);
45 }
46
47 const int fc_get_buffer_length(void)
48 {
49   return sizeof(long double);
50 }
51
52 void fc_val_from_str(const char *str, unsigned int len)
53 {
54   extern long double strtold(const char *str, char **end);
55
56   printf("-> %s\n", str);
57   CLEAR_BUFFER();
58   value = strtold(str, NULL);
59 }
60
61 void fc_val_from_float(long double l)
62 {
63   CLEAR_BUFFER();
64   value = l;
65 }
66
67 long double fc_val_to_float(const void *val)
68 {
69   return CAST_IN(val);
70 }
71
72 void fc_get_min(unsigned int num_bits)
73 {
74   CLEAR_BUFFER();
75   switch (num_bits)
76   {
77     case 32:
78       value = FLT_MIN;
79       break;
80     case 64:
81       value = DBL_MIN;
82       break;
83     case 80:
84     default:
85       value = LDBL_MIN;
86       break;
87   }
88 }
89
90 void fc_get_max(unsigned int num_bits)
91 {
92   CLEAR_BUFFER();
93   switch (num_bits)
94   {
95     case 32:
96       value = FLT_MAX;
97       break;
98     case 64:
99       value = DBL_MAX;
100       break;
101     case 80:
102     default:
103       value = LDBL_MAX;
104       break;
105   }
106 }
107
108 void fc_get_nan(void)
109 {
110   /* nan: all exponent bit set, non-zero mantissa. not signalling wheni
111    * msb of mantissa is set (easily found using this struct */
112   union ieee854_long_double ld;
113
114   CLEAR_BUFFER();
115   ld.ieee_nan.negative = 0;
116   ld.ieee_nan.exponent = 0x7FFF;
117   ld.ieee_nan.quiet_nan = 1;
118   ld.ieee_nan.mantissa0 = 42;
119
120   value = ld.d;
121 }
122
123 void fc_get_inf(void)
124 {
125   /* +-inf: all exponent bit set, sign is easy, one is strange XXX */
126   union ieee854_long_double ld;
127
128   CLEAR_BUFFER();
129   ld.ieee_nan.negative = 0;
130   ld.ieee_nan.exponent = 0x7FFF;
131   ld.ieee_nan.quiet_nan = 0;
132   ld.ieee_nan.one = 1;
133   ld.ieee_nan.mantissa0 = 0;
134   ld.ieee_nan.mantissa1 = 0;
135
136   value = ld.d;
137 }
138
139 void fc_calc(const void *a, const void *b, int opcode)
140 {
141   CLEAR_BUFFER();
142   switch (opcode)
143   {
144     case FC_ADD:
145       value = CAST_IN(a) + CAST_IN(b);
146       break;
147     case FC_SUB:
148       value = CAST_IN(a) - CAST_IN(b);
149       break;
150     case FC_MUL:
151       value = CAST_IN(a) * CAST_IN(b);
152       break;
153     case FC_DIV:
154       value = CAST_IN(a) / CAST_IN(b);
155       break;
156     case FC_NEG:
157       value = -CAST_IN(a);
158       printf("-> NEG %Lg\n", value);
159       break;
160   }
161 }
162
163 int fc_comp(const void *a, const void *b)
164 {
165   if (CAST_IN(a) == CAST_IN(b)) return 0;
166   else return (CAST_IN(a) > CAST_IN(b))?(1):(-1);
167 }
168
169 char *fc_print_dec(const void *a, char *buf, int buflen)
170 {
171   snprintf(buf, buflen, "%1.30Lg", CAST_IN(a));
172   return buf;
173 }
174
175 unsigned char fc_sub_bits(const void *value, unsigned num_bits, unsigned byte_ofs)
176 {
177   long double val = CAST_IN(value);
178   float f;
179   double d;
180
181   unsigned char *p;
182   unsigned len;
183
184   switch (num_bits) {
185   case 32:
186     f = (float)val;
187     p = (unsigned char *)&f;
188     len = 4;
189     break;
190
191   case 64:
192     d = (double)val;
193     p = (unsigned char *)&d;
194     len = 8;
195     break;
196
197   case 80:
198     p = (unsigned char *)&val;
199     len = 10;
200     break;
201
202   default:
203     return 0;
204   }
205
206   if (byte_ofs > len)
207     return 0;
208   return p[byte_ofs];
209 }