4 * Floating point read/write functions.
6 * Copyright 2010-2011 EfficiOS Inc. and Linux Foundation
8 * Author: Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
10 * Permission is hereby granted, free of charge, to any person obtaining a copy
11 * of this software and associated documentation files (the "Software"), to deal
12 * in the Software without restriction, including without limitation the rights
13 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
14 * copies of the Software, and to permit persons to whom the Software is
15 * furnished to do so, subject to the following conditions:
17 * The above copyright notice and this permission notice shall be included in
18 * all copies or substantial portions of the Software.
20 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
21 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
22 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
23 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
24 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
25 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
28 * Reference: ISO C99 standard 5.2.4
31 #include <babeltrace/ctf/types.h>
33 #include <float.h> /* C99 floating point definitions */
34 #include <limits.h> /* C99 limits */
35 #include <babeltrace/endian.h>
39 * This library is limited to binary representation of floating point values.
40 * We use hardware support for conversion between 32 and 64-bit floating
45 * Aliasing float/double and unsigned long is not strictly permitted by strict
46 * aliasing, but in practice declaration prunning is well supported, and this permits
47 * us to use per-word read/writes rather than per-byte.
50 #if defined(__GNUC__) || defined(__MINGW32__) || defined(_MSC_VER)
51 #define HAS_TYPE_PRUNING
56 #error "Unsupported floating point radix"
63 #ifdef HAS_TYPE_PRUNING
64 unsigned long bits
[(sizeof(double) + sizeof(unsigned long) - 1) / sizeof(unsigned long)];
66 unsigned char bits
[sizeof(double)];
71 * This mutex protects the static temporary float and double
72 * declarations (static_float_declaration and static_double_declaration).
74 static pthread_mutex_t float_mutex
= PTHREAD_MUTEX_INITIALIZER
;
76 static struct declaration_float
*static_float_declaration
,
77 *static_double_declaration
;
83 static void float_lock(void)
87 ret
= pthread_mutex_lock(&float_mutex
);
91 static void float_unlock(void)
95 ret
= pthread_mutex_unlock(&float_mutex
);
99 static int _ctf_float_copy(struct bt_stream_pos
*destp
,
100 struct definition_float
*dest_definition
,
101 struct bt_stream_pos
*srcp
,
102 const struct definition_float
*src_definition
)
106 /* We only support copy of same-size floats for now */
107 assert(src_definition
->declaration
->sign
->len
==
108 dest_definition
->declaration
->sign
->len
);
109 assert(src_definition
->declaration
->exp
->len
==
110 dest_definition
->declaration
->exp
->len
);
111 assert(src_definition
->declaration
->mantissa
->len
==
112 dest_definition
->declaration
->mantissa
->len
);
114 if (src_definition
->declaration
->byte_order
== LITTLE_ENDIAN
) {
115 ret
= ctf_integer_read(srcp
, &src_definition
->mantissa
->p
);
118 ret
= ctf_integer_read(srcp
, &src_definition
->exp
->p
);
121 ret
= ctf_integer_read(srcp
, &src_definition
->sign
->p
);
125 ret
= ctf_integer_read(srcp
, &src_definition
->sign
->p
);
128 ret
= ctf_integer_read(srcp
, &src_definition
->exp
->p
);
131 ret
= ctf_integer_read(srcp
, &src_definition
->mantissa
->p
);
136 dest_definition
->mantissa
->value
._unsigned
=
137 src_definition
->mantissa
->value
._unsigned
;
138 dest_definition
->exp
->value
._signed
=
139 src_definition
->exp
->value
._signed
;
140 dest_definition
->sign
->value
._unsigned
=
141 src_definition
->sign
->value
._unsigned
;
144 if (dest_definition
->declaration
->byte_order
== LITTLE_ENDIAN
) {
145 ret
= ctf_integer_write(destp
, &dest_definition
->mantissa
->p
);
148 ret
= ctf_integer_write(destp
, &dest_definition
->exp
->p
);
151 ret
= ctf_integer_write(destp
, &dest_definition
->sign
->p
);
155 ret
= ctf_integer_write(destp
, &dest_definition
->sign
->p
);
158 ret
= ctf_integer_write(destp
, &dest_definition
->exp
->p
);
161 ret
= ctf_integer_write(destp
, &dest_definition
->mantissa
->p
);
168 int ctf_float_read(struct bt_stream_pos
*ppos
, struct bt_definition
*definition
)
170 struct definition_float
*float_definition
=
171 container_of(definition
, struct definition_float
, p
);
172 const struct declaration_float
*float_declaration
=
173 float_definition
->declaration
;
174 struct ctf_stream_pos
*pos
= ctf_pos(ppos
);
175 union doubleIEEE754 u
;
176 struct bt_definition
*tmpdef
;
177 struct definition_float
*tmpfloat
;
178 struct ctf_stream_pos destp
;
179 struct mmap_align mma
;
183 switch (float_declaration
->mantissa
->len
+ 1) {
185 tmpdef
= static_float_declaration
->p
.definition_new(
186 &static_float_declaration
->p
,
187 NULL
, 0, 0, "__tmpfloat");
190 tmpdef
= static_double_declaration
->p
.definition_new(
191 &static_double_declaration
->p
,
192 NULL
, 0, 0, "__tmpfloat");
198 tmpfloat
= container_of(tmpdef
, struct definition_float
, p
);
199 memset(&destp
, 0, sizeof(destp
));
200 ctf_init_pos(&destp
, -1, O_RDWR
);
201 mmap_align_set_addr(&mma
, (char *) u
.bits
);
202 destp
.base_mma
= &mma
;
203 destp
.packet_size
= sizeof(u
) * CHAR_BIT
;
204 ctf_align_pos(pos
, float_declaration
->p
.alignment
);
205 ret
= _ctf_float_copy(&destp
.parent
, tmpfloat
, ppos
, float_definition
);
206 switch (float_declaration
->mantissa
->len
+ 1) {
208 float_definition
->value
= u
.vf
;
211 float_definition
->value
= u
.vd
;
219 bt_definition_unref(tmpdef
);
225 int ctf_float_write(struct bt_stream_pos
*ppos
, struct bt_definition
*definition
)
227 struct definition_float
*float_definition
=
228 container_of(definition
, struct definition_float
, p
);
229 const struct declaration_float
*float_declaration
=
230 float_definition
->declaration
;
231 struct ctf_stream_pos
*pos
= ctf_pos(ppos
);
232 union doubleIEEE754 u
;
233 struct bt_definition
*tmpdef
;
234 struct definition_float
*tmpfloat
;
235 struct ctf_stream_pos srcp
;
236 struct mmap_align mma
;
240 switch (float_declaration
->mantissa
->len
+ 1) {
242 tmpdef
= static_float_declaration
->p
.definition_new(
243 &static_float_declaration
->p
,
244 NULL
, 0, 0, "__tmpfloat");
247 tmpdef
= static_double_declaration
->p
.definition_new(
248 &static_double_declaration
->p
,
249 NULL
, 0, 0, "__tmpfloat");
255 tmpfloat
= container_of(tmpdef
, struct definition_float
, p
);
256 ctf_init_pos(&srcp
, -1, O_RDONLY
);
257 mmap_align_set_addr(&mma
, (char *) u
.bits
);
258 srcp
.base_mma
= &mma
;
259 srcp
.packet_size
= sizeof(u
) * CHAR_BIT
;
260 switch (float_declaration
->mantissa
->len
+ 1) {
262 u
.vf
= float_definition
->value
;
265 u
.vd
= float_definition
->value
;
271 ctf_align_pos(pos
, float_declaration
->p
.alignment
);
272 ret
= _ctf_float_copy(ppos
, float_definition
, &srcp
.parent
, tmpfloat
);
275 bt_definition_unref(tmpdef
);
282 void __attribute__((constructor
)) ctf_float_init(void)
284 static_float_declaration
=
285 bt_float_declaration_new(FLT_MANT_DIG
,
286 sizeof(float) * CHAR_BIT
- FLT_MANT_DIG
,
289 static_double_declaration
=
290 bt_float_declaration_new(DBL_MANT_DIG
,
291 sizeof(double) * CHAR_BIT
- DBL_MANT_DIG
,
293 __alignof__(double));
297 void __attribute__((destructor
)) ctf_float_fini(void)
299 bt_declaration_unref(&static_float_declaration
->p
);
300 bt_declaration_unref(&static_double_declaration
->p
);