Use mmap_align
[babeltrace.git] / formats / ctf / types / float.c
1 /*
2 * Common Trace Format
3 *
4 * Floating point read/write functions.
5 *
6 * Copyright 2010-2011 EfficiOS Inc. and Linux Foundation
7 *
8 * Author: Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
9 *
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:
16 *
17 * The above copyright notice and this permission notice shall be included in
18 * all copies or substantial portions of the Software.
19 *
20 * Reference: ISO C99 standard 5.2.4
21 */
22
23 #include <babeltrace/ctf/types.h>
24 #include <glib.h>
25 #include <float.h> /* C99 floating point definitions */
26 #include <limits.h> /* C99 limits */
27 #include <babeltrace/endian.h>
28
29 /*
30 * This library is limited to binary representation of floating point values.
31 * We use hardware support for conversion between 32 and 64-bit floating
32 * point values.
33 */
34
35 /*
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.
39 */
40
41 #if defined(__GNUC__) || defined(__MINGW32__) || defined(_MSC_VER)
42 #define HAS_TYPE_PRUNING
43 #endif
44
45 #if (FLT_RADIX != 2)
46
47 #error "Unsupported floating point radix"
48
49 #endif
50
51 union doubleIEEE754 {
52 double vd;
53 float vf;
54 #ifdef HAS_TYPE_PRUNING
55 unsigned long bits[(sizeof(double) + sizeof(unsigned long) - 1) / sizeof(unsigned long)];
56 #else
57 unsigned char bits[sizeof(double)];
58 #endif
59 };
60
61 static struct declaration_float *static_float_declaration,
62 *static_double_declaration;
63
64 struct pos_len {
65 size_t sign_start, exp_start, mantissa_start, len;
66 };
67
68 int _ctf_float_copy(struct stream_pos *destp,
69 struct definition_float *dest_definition,
70 struct stream_pos *srcp,
71 const struct definition_float *src_definition)
72 {
73 int ret;
74
75 /* We only support copy of same-size floats for now */
76 assert(src_definition->declaration->sign->len ==
77 dest_definition->declaration->sign->len);
78 assert(src_definition->declaration->exp->len ==
79 dest_definition->declaration->exp->len);
80 assert(src_definition->declaration->mantissa->len ==
81 dest_definition->declaration->mantissa->len);
82 /* Read */
83 if (src_definition->declaration->byte_order == LITTLE_ENDIAN) {
84 ret = ctf_integer_read(srcp, &src_definition->mantissa->p);
85 if (ret)
86 return ret;
87 ret = ctf_integer_read(srcp, &src_definition->exp->p);
88 if (ret)
89 return ret;
90 ret = ctf_integer_read(srcp, &src_definition->sign->p);
91 if (ret)
92 return ret;
93 } else {
94 ret = ctf_integer_read(srcp, &src_definition->sign->p);
95 if (ret)
96 return ret;
97 ret = ctf_integer_read(srcp, &src_definition->exp->p);
98 if (ret)
99 return ret;
100 ret = ctf_integer_read(srcp, &src_definition->mantissa->p);
101 if (ret)
102 return ret;
103 }
104
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;
111
112 /* Write */
113 if (dest_definition->declaration->byte_order == LITTLE_ENDIAN) {
114 ret = ctf_integer_write(destp, &dest_definition->mantissa->p);
115 if (ret)
116 return ret;
117 ret = ctf_integer_write(destp, &dest_definition->exp->p);
118 if (ret)
119 return ret;
120 ret = ctf_integer_write(destp, &dest_definition->sign->p);
121 if (ret)
122 return ret;
123 } else {
124 ret = ctf_integer_write(destp, &dest_definition->sign->p);
125 if (ret)
126 return ret;
127 ret = ctf_integer_write(destp, &dest_definition->exp->p);
128 if (ret)
129 return ret;
130 ret = ctf_integer_write(destp, &dest_definition->mantissa->p);
131 if (ret)
132 return ret;
133 }
134 return 0;
135 }
136
137 int ctf_float_read(struct stream_pos *ppos, struct definition *definition)
138 {
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 doubleIEEE754 u;
145 struct definition *tmpdef;
146 struct definition_float *tmpfloat;
147 struct ctf_stream_pos destp;
148 struct mmap_align mma;
149 int ret;
150
151 switch (float_declaration->mantissa->len + 1) {
152 case FLT_MANT_DIG:
153 tmpdef = static_float_declaration->p.definition_new(
154 &static_float_declaration->p,
155 NULL, 0, 0, "__tmpfloat");
156 break;
157 case DBL_MANT_DIG:
158 tmpdef = static_double_declaration->p.definition_new(
159 &static_double_declaration->p,
160 NULL, 0, 0, "__tmpfloat");
161 break;
162 default:
163 return -EINVAL;
164 }
165 tmpfloat = container_of(tmpdef, struct definition_float, p);
166 ctf_init_pos(&destp, -1, O_RDWR);
167 mmap_align_set_addr(&mma, (char *) u.bits);
168 destp.base_mma = &mma;
169 destp.packet_size = sizeof(u) * CHAR_BIT;
170 ctf_align_pos(pos, float_declaration->p.alignment);
171 ret = _ctf_float_copy(&destp.parent, tmpfloat, ppos, float_definition);
172 switch (float_declaration->mantissa->len + 1) {
173 case FLT_MANT_DIG:
174 float_definition->value = u.vf;
175 break;
176 case DBL_MANT_DIG:
177 float_definition->value = u.vd;
178 break;
179 default:
180 return -EINVAL;
181 }
182 definition_unref(tmpdef);
183 return ret;
184 }
185
186 int ctf_float_write(struct stream_pos *ppos, struct definition *definition)
187 {
188 struct definition_float *float_definition =
189 container_of(definition, struct definition_float, p);
190 const struct declaration_float *float_declaration =
191 float_definition->declaration;
192 struct ctf_stream_pos *pos = ctf_pos(ppos);
193 union doubleIEEE754 u;
194 struct definition *tmpdef;
195 struct definition_float *tmpfloat;
196 struct ctf_stream_pos srcp;
197 struct mmap_align mma;
198 int ret;
199
200 switch (float_declaration->mantissa->len + 1) {
201 case FLT_MANT_DIG:
202 tmpdef = static_float_declaration->p.definition_new(
203 &static_float_declaration->p,
204 NULL, 0, 0, "__tmpfloat");
205 break;
206 case DBL_MANT_DIG:
207 tmpdef = static_double_declaration->p.definition_new(
208 &static_double_declaration->p,
209 NULL, 0, 0, "__tmpfloat");
210 break;
211 default:
212 return -EINVAL;
213 }
214 tmpfloat = container_of(tmpdef, struct definition_float, p);
215 ctf_init_pos(&srcp, -1, O_RDONLY);
216 mmap_align_set_addr(&mma, (char *) u.bits);
217 srcp.base_mma = &mma;
218 srcp.packet_size = sizeof(u) * CHAR_BIT;
219 switch (float_declaration->mantissa->len + 1) {
220 case FLT_MANT_DIG:
221 u.vf = float_definition->value;
222 break;
223 case DBL_MANT_DIG:
224 u.vd = float_definition->value;
225 break;
226 default:
227 return -EINVAL;
228 }
229 ctf_align_pos(pos, float_declaration->p.alignment);
230 ret = _ctf_float_copy(ppos, float_definition, &srcp.parent, tmpfloat);
231 definition_unref(tmpdef);
232 return ret;
233 }
234
235 void __attribute__((constructor)) ctf_float_init(void)
236 {
237 static_float_declaration =
238 float_declaration_new(FLT_MANT_DIG,
239 sizeof(float) * CHAR_BIT - FLT_MANT_DIG,
240 BYTE_ORDER,
241 __alignof__(float));
242 static_double_declaration =
243 float_declaration_new(DBL_MANT_DIG,
244 sizeof(double) * CHAR_BIT - DBL_MANT_DIG,
245 BYTE_ORDER,
246 __alignof__(double));
247 }
248
249 void __attribute__((destructor)) ctf_float_fini(void)
250 {
251 declaration_unref(&static_float_declaration->p);
252 declaration_unref(&static_double_declaration->p);
253 }
This page took 0.034885 seconds and 5 git commands to generate.