1.2.3. 创建浮点常量节点
在GCC中表示浮点常量的节点是下面所示的tree_real_cst。
1.2.3.1. tree_real_cst节点
702 struct tree_real_cst GTY(()) in tree.h
703 {
704 struct tree_common common;
705 struct real_value * real_cst_ptr;
706 };
节点tree_real_cst的核心是real_value,它根据有关的标准定义了浮点值。
43 struct real_value GTY(()) in real.h
44 {
45 ENUM_BITFIELD (real_value_class) class : 2;
46 unsigned int sign : 1;
47 unsigned int signalling : 1;
48 unsigned int canonical : 1;
49 signed int exp : EXP_BITS;
50 unsigned long sig[SIGSZ];
51 };
52
53 /* Various headers condition prototypes on #ifdef REAL_VALUE_TYPE, so it
54 needs to be a macro. We do need to continue to have a structure tag
55 so that other headers can forward declare it. */
56 #define REAL_VALUE_TYPE struct real_value
在上面的定义中,使用了下面的用于实数值的宏。
37 #define SIGNIFICAND_BITS (128 + HOST_BITS_PER_LONG) in real.h
38 #define EXP_BITS (32 - 5)
39 #define MAX_EXP ((1 << (EXP_BITS - 1)) - 1)
40 #define SIGSZ (SIGNIFICAND_BITS / HOST_BITS_PER_LONG)
41 #define SIG_MSB ((unsigned long)1 << (HOST_BITS_PER_LONG - 1))
可见,在real_value结构中,域is close resembel to float format. Theexp是指数部分,域sig是有效位部分。
1.2.3.1.1. 从real_value创建节点
从real_value创建REAL_CST节点是个直截了当的过程。
466 tree
467 build_real (tree type, REAL_VALUE_TYPE d) in tree.c
468 {
469 tree v;
470 REAL_VALUE_TYPE *dp;
471 int overflow = 0;
472
473 /* ??? Used to check for overflow here via CHECK_FLOAT_TYPE.
474 Consider doing it via real_convert now. */
475
476 v = make_node (REAL_CST);
477 dp = ggc_alloc (sizeof (REAL_VALUE_TYPE));
478 memcpy (dp, &d, sizeof (REAL_VALUE_TYPE));
479
480 TREE_TYPE (v) = type;
481 TREE_REAL_CST_PTR (v) = dp;
482 TREE_OVERFLOW (v) = TREE_CONSTANT_OVERFLOW (v) = overflow;
483 return v;
484 }
注意481行,在tree_real_cst节点中,域TREE_REAL_CST_PTR指向被创建的real_value对象。
1.2.3.1.2. 从整型常量创建节点
C/C++语言中,在算术表达式里,有所谓的操作数类型提升。在浮点数与整数的算术计算中,整数需要被类型提升至浮点数。这个类型提升由下面的函数执行。
507 tree
508 build_real_from_int_cst (tree type, tree i) in tree.c
509 {
510 tree v;
511 int overflow = TREE_OVERFLOW (i);
512
513 v = build_real (type, real_value_from_int_cst (type, i));
514
515 TREE_OVERFLOW (v) |= overflow;
516 TREE_CONSTANT_OVERFLOW (v) |= overflow;
517 return v;
518 }
1.2.3.1.2.1. 从整型常量构建real_value
从整型常量构建代表浮点值的real_value不是容易的事情。在这里入口的函数是real_value_from_int_cst。
489 REAL_VALUE_TYPE
490 real_value_from_int_cst (tree type, tree i) in tree.c
491 {
492 REAL_VALUE_TYPE d;
493
494 /* Clear all bits of the real value type so that we can later do
495 bitwise comparisons to see if two values are the same. */
496 memset (&d, 0, sizeof d);
497
498 real_from_integer (&d, type ? TYPE_MODE (type) : VOIDmode,
499 TREE_INT_CST_LOW (i), TREE_INT_CST_HIGH (i),
500 TREE_UNSIGNED (TREE_TYPE (i)));
501 return d;
502 }
真正的转换由函数real_from_integer实现。
1957 void
1958 real_from_integer (REAL_VALUE_TYPE *r, enum machine_mode mode, in real.c
1959 unsigned HOST_WIDE_INT low, HOST_WIDE_INT high,
1960 int unsigned_p)
1961 {
1962 if (low == 0 && high == 0)
1963 get_zero (r, 0);
对于常量0,构建很简单。注意到传入的sign被固定成0。
128 static inline void
129 get_zero (REAL_VALUE_TYPE *r, int sign) in real.c
130 {
131 memset (r, 0, sizeof (*r));
132 r->sign = sign;
133 }
对于其他实数常量,正如我们所了解的,浮点数的精度是有限的,同样可以表达的最大最小值也是有限的。因此real_value中域class用于区分各种情况,它可以是下列值:rvc_zero,rvc_normal,rvc_inf,rvc_nan,其中,inf表示无穷,nan表示非有效值,它可由0除0产生。
对于非0的值,real_from_integer进行以下操作。
real_from_integer (continue)
1965 else
1966 {
1967 memset (r, 0, sizeof (*r));
1968 r->class = rvc_normal;
1969 r->sign = high < 0 && !unsigned_p;
1970 r->exp = 2 * HOST_BITS_PER_WIDE_INT;
1971
1972 if (r->sign)
1973 {
1974 high = ~high;
1975 if (low == 0)
1976 high += 1;
1977 else
1978 low = -low;
1979 }
1980
1981 if (HOST_BITS_PER_LONG == HOST_BITS_PER_WIDE_INT)
1982 {
1983 r->sig[SIGSZ-1] = high;
1984 r->sig[SIGSZ-2] = low;
1985 }
1986 else if (HOST_BITS_PER_LONG*2 == HOST_BITS_PER_WIDE_INT)
1987 {
1988 r->sig[SIGSZ-1] = high >> (HOST_BITS_PER_LONG - 1) >> 1;
1989 r->sig[SIGSZ-2] = high;
1990 r->sig[SIGSZ-3] = low >> (HOST_BITS_PER_LONG - 1) >> 1;
1991 r->sig[SIGSZ-4] = low;
1992 }
1993 else
1994 abort ();
1995
1996 normalize (r);
1997 }
1998
1999 if (mode != VOIDmode)
2000 real_convert (r, mode, r);
2001 }
注意从1972到1979行的代码,它使用了2进制补码,exp的初始值是2 * HOST_BITS_PER_WIDE_INT (在x86/Linux下,它是128)。
1.2.3.1.2.2. 生成值的规范化
域sig保存了值的有效位,但是我们希望值由尽可能的精度,这是所谓的规范化(例如,对于0.000001,由于浮点格式已指定了固定的若干位用于指数部分和尾数部分,因此,如果将它改为1.000000*10-6,那么在使用同样多的位数的情况下,表达的精度提高了1000000倍)。因此,我们需要函数normalize。
477 static void
478 normalize (REAL_VALUE_TYPE *r) in real.c
479 {
480 int shift = 0, exp;
481 int i, j;
482
483 /* Find the first word that is nonzero. */
484 for (i = SIGSZ- 1; i >= 0; i--)
485 if (r->sig[i] == 0)
486 shift += HOST_BITS_PER_LONG;
487 else
488 break;
489
490 /* Zero significand flushes to zero. */
491 if (i < 0)
492 {
493 r->class = rvc_zero;
494 r->exp = 0;
495 return;
496 }
497
498 /* Find the first bit that is nonzero. */
499 for (j = 0; ; j++)
500 if (r->sig[i] & ((unsigned long)1 << (HOST_BITS_PER_LONG - 1 - j)))
501 break;
502 shift += j;
503
504 if (shift > 0)
505 {
506 exp = r->exp - shift;
507 if (exp > MAX_EXP)
508 get_inf (r, r->sign);
509 else if (exp < -MAX_EXP)
510 get_zero (r, r->sign);
511 else
512 {
513 r->exp = exp;
514 lshift_significand (r, r, shift);
515 }
516 }
517 }
记得对于整型常量,我们首先为域exp填入128。这一步是经过深思熟虑的。比如,对于常量1,域exp是1(显然,它表示值整数部分的比特数),这个值1将被移到数字串的最左端,跟着小数点后的长串0。
236 static void
237 lshift_significand (REAL_VALUE_TYPE *r, in real.c
238 const REAL_VALUE_TYPE *a, unsigned int n)
239 {
240 unsigned int i, ofs = n / HOST_BITS_PER_LONG;
241
242 n &= HOST_BITS_PER_LONG - 1;
243 if (n == 0)
244 {
245 for (i = 0; ofs + i < SIGSZ; ++i)
246 r->sig[SIGSZ-1-i] = a->sig[SIGSZ-1-i-ofs];
247 for (; i < SIGSZ; ++i)
248 r->sig[SIGSZ-1-i] = 0;
249 }
250 else
251 for (i = 0; i < SIGSZ; ++i)
252 {
253 r->sig[SIGSZ-1-i]
254 = (((ofs + i >= SIGSZ? 0 : a->sig[SIGSZ-1-i-ofs]) << n)
255 | ((ofs + i + 1 >= SIGSZ? 0 : a->sig[SIGSZ-1-i-ofs-1])
256 >> (HOST_BITS_PER_LONG - n)));
257 }
258 }
函数lshift_significand不复杂,它按照要求向左移动比特位。
1.2.3.1.2.3. 转换到实数模式
虽然我们已经将整型常量放入real_value节点,它仍然是整型,和任何的浮点机器模式都不匹配。因此,我们需要进一步将值转换成机器模式所定义的格式。函数real_convert展示了这一过程。
2368 void
2369 real_convert (REAL_VALUE_TYPE *r, enum machine_mode mode, in real.c
2370 const REAL_VALUE_TYPE *a)
2371 {
2372 const struct real_format *fmt;
2373
2374 fmt = REAL_MODE_FORMAT (mode);
2375 if (fmt == NULL)
2376 abort ();
2377
2378 *r = *a;
2379 round_for_format (fmt, r);
2380
2381 /* round_for_format de-normalizes denormals. Undo just that part. */
2382 if (r->class == rvc_normal)
2383 normalize (r);
2384 }
149 #define REAL_MODE_FORMAT(MODE) (real_format_for_mode[(MODE)-MIN_MODE_FLOAT])
在REAL_MODE_FORMAT的定义中,real_format_for_mode是一个类型为real_format的全局数组。它记录了特定模式到浮点数转换的细节。它在machmode.def中被初始化,在当前版本中,它包含了2个格式,ieee_single_format和&ieee_double_format。 对于其他浮点格式,这个数组要被函数process_options 通过选项OVERRIDE_OPTIONS来改写。
106 struct real_format in real.h
107 {
108 /* Move to and from the target bytes. */
109 void (*encode) (const struct real_format *, long *,
110 const REAL_VALUE_TYPE *);
111 void (*decode) (const struct real_format *, REAL_VALUE_TYPE *,
112 const long *);
113
114 /* The radix of the exponent and digits of the significand. */
115 int b;
116
117 /* log2(b). */
118 int log2_b;
119
120 /* Size of the significand in digits of radix B. */
121 int p;
122
123 /* Size of the significant of a NaN, in digits of radix B. */
124 int pnan;
125
126 /* The minimum negative integer, x, such that b**(x-1) is normalized. */
127 int emin;
128
129 /* The maximum integer, x, such that b**(x-1) is representable. */
130 int emax;
131
132 /* The bit position of the sign bit, or -1 for a complex encoding. */
133 int signbit;
134
135 /* Properties of the format. */
136 bool has_nans;
137 bool has_inf;
138 bool has_denorm;
139 bool has_signed_zero;
140 bool qnan_msb_set;
141 };
由于域b,real_format 实际上可以支持小数点出现在任一地方。对于ieee_single_format和&ieee_double_format我们有:
2652 const struct real_format ieee_single_format = in real.c
2653 {
2654 encode_ieee_single,
2655 decode_ieee_single,
2656 2,
2657 1,
2658 24,
2659 24,
2660 -125,
2661 128,
2662 31,
2663 true,
2664 true,
2665 true,
2666 true,
2667 true
2668 };
2875 const struct real_format ieee_double_format = in real.c
2876 {
2877 encode_ieee_double,
2878 decode_ieee_double,
2879 2,
2880 1,
2881 53,
2882 53,
2883 -1021,
2884 1024,
2885 63,
2886 true,
2887 true,
2888 true,
2889 true,
2890 true
2891 };
有了上面的了解,函数round_for_format虽然长,但不难理解。既然我们保留了若干的位数作为尾数(significand),为了使值尽可能的精确,我们应该尽量地使用这些位。因此以下将执行必要的位移。
2236 static void
2237 round_for_format (const struct real_format *fmt, REAL_VALUE_TYPE *r) in real.c
2238 {
2239 int p2, np2, i, w;
2240 unsigned long sticky;
2241 bool guard, lsb;
2242 int emin2m1, emax2;
2243
2244 p2 = fmt->p * fmt->log2_b;
2245 emin2m1 = (fmt->emin - 1) * fmt->log2_b;
2246 emax2 = fmt->emax * fmt->log2_b;
2247
2248 np2 = SIGNIFICAND_BITS - p2;
2249 switch (r->class)
2250 {
2251 underflow:
2252 get_zero (r, r->sign);
2253 case rvc_zero:
2254 if (!fmt->has_signed_zero)
2255 r->sign = 0;
2256 return;
2257
2258 overflow:
2259 get_inf (r, r->sign);
2260 case rvc_inf:
2261 return;
2262
2263 case rvc_nan:
2264 clear_significand_below (r, np2);
2265 return;
2266
2267 case rvc_normal:
2268 break;
2269
2270 default:
2271 abort ();
2272 }
2273
2274 /* If we're not base2, normalize the exponent to a multiple of
2275 the true base. */
2276 if (fmt->log2_b != 1)
2277 {
2278 int shift = r->exp & (fmt->log2_b - 1);
2279 if (shift)
2280 {
2281 shift = fmt->log2_b - shift;
2282 r->sig[0] |= sticky_rshift_significand (r, r, shift);
2283 r->exp += shift;
2284 }
2285 }
2286
2287 /* Check the range of the exponent. If we're out of range,
2288 either underflow or overflow. */
2289 if (r->exp > emax2)
2290 goto overflow;
2291 else if (r->exp <= emin2m1)
2292 {
2293 int diff;
2294
2295 if (!fmt->has_denorm)
2296 {
2297 /* Don't underflow completely until we've had a chance to round. */
2298 if (r->exp < emin2m1)
2299 goto underflow;
2300 }
2301 else
2302 {
2303 diff = emin2m1 - r->exp + 1;
2304 if (diff > p2)
2305 goto underflow;
2306
2307 /* De-normalize the significand. */
2308 r->sig[0] |= sticky_rshift_significand (r, r, diff);
2309 r->exp += diff;
2310 }
2311 }
考虑到我们使用的格式可能不是基于2进制的(假设为base进制),real_format中的域log2_b记录了log2(base),而域p记录了尾数以base进制表达的位数,因此在上面的2244行将尾数转换为2进制数。而2245,2246行相应地算出最大最小值。
我们已经看到,real_value的域exp是值以2进制表达的指数(exponential)部分。如果目标格式不是2进制,而且它的指数部分与2进制的尾数部分有重叠,我们需要通过sticky_rshift_significand对尾数做右移以解决重叠。另外,如果指数部分已溢出,也只有牺牲精度,对尾数右移。
168 static bool
169 sticky_rshift_significand (REAL_VALUE_TYPE *r, in real.c
170 const REAL_VALUE_TYPE *a, unsigned int n)
171 {
172 unsigned long sticky = 0;
173 unsigned int i, ofs = 0;
174
175 if (n >= HOST_BITS_PER_LONG)
176 {
177 for (i = 0, ofs = n / HOST_BITS_PER_LONG; i < ofs; ++i)
178 sticky |= a->sig[i];
179 n &= HOST_BITS_PER_LONG - 1;
180 }
181
182 if (n != 0)
183 {
184 sticky |= a->sig[ofs] & (((unsigned long)1 << n) - 1);
185 for (i = 0; i < SIGSZ; ++i)
186 {
187 r->sig[i]
188 = (((ofs + i >= SIGSZ? 0 : a->sig[ofs + i]) >> n)
189 | ((ofs + i + 1 >= SIGSZ? 0 : a->sig[ofs + i + 1])
190 << (HOST_BITS_PER_LONG - n)));
191 }
192 }
193 else
194 {
195 for (i = 0; ofs + i < SIGSZ; ++i)
196 r->sig[i] = a->sig[ofs + i];
197 for (; i < SIGSZ; ++i)
198 r->sig[i] = 0;
199 }
200
201 return sticky != 0;
202 }
如果任一比特被移出,sticky_rshift_significand将返回true。这个返回值(这里为1)会和目标格式的尾数部分的最低位(the least significant bit)进行异或。显然,这个取整操作会减少精度。
然而,如果指数部分超出了目标格式能表达的最大值时,毫无疑问发生了溢出。另外,如果指数部分小于目标格式的规范化的最小值时,所做的操作取决于目标格式是否支持去规范化(denormalize)。对于支持去规范化的格式,如果尾数部分仍然有效,则调用sticky_rshift_significand进行去规范化。
round_for_format (continue)
2313 /* There are P2 true significand bits, followed by one guard bit,
2314 followed by one sticky bit, followed by stuff. Fold nonzero
2315 stuff into the sticky bit. */
2316
2317 sticky = 0;
2318 for (i = 0, w = (np2 - 1) / HOST_BITS_PER_LONG; i < w; ++i)
2319 sticky |= r->sig[i];
2320 sticky |=
2321 r->sig[w] & (((unsigned long)1 << ((np2 - 1) % HOST_BITS_PER_LONG)) - 1);
2322
2323 guard = test_significand_bit (r, np2 - 1);
2324 lsb = test_significand_bit (r, np2);
2325
2326 /* Round to even. */
2327 if (guard && (sticky || lsb))
2328 {
2329 REAL_VALUE_TYPE u;
2330 get_zero (&u, 0);
2331 set_significand_bit (&u, np2);
2332
2333 if (add_significands (r, r, &u))
2334 {
2335 /* Overflow. Means the significand had been all ones, and
2336 is now all zeros. Need to increase the exponent, and
2337 possibly re-normalize it. */
2338 if (++r->exp > emax2)
2339 goto overflow;
2340 r->sig[SIGSZ-1] = SIG_MSB;
2341
2342 if (fmt->log2_b != 1)
2343 {
2344 int shift = r->exp & (fmt->log2_b - 1);
2345 if (shift)
2346 {
2347 shift = fmt->log2_b - shift;
2348 rshift_significand (r, r, shift);
2349 r->exp += shift;
2350 if (r->exp > emax2)
2351 goto overflow;
2352 }
2353 }
2354 }
2355 }
2356
2357 /* Catch underflow that we deferred until after rounding. */
2358 if (r->exp <= emin2m1)
2359 goto underflow;
2360
2361 /* Clear out trailing garbage. */
2362 clear_significand_below (r, np2);
2363 }
上面的代码处理由于不同小数点位导致的位移。而round_for_format的最后部分处理不同大小的尾数部分。我们已经看过,对于real_value,用于尾数部分的比特数很大,为128 + HOST_BITS_PER_LONG(对于Linux/x86,它是192),而浮点格式使用比特数要少一些。因此把real_value转换到浮点格式,值截取是需要仔细考虑的问题。
注意在2324行,在np2位的是被截取掉的最高位,在2323行guard则是被截取掉的次高位。作为好的截取方法,如果被截取掉的值大于guard,我们需要通过为截取后的值加上1。函数add_significands完成这个加1操作。
275 static inline bool
276 add_significands (REAL_VALUE_TYPE *r, const REAL_VALUE_TYPE *a, in real.c
277 const REAL_VALUE_TYPE *b)
278 {
279 bool carry = false;
280 int i;
281
282 for (i = 0; i < SIGSZ; ++i)
283 {
284 unsigned long ai = a->sig[i];
285 unsigned long ri = ai + b->sig[i];
286
287 if (carry)
288 {
289 carry = ri < ai;
290 carry |= ++ri == 0;
291 }
292 else
293 carry = ri < ai;
294
295 r->sig[i] = ri;
296 }
297
298 return carry;
299 }
因为尾数被看作无符号数,如果上述的和小于其操作数,表明发生了进位,carry被设置。如果最终和带有进位,我们需要调整指数部分。在这里我们为指数部分的值加上1。如果指数部分原有值为全1,则发生了溢出。如果没有溢出,就要从2340行开始对这个值重新规范化(re-normalize)。