d8d07feb075935f5dc1a98070a4b7ea7db16075d
[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 LLDBL 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 <string.h>
19 #include <float.h>
20 #include <stdlib.h>
21 #include <stdio.h>
22
23 #ifdef USE_LONG_DOUBLE
24 /* have long double type */
25
26 /* only defined in C99 mode */
27 extern long double strtold(const char *str, char **end);
28
29 #define strtoLLD        strtold
30
31 #else
32 /* don't have long double type */
33
34 extern double strtod(const char *str, char **end);
35
36 #define strtoLLD        strtod
37
38 #endif
39
40 /********
41  * globals
42  ********/
43 static LLDBL value;
44
45 #define CAST_IN(val) (*((LLDBL *)((val))))
46 #define CAST_OUT(val) ((void *)&(val))
47
48 #define CLEAR_BUFFER() memset((char*)&value, 0, sizeof(LLDBL))
49 /********
50  * private functions
51  ********/
52
53 /********
54  * functions defined in fltcalc.h
55  ********/
56 const void *fc_get_buffer(void)
57 {
58   return CAST_OUT(value);
59 }
60
61 const int fc_get_buffer_length(void)
62 {
63   return sizeof(LLDBL);
64 }
65
66 void fc_val_from_str(const char *str, unsigned int len)
67 {
68   CLEAR_BUFFER();
69   value = strtoLLD(str, NULL);
70 }
71
72 void fc_val_from_float(LLDBL l)
73 {
74   CLEAR_BUFFER();
75   value = l;
76 }
77
78 LLDBL fc_val_to_float(const void *val)
79 {
80   return CAST_IN(val);
81 }
82
83 void fc_get_min(unsigned int num_bits)
84 {
85   CLEAR_BUFFER();
86   switch (num_bits)
87   {
88     case 32:
89       value = FLT_MIN;
90       break;
91     case 64:
92       value = DBL_MIN;
93       break;
94     case 80:
95     default:
96       value = LDBL_MIN;
97       break;
98   }
99 }
100
101 void fc_get_max(unsigned int num_bits)
102 {
103   CLEAR_BUFFER();
104   switch (num_bits)
105   {
106     case 32:
107       value = FLT_MAX;
108       break;
109     case 64:
110       value = DBL_MAX;
111       break;
112     case 80:
113     default:
114       value = LDBL_MAX;
115       break;
116   }
117 }
118
119 void fc_get_nan(void)
120 {
121   value = strtoLLD("nan", NULL);
122
123 }
124
125 void fc_get_inf(void)
126 {
127   value = strtoLLD("inf", NULL);
128 }
129
130 void fc_calc(const void *a, const void *b, int opcode)
131 {
132   CLEAR_BUFFER();
133   switch (opcode)
134   {
135     case FC_ADD:
136       value = CAST_IN(a) + CAST_IN(b);
137       break;
138     case FC_SUB:
139       value = CAST_IN(a) - CAST_IN(b);
140       break;
141     case FC_MUL:
142       value = CAST_IN(a) * CAST_IN(b);
143       break;
144     case FC_DIV:
145       value = CAST_IN(a) / CAST_IN(b);
146       break;
147     case FC_NEG:
148       value = -CAST_IN(a);
149       break;
150   }
151 }
152
153 int fc_comp(const void *a, const void *b)
154 {
155   if (CAST_IN(a) == CAST_IN(b)) return 0;
156   else return (CAST_IN(a) > CAST_IN(b))?(1):(-1);
157 }
158
159 char *fc_print_dec(const void *a, char *buf, int buflen)
160 {
161 #ifdef USE_LONG_DOUBLE
162   snprintf(buf, buflen, "%1.30Lg", CAST_IN(a));
163 #else
164   snprintf(buf, buflen, "%1.30g", CAST_IN(a));
165 #endif
166   return buf;
167 }
168
169 unsigned char fc_sub_bits(const void *value, unsigned num_bits, unsigned byte_ofs)
170 {
171   LLDBL val = CAST_IN(value);
172   float f;
173   double d;
174
175   unsigned char *p;
176   unsigned len;
177
178   switch (num_bits) {
179   case 32:
180     f = (float)val;
181     p = (unsigned char *)&f;
182     len = 4;
183     break;
184
185   case 64:
186     d = (double)val;
187     p = (unsigned char *)&d;
188     len = 8;
189     break;
190
191   case 80:
192     p = (unsigned char *)&val;
193     len = 10;
194     break;
195
196   default:
197     return 0;
198   }
199
200   if (byte_ofs > len)
201     return 0;
202   return p[byte_ofs];
203 }