函数build1类似于build,但用于一元操作符。它用于代替相当一部分的build调用。减少对于RISC机器来说相当昂贵的可变参量的使用。
2411 tree
2412 build1 (enum tree_code code, tree type, tree node) in tree.c
2413 {
2414 int length = sizeof (struct tree_exp);
2415 #ifdef GATHER_STATISTICS
2416 tree_node_kind kind;
2417 #endif
2418 tree t;
2419
2420 #ifdef GATHER_STATISTICS
2421 switch (TREE_CODE_CLASS (code))
2422 {
2423 case 's': /* an expression with side effects */
2424 kind = s_kind;
2425 break;
2426 case 'r': /* a reference */
2427 kind = r_kind;
2428 break;
2429 default:
2430 kind = e_kind;
2431 break;
2432 }
2433
2434 tree_node_counts[(int) kind]++;
2435 tree_node_sizes[(int) kind] += length;
2436 #endif
2437
2438 #ifdef ENABLE_CHECKING
2439 if (TREE_CODE_CLASS (code) == '2'
2440 || TREE_CODE_CLASS (code) == '<'
2441 || TREE_CODE_LENGTH (code) != 1)
2442 abort ();
2443 #endif /* ENABLE_CHECKING */
2444
2445 t = ggc_alloc_tree (length);
2446
2447 memset (t, 0, sizeof (struct tree_common));
2448
2449 TREE_SET_CODE (t, code);
2450
2451 TREE_TYPE (t) = type;
2452 TREE_COMPLEXITY (t) = 0;
2453 TREE_OPERAND (t, 0) = node;
2454 if (node && first_rtl_op (code) != 0)
2455 {
2456 TREE_SIDE_EFFECTS (t) = TREE_SIDE_EFFECTS (node);
2457 TREE_READONLY (t) = TREE_READONLY (node);
2458 }
2459
2460 if (TREE_CODE_CLASS (code) == 's')
2461 TREE_SIDE_EFFECTS (t) = 1;
2462 else switch (code)
2463 {
2464 case INIT_EXPR:
2465 case MODIFY_EXPR:
2466 case VA_ARG_EXPR:
2467 case RTL_EXPR:
2468 case PREDECREMENT_EXPR:
2469 case PREINCREMENT_EXPR:
2470 case POSTDECREMENT_EXPR:
2471 case POSTINCREMENT_EXPR:
2472 /* All of these have side-effects, no matter what their
2473 operands are. */
2474 TREE_SIDE_EFFECTS (t) = 1;
2475 TREE_READONLY (t) = 0;
2476 break;
2477
2478 case INDIRECT_REF:
2479 /* Whether a dereference is readonly has nothing to do with whether
2480 its operand is readonly. */
2481 TREE_READONLY (t) = 0;
2482 break;
2483
2484 case ADDR_EXPR:
2485 if (node)
2486 {
2487 /* The address of a volatile decl or reference does not have
2488 side-effects. But be careful not to ignore side-effects from
2489 other sources deeper in the expression--if node is a _REF and
2490 one of its operands has side-effects, so do we. */
2491 if (TREE_THIS_VOLATILE (node))
2492 {
2493 TREE_SIDE_EFFECTS (t) = 0;
2494 if (!DECL_P (node))
2495 {
2496 int i = first_rtl_op (TREE_CODE (node)) - 1;
2497 for (; i >= 0; --i)
2498 {
2499 if (TREE_SIDE_EFFECTS (TREE_OPERAND (node, i)))
2500 TREE_SIDE_EFFECTS (t) = 1;
2501 }
2502 }
2503 }
2504 }
2505 break;
2506
2507 default:
2508 if (TREE_CODE_CLASS (code) == '1' && node && TREE_CONSTANT (node))
2509 TREE_CONSTANT (t) = 1;
2510 break;
2511 }
2512
2513 return t;
2514 }
在上面2460行,树类别码‘s’表明一个有副作用,但其值不被关注的语句(statement)。
函数build_decl被用于创建tree_decl类型节点,该节点用于表示声明。注意下面的2565行,在目标文件中,函数定义将被放于代码段。而我们对函数的调用,则会编译成一条跳转语句和相关的进出栈或寄存器操作指令。它类似于指针,因此函数声明所对应的函数模式(FUNCTION_MODE),在目标机器上,通常等同于指针的模式。
2547 tree
2548 build_decl (enum tree_code code, tree name, tree type) in tree.c
2549 {
2550 tree t;
2551
2552 t = make_node (code);
2553
2554 /* if (type == error_mark_node)
2555 type = integer_type_node; */
2556 /* That is not done, deliberately, so that having error_mark_node
2557 as the type can suppress useless errors in the use of this variable. */
2558
2559 DECL_NAME (t) = name;
2560 TREE_TYPE (t) = type;
2561
2562 if (code == VAR_DECL || code == PARM_DECL || code == RESULT_DECL)
2563 layout_decl (t, 0);
2564 else if (code == FUNCTION_DECL)
2565 DECL_MODE (t) = FUNCTION_MODE;
2566
2567 return t;
2568 }
在上面看到,对于VAR_DECL,PARM_DECL和RESULT_DECL节点需要特别的处理。 因此,我们首先看一下PARM_DECL和RESULT_DECL节点是什么。
PARM_DECL[2]
² 用于表示函数的一个形参。其处理类似于VAR_DECL节点。该节点只出现在FUNCTION_DECL的DECL_ARGUMENTS域中。其DECL_ARG_TYPE域是当向这个函数传入一个值时,这个值所实际对应的类型。它可能是比形参的类型更宽(wider)的类型。例如,形参类型是short而DECL_ARG_TYPE是int。
RESULT_DECL[2]
² 这个节点表示函数的返回值。如果一个值被赋予RESULT_DECL,就意味着函数将以按位拷贝(bitwise copy)的方式返回这个值。你可以向对待VAR_DECL那样,用宏DECL_SIZE和DECL_ALIGN访问RESULT_DECL 节点。
对于VAR_DECL,PARM_DECL和RESULT_DECL,它们需要在节点中设置大小,模式和对齐量,这些信息。
352 void
353 layout_decl (tree decl, unsigned int known_align) in stor-layout.c
354 {
355 tree type = TREE_TYPE (decl);
356 enum tree_code code = TREE_CODE (decl);
357 rtx rtl = NULL_RTX;
358
359 if (code == CONST_DECL)
360 return;
361 else if (code != VAR_DECL && code != PARM_DECL && code != RESULT_DECL
362 && code != TYPE_DECL && code != FIELD_DECL)
363 abort ();
364
365 rtl = DECL_RTL_IF_SET (decl);
366
367 if (type == error_mark_node)
368 type = void_type_node;
369
370 /* Usually the size and mode come from the data type without change,
371 however, the front-end may set the explicit width of the field, so its
372 size may not be the same as the size of its type. This happens with
373 bitfields, of course (an `int' bitfield may be only 2 bits, say), but it
374 also happens with other fields. For example, the C++ front-end creates
375 zero-sized fields corresponding to empty base classes, and depends on
376 layout_type setting DECL_FIELD_BITPOS correctly for the field. Set the
377 size in bytes from the size in bits. If we have already set the mode,
378 don't set it again since we can be called twice for FIELD_DECLs. */
379
380 TREE_UNSIGNED (decl) = TREE_UNSIGNED (type);
381 if (DECL_MODE (decl) == VOIDmode)
382 DECL_MODE (decl) = TYPE_MODE (type);
383
384 if (DECL_SIZE (decl) == 0)
385 {
386 DECL_SIZE (decl) = TYPE_SIZE (type);
387 DECL_SIZE_UNIT (decl) = TYPE_SIZE_UNIT (type);
388 }
389 else if (DECL_SIZE_UNIT (decl) == 0)
390 DECL_SIZE_UNIT (decl)
391 = convert (sizetype, size_binop (CEIL_DIV_EXPR, DECL_SIZE (decl),
392 bitsize_unit_node));
393
394 if (code != FIELD_DECL)
395 /* For non-fields, update the alignment from the type. */
396 do_type_align (type, decl);
397 else
398 /* For fields, it's a bit more complicated... */
399 {
…
493 }
当从build_decl进入这个函数时,tree_decl节点中,除了name和type域已经设置外,其余由0填充(参见make_node)。注意到382行,VOIDmode是0。而在394行,如果我们不是从layout_type来的,节点不可能是FIELD_DECL。因此,在396行,do_type_align将参考声明所对应的类型的对齐量,来为声明节点设置对齐量。
328 static inline void
329 do_type_align (tree type, tree decl) in stor-layout.c
330 {
331 if (TYPE_ALIGN (type) > DECL_ALIGN (decl))
332 {
333 DECL_ALIGN (decl) = TYPE_ALIGN (type);
334 if (TREE_CODE (decl) == FIELD_DECL)
335 DECL_USER_ALIGN (decl) = TYPE_USER_ALIGN (type);
336 }
337 }
GNU C++有一个有趣的扩展,允许局部数组的维度是一个非常量,例如:
void func () {
int j = 5;
int arrJ[j++];
}
是合法的。显然arrJ的大小是一个表达式,而非一个INTEGER_CST节点。这个表示大小的表达式可能会有副作用(这里的j++即是)。这意味着对该表达式的求值只能做一次,其余时候只能用缓存的值。在前端中,节点SAVE_EXPR就是为这个目的设置的。在下面函数variable_size将会把这些非常量的表示声明大小的节点替换为SAVE_EXPR。
layout_decl (continue)
495 /* Evaluate nonconstant size only once, either now or as soon as safe. */
496 if (DECL_SIZE (decl) != 0 && TREE_CODE (DECL_SIZE (decl)) != INTEGER_CST)
497 DECL_SIZE (decl) = variable_size (DECL_SIZE (decl));
498 if (DECL_SIZE_UNIT (decl) != 0
499 && TREE_CODE (DECL_SIZE_UNIT (decl)) != INTEGER_CST)
500 DECL_SIZE_UNIT (decl) = variable_size (DECL_SIZE_UNIT (decl));
501
502 /* If requested, warn about definitions of large data objects. */
503 if (warn_larger_than
504 && (code == VAR_DECL || code == PARM_DECL)
505 && ! DECL_EXTERNAL (decl))
506 {
507 tree size = DECL_SIZE_UNIT (decl);
508
509 if (size != 0 && TREE_CODE (size) == INTEGER_CST
510 && compare_tree_int (size, larger_than_size) > 0)
511 {
512 int size_as_int = TREE_INT_CST_LOW (size);
513
514 if (compare_tree_int (size, size_as_int) == 0)
515 warning ("%Jsize of '%D' is %d bytes", decl, decl, size_as_int);
516 else
517 warning ("%Jsize of '%D' is larger than %d bytes",
518 decl, decl, larger_than_size);
519 }
520 }
521
522 /* If the RTL was already set, update its mode and mem attributes. */
523 if (rtl)
524 {
525 PUT_MODE (rtl, DECL_MODE (decl));
526 SET_DECL_RTL (decl, 0);
527 set_mem_attributes (rtl, decl, 1);
528 SET_DECL_RTL (decl, rtl);
529 }
530 }
在523行,rtl是节点对应的RTL节点,它只会在完成编译单元的解析后,才会产生。RTL节点将指引汇编的产生,如果声明的布局发生变化,可能会对内存的分配产生影响,必须更新对应的RTL节点的属性(如果已生成RTL节点的话)。