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 * Reference: ISO C99 standard 5.2.4
23 #include <babeltrace/ctf/types.h>
25 #include <float.h> /* C99 floating point definitions */
26 #include <limits.h> /* C99 limits */
30 * This library is limited to binary representation of floating point values.
31 * Sign-extension of the exponents is assumed to keep the NaN, +inf, -inf
32 * values, but this should be double-checked (TODO).
36 * Aliasing float/double and unsigned long is not strictly permitted by strict
37 * aliasing, but in practice declaration prunning is well supported, and this permits
38 * us to use per-word read/writes rather than per-byte.
41 #if defined(__GNUC__) || defined(__MINGW32__) || defined(_MSC_VER)
42 #define HAS_TYPE_PRUNING
47 #error "Unsupported floating point radix"
53 #ifdef HAS_TYPE_PRUNING
54 unsigned long bits
[(sizeof(double) + sizeof(unsigned long) - 1) / sizeof(unsigned long)];
56 unsigned char bits
[sizeof(double)];
60 union ldoubleIEEE754
{
62 #ifdef HAS_TYPE_PRUNING
63 unsigned long bits
[(sizeof(long double) + sizeof(unsigned long) - 1) / sizeof(unsigned long)];
65 unsigned char bits
[sizeof(long double)];
69 static struct declaration_float
*static_ldouble_declaration
;
72 size_t sign_start
, exp_start
, mantissa_start
, len
;
75 int _ctf_float_copy(struct stream_pos
*destp
,
76 struct definition_float
*dest_definition
,
77 struct stream_pos
*srcp
,
78 const struct definition_float
*src_definition
)
83 if (src_definition
->declaration
->byte_order
== LITTLE_ENDIAN
) {
84 ret
= ctf_integer_read(srcp
, &src_definition
->mantissa
->p
);
87 ret
= ctf_integer_read(srcp
, &src_definition
->exp
->p
);
90 ret
= ctf_integer_read(srcp
, &src_definition
->sign
->p
);
94 ret
= ctf_integer_read(srcp
, &src_definition
->sign
->p
);
97 ret
= ctf_integer_read(srcp
, &src_definition
->exp
->p
);
100 ret
= ctf_integer_read(srcp
, &src_definition
->mantissa
->p
);
105 dest_definition
->mantissa
->value
._unsigned
=
106 src_definition
->mantissa
->value
._unsigned
;
107 dest_definition
->exp
->value
._signed
=
108 src_definition
->exp
->value
._signed
;
109 dest_definition
->sign
->value
._unsigned
=
110 src_definition
->sign
->value
._unsigned
;
113 if (dest_definition
->declaration
->byte_order
== LITTLE_ENDIAN
) {
114 ret
= ctf_integer_write(destp
, &dest_definition
->mantissa
->p
);
117 ret
= ctf_integer_write(destp
, &dest_definition
->exp
->p
);
120 ret
= ctf_integer_write(destp
, &dest_definition
->sign
->p
);
124 ret
= ctf_integer_write(destp
, &dest_definition
->sign
->p
);
127 ret
= ctf_integer_write(destp
, &dest_definition
->exp
->p
);
130 ret
= ctf_integer_write(destp
, &dest_definition
->mantissa
->p
);
137 int ctf_float_read(struct stream_pos
*ppos
, struct definition
*definition
)
139 struct definition_float
*float_definition
=
140 container_of(definition
, struct definition_float
, p
);
141 const struct declaration_float
*float_declaration
=
142 float_definition
->declaration
;
143 struct ctf_stream_pos
*pos
= ctf_pos(ppos
);
144 union ldoubleIEEE754 u
;
145 struct definition
*tmpdef
=
146 static_ldouble_declaration
->p
.definition_new(&static_ldouble_declaration
->p
,
148 struct definition_float
*tmpfloat
=
149 container_of(tmpdef
, struct definition_float
, p
);
150 struct ctf_stream_pos destp
;
153 ctf_init_pos(&destp
, -1, O_RDWR
);
154 destp
.base
= (char *) u
.bits
;
156 ctf_align_pos(pos
, float_declaration
->p
.alignment
);
157 ret
= _ctf_float_copy(&destp
.parent
, tmpfloat
, ppos
, float_definition
);
158 float_definition
->value
= u
.v
;
159 definition_unref(tmpdef
);
163 int ctf_float_write(struct stream_pos
*ppos
, struct definition
*definition
)
165 struct definition_float
*float_definition
=
166 container_of(definition
, struct definition_float
, p
);
167 const struct declaration_float
*float_declaration
=
168 float_definition
->declaration
;
169 struct ctf_stream_pos
*pos
= ctf_pos(ppos
);
170 union ldoubleIEEE754 u
;
171 struct definition
*tmpdef
=
172 static_ldouble_declaration
->p
.definition_new(&static_ldouble_declaration
->p
,
174 struct definition_float
*tmpfloat
=
175 container_of(tmpdef
, struct definition_float
, p
);
176 struct ctf_stream_pos srcp
;
179 ctf_init_pos(&srcp
, -1, O_RDONLY
);
180 srcp
.base
= (char *) u
.bits
;
182 u
.v
= float_definition
->value
;
183 ctf_align_pos(pos
, float_declaration
->p
.alignment
);
184 ret
= _ctf_float_copy(ppos
, float_definition
, &srcp
.parent
, tmpfloat
);
185 definition_unref(tmpdef
);
189 void __attribute__((constructor
)) ctf_float_init(void)
191 static_ldouble_declaration
=
192 float_declaration_new(LDBL_MANT_DIG
,
193 sizeof(long double) * CHAR_BIT
- LDBL_MANT_DIG
,
195 __alignof__(long double));
198 void __attribute__((destructor
)) ctf_float_fini(void)
200 declaration_unref(&static_ldouble_declaration
->p
);