Bitfields: allow per-word read on native endianness
[babeltrace.git] / lib / types / float.c
1 /*
2 * Common Trace Format
3 *
4 * Floating point read/write functions.
5 *
6 * Copyright 2010 - Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
7 *
8 * Reference: ISO C99 standard 5.2.4
9 *
10 * Dual LGPL v2.1/GPL v2 license.
11 */
12
13 #include <ctf/ctf-types.h>
14 #include <glib.h>
15 #include <endian.h>
16
17 /*
18 * Aliasing float/double and unsigned long is not strictly permitted by strict
19 * aliasing, but in practice type prunning is well supported, and this permits
20 * us to use per-word read/writes rather than per-byte.
21 */
22
23 #if defined(__GNUC__) || defined(__MINGW32__) || defined(_MSC_VER)
24 #define HAS_TYPE_PRUNING
25 #endif
26
27 union floatIEEE754 {
28 float v;
29 #ifdef HAS_TYPE_PRUNING
30 unsigned long bits[(sizeof(float) + sizeof(unsigned long) - 1) / sizeof(unsigned long)];
31 #else
32 unsigned char bits[sizeof(float)];
33 #endif
34 };
35
36 union doubleIEEE754 {
37 double v;
38 #ifdef HAS_TYPE_PRUNING
39 unsigned long bits[(sizeof(double) + sizeof(unsigned long) - 1) / sizeof(unsigned long)];
40 #else
41 unsigned char bits[sizeof(double)];
42 #endif
43 };
44
45 double float_read(const uint8_t *ptr, size_t len, int byte_order)
46 {
47 int rbo = (byte_order != __FLOAT_WORD_ORDER); /* reverse byte order */
48
49 switch (len) {
50 case 32:
51 {
52 union floatIEEE754 u;
53 uint32_t tmp;
54
55 if (!rbo)
56 return (double) *(const float *) ptr;
57 /*
58 * Need to reverse byte order. Read the opposite from our
59 * architecture.
60 */
61 if (__FLOAT_WORD_ORDER == LITTLE_ENDIAN) {
62 /* Read big endian */
63 tmp = bitfield_unsigned_read(ptr, 0, 1, BIG_ENDIAN);
64 bitfield_unsigned_write(&u.bits, 31, 1, LITTLE_ENDIAN,
65 tmp);
66 tmp = bitfield_unsigned_read(ptr, 1, 8, BIG_ENDIAN);
67 bitfield_unsigned_write(&u.bits, 23, 8, LITTLE_ENDIAN,
68 tmp);
69 tmp = bitfield_unsigned_read(ptr, 9, 23, BIG_ENDIAN);
70 bitfield_unsigned_write(&u.bits, 0, 23, LITTLE_ENDIAN,
71 tmp);
72 } else {
73 /* Read little endian */
74 tmp = bitfield_unsigned_read(ptr, 31, 1, LITTLE_ENDIAN);
75 bitfield_unsigned_write(&u.bits, 0, 1, BIG_ENDIAN,
76 tmp);
77 tmp = bitfield_unsigned_read(ptr, 23, 8, LITTLE_ENDIAN);
78 bitfield_unsigned_write(&u.bits, 1, 8, BIG_ENDIAN,
79 tmp);
80 tmp = bitfield_unsigned_read(ptr, 0, 23, LITTLE_ENDIAN);
81 bitfield_unsigned_write(&u.bits, 9, 23, BIG_ENDIAN,
82 tmp);
83 }
84 return (double) u.v;
85 }
86 case 64:
87 {
88 union doubleIEEE754 u;
89 uint64_t tmp;
90
91 if (!rbo)
92 return (double) *(const double *) ptr;
93 /*
94 * Need to reverse byte order. Read the opposite from our
95 * architecture.
96 */
97 if (__FLOAT_WORD_ORDER == LITTLE_ENDIAN) {
98 /* Read big endian */
99 tmp = bitfield_unsigned_read(ptr, 0, 1, BIG_ENDIAN);
100 bitfield_unsigned_write(&u.bits, 63, 1, LITTLE_ENDIAN,
101 tmp);
102 tmp = bitfield_unsigned_read(ptr, 1, 11, BIG_ENDIAN);
103 bitfield_unsigned_write(&u.bits, 52, 11, LITTLE_ENDIAN,
104 tmp);
105 tmp = bitfield_unsigned_read(ptr, 12, 52, BIG_ENDIAN);
106 bitfield_unsigned_write(&u.bits, 0, 52, LITTLE_ENDIAN,
107 tmp);
108 } else {
109 /* Read little endian */
110 tmp = bitfield_unsigned_read(ptr, 63, 1, LITTLE_ENDIAN);
111 bitfield_unsigned_write(&u.bits, 0, 1, BIG_ENDIAN,
112 tmp);
113 tmp = bitfield_unsigned_read(ptr, 52, 11, LITTLE_ENDIAN);
114 bitfield_unsigned_write(&u.bits, 1, 11, BIG_ENDIAN,
115 tmp);
116 tmp = bitfield_unsigned_read(ptr, 0, 52, LITTLE_ENDIAN);
117 bitfield_unsigned_write(&u.bits, 12, 52, BIG_ENDIAN,
118 tmp);
119 }
120 return u.v;
121 }
122 default:
123 printf("float read unavailable for size %u\n", len);
124 assert(0);
125 }
126 }
127
128 size_t float_write(uint8_t *ptr, size_t len, int byte_order, double v)
129 {
130 int rbo = (byte_order != __FLOAT_WORD_ORDER); /* reverse byte order */
131
132 if (!ptr)
133 goto end;
134
135 switch (len) {
136 case 32:
137 {
138 union floatIEEE754 u;
139 uint32_t tmp;
140
141 if (!rbo) {
142 *(float *) ptr = (float) v;
143 break;
144 }
145 u.v = v;
146 /*
147 * Need to reverse byte order. Write the opposite from our
148 * architecture.
149 */
150 if (__FLOAT_WORD_ORDER == LITTLE_ENDIAN) {
151 /* Write big endian */
152 tmp = bitfield_unsigned_read(ptr, 31, 1, LITTLE_ENDIAN);
153 bitfield_unsigned_write(&u.bits, 0, 1, BIG_ENDIAN,
154 tmp);
155 tmp = bitfield_unsigned_read(ptr, 23, 8, LITTLE_ENDIAN);
156 bitfield_unsigned_write(&u.bits, 1, 8, BIG_ENDIAN,
157 tmp);
158 tmp = bitfield_unsigned_read(ptr, 0, 23, LITTLE_ENDIAN);
159 bitfield_unsigned_write(&u.bits, 9, 23, BIG_ENDIAN,
160 tmp);
161 } else {
162 /* Write little endian */
163 tmp = bitfield_unsigned_read(ptr, 0, 1, BIG_ENDIAN);
164 bitfield_unsigned_write(&u.bits, 31, 1, LITTLE_ENDIAN,
165 tmp);
166 tmp = bitfield_unsigned_read(ptr, 1, 8, BIG_ENDIAN);
167 bitfield_unsigned_write(&u.bits, 23, 8, LITTLE_ENDIAN,
168 tmp);
169 tmp = bitfield_unsigned_read(ptr, 9, 23, BIG_ENDIAN);
170 bitfield_unsigned_write(&u.bits, 0, 23, LITTLE_ENDIAN,
171 tmp);
172 }
173 break;
174 }
175 case 64:
176 {
177 union doubleIEEE754 u;
178 uint64_t tmp;
179
180 if (!rbo) {
181 *(double *) ptr = v;
182 break;
183 }
184 u.v = v;
185 /*
186 * Need to reverse byte order. Write the opposite from our
187 * architecture.
188 */
189 if (__FLOAT_WORD_ORDER == LITTLE_ENDIAN) {
190 /* Write big endian */
191 tmp = bitfield_unsigned_read(ptr, 63, 1, LITTLE_ENDIAN);
192 bitfield_unsigned_write(&u.bits, 0, 1, BIG_ENDIAN,
193 tmp);
194 tmp = bitfield_unsigned_read(ptr, 52, 11, LITTLE_ENDIAN);
195 bitfield_unsigned_write(&u.bits, 1, 11, BIG_ENDIAN,
196 tmp);
197 tmp = bitfield_unsigned_read(ptr, 0, 52, LITTLE_ENDIAN);
198 bitfield_unsigned_write(&u.bits, 12, 52, BIG_ENDIAN,
199 tmp);
200 } else {
201 /* Write little endian */
202 tmp = bitfield_unsigned_read(ptr, 0, 1, BIG_ENDIAN);
203 bitfield_unsigned_write(&u.bits, 63, 1, LITTLE_ENDIAN,
204 tmp);
205 tmp = bitfield_unsigned_read(ptr, 1, 11, BIG_ENDIAN);
206 bitfield_unsigned_write(&u.bits, 52, 11, LITTLE_ENDIAN,
207 tmp);
208 tmp = bitfield_unsigned_read(ptr, 12, 52, BIG_ENDIAN);
209 bitfield_unsigned_write(&u.bits, 0, 52, LITTLE_ENDIAN,
210 tmp);
211 }
212 break;
213 }
214 default:
215 printf("float write unavailable for size %u\n", len);
216 assert(0);
217 }
218 end:
219 return len;
220 }
This page took 0.034484 seconds and 5 git commands to generate.