9.6.1.3. 属性的优化
一些属性包含复杂的表达式作为其值。使用i386.md文件中的一个例子,“length_immediate”属性的定义如下" 。
189 (define_attr "length_immediate"""
190 (cond [(eq_attr "type""incdec,setcc,icmov,str,cld,lea,other,multi,idiv,leave")
191 (const_int 0)
192 (eq_attr "unit" "i387,sse,mmx")
193 (const_int 0)
194 (eq_attr "type""alu,alu1,negnot,imovx,ishift,rotate,ishift1,rotate1,
195 imul,icmp,push,pop")
196 (symbol_ref"ix86_attr_length_immediate_default(insn,1)")
197 (eq_attr "type" "imov,test")
198 (symbol_ref"ix86_attr_length_immediate_default(insn,0)")
199 (eq_attr "type" "call")
200 (if_then_else (match_operand 0"constant_call_address_operand" "")
201 (const_int 4)
202 (const_int 0))
203 (eq_attr "type" "callv")
204 (if_then_else (match_operand 1"constant_call_address_operand" "")
205 (const_int 4)
206 (const_int 0))
207 ;; We don't know the size before shorten_branches. Expect
208 ;; the instruction to fit for better scheduling.
209 (eq_attr "type" "ibr")
210 (const_int 1)
211 ]
212 (symbol_ref "/* Update immediate_length and other attributes! */
213 abort(),1")))
190行到213行是用于该属性缺省值的表达式。从这个原始形式为所关联的指令产生get_attr_length_immediate是困难的。不过,因为缺省值将被用于没有显式声明这个属性值的指令中,并且该指令,在任何时候,都必须为每个属性采取值列表中的一个值。而当选定了一个指令,必须通过其define_insn模式中的条件测试。即确定了绝大多数属性的值。因此,最好把这些属性值应用到这个表达式来得到最简化的形式,并为该指令保存这个简化的表达式。这就是所谓的属性优化的目的。
不过记住,现在这个属性的rtx对象并不是我们在上面看到的。主要的1在于所有的IF_THEN_ELSE对象被重构为COND对象(参见get_attr_value,及调用的make_canonical)。
3624 static void
3625 optimize_attrs (void) in genattrtab.c
3626 {
3627 struct attr_desc*attr;
3628 struct attr_value*av;
3629 struct insn_ent*ie;
3630 rtx newexp;
3631 int i;
3632 structattr_value_list
3633 {
3634 struct attr_value *av;
3635 struct insn_ent*ie;
3636 struct attr_desc*attr;
3637 structattr_value_list *next;
3638 };
3639 structattr_value_list **insn_code_values;
3640 structattr_value_list *ivbuf;
3641 structattr_value_list *iv;
3642
3643 /* For each insncode, make a list of all the insn_ent's for it,
3644 for all values for all attributes. */
3645
3646 if (num_insn_ents == 0)
3647 return;
3648
3649 /* Make 2 extraelements, for "code" values -2 and -1. */
3650 insn_code_values = xcalloc ((insn_code_number + 2),
3651 sizeof (structattr_value_list *));
3652
3653 /* Offset the tableaddress so we can index by -2 or -1. */
3654 insn_code_values += 2;
3655
3656 iv = ivbuf = xmalloc (num_insn_ents * sizeof (structattr_value_list));
3657
3658 for (i = 0; i < MAX_ATTRS_INDEX; i++)
3659 for (attr =attrs[i];attr; attr = attr->next)
3660 for (av =attr->first_value; av; av = av->next)
3661 for (ie =av->first_insn; ie; ie = ie->next)
3662 {
3663 iv->attr = attr;
3664 iv->av = av;
3665 iv->ie = ie;
3666 iv->next = insn_code_values[ie->insn_code];
3667 insn_code_values[ie->insn_code] = iv;
3668 iv++;
3669 }
3670
3671 /* Sanity check onnum_insn_ents. */
3672 if (iv != ivbuf + num_insn_ents)
3673 abort ();
3674
3675 /* Process one insncode at a time. */
3676 for (i = -2; i < insn_code_number; i++)
3677 {
3678 /* Clear theATTR_CURR_SIMPLIFIED_P flag everywhere relevant.
3679 We use it to mean "alreadysimplified for this insn". */
3680 for (iv =insn_code_values[i]; iv; iv = iv->next)
3681 clear_struct_flag (iv->av->value);
3682
3683 for (iv =insn_code_values[i]; iv; iv = iv->next)
3684 {
3685 structobstack *old = rtl_obstack;
3686
3687 attr = iv->attr;
3688 av = iv->av;
3689 ie= iv->ie;
3690 if (GET_CODE (av->value) != COND)
3691 continue;
3692
3693 rtl_obstack = temp_obstack;
3694 newexp = av->value;
3695 while(GET_CODE (newexp) == COND)
3696 {
3697 rtx newexp2 = simplify_cond (newexp, ie->insn_code,
3698 ie->insn_index);
3699 if (newexp2 == newexp)
3700 break;
3701 newexp = newexp2;
3702 }
3703
3704 rtl_obstack = old;
3705 if (newexp != av->value)
3706 {
3707 newexp = attr_copy_rtx (newexp);
3708 remove_insn_ent (av, ie);
3709 av = get_attr_value (newexp, attr, ie->insn_code);
3710 iv->av = av;
3711 insert_insn_ent (av, ie);
3712 }
3713 }
3714 }
3715
3716 free (ivbuf);
3717 free (insn_code_values - 2);
3718 }
为了理解在3658行的大FOR循环,参见下面的图形。在这些循环之前,数据的地图如下,所有使用同一个属性的指令构成了一个链表,这个链表保存在属性值的数据对象中(注意缺省值已经被链入value,参见fill_attr)。
图82:属性优化,图1
这个FOR循环组合上图所示的数据。被绿色线所包围的数据形成了一个iv,被红色线所包围的数据形成了下一个iv。这个数据有三个层次,attribute位于最顶层,value在中间,而insn在最底层。组合首先在底层开始,在3个层次上相关的数据被放在一起(同样看到,被绿色线包围的指令必须具有,比红色线包围的指令更小的,指令编码,参见gen_insn以及fill_attr)。

图83:属性优化,图2
注意在3676及3683行的FOR循环中,iv的遍历次序是指令编码的升序。根据指令编码来处理是必要的。这是因为在简化过程中,我们可能得到以下的数据——一个新的属性值被作为对指令的简化结果加入(它看起来不像列表中的其它值,通常的情形是使用缺省值的指令),而这个insn被移到这个值的下面。因此如果我们根据值来处理,这个新的值就会被重复访问——这是重复的工作。

图84:属性优化,图3
对于每个是COND的属性值,simplify_cond用于检查是否可以执行简化。在研究这个函数之前,请回忆COND虽然类似于switch-case语句,其条件测试必须被依次执行。因此,以正确的次序安排这个条件是非常重要的。这是机器描述文件作者的责任。
2492 static rtx
2493 simplify_cond (rtx exp, int insn_code,int insn_index) ingenattrtab.c
2494 {
2495 int i, j;
2496 /* We store the desired contents here,
2497 then build a new expression if they don'tmatch EXP. */
2498 rtx defval = XEXP (exp, 1);
2499 rtx new_defval = XEXP (exp, 1);
2500 int len = XVECLEN (exp, 0);
2501 rtx *tests = xmalloc (len * sizeof (rtx));
2502 int allsame = 1;
2503 rtx ret;
2504
2505 /* This lets us free all storage allocatedbelow, if appropriate. */
2506 obstack_finish (rtl_obstack);
2507
2508 memcpy (tests, XVEC (exp, 0)->elem, len * sizeof (rtx));
2509
2510 /* See if default value needssimplification. */
2511 if (GET_CODE (defval) == COND)
2512 new_defval = simplify_cond (defval, insn_code, insn_index);
2513
2514 /* Simplify the subexpressions, and see whattests we can get rid of. */
2515
2516 for (i = 0; i< len; i += 2)
2517 {
2518 rtx newtest, newval;
2519
2520 /* Simplify this test. */
2521 newtest = simplify_test_exp_in_temp (tests[i], insn_code, insn_index);
2522 tests[i] = newtest;
2523
2524 newval = tests[i + 1];
2525 /* See if this value may needsimplification. */
2526 if (GET_CODE (newval) == COND)
2527 newval = simplify_cond (newval, insn_code, insn_index);
2528
2529 /* Look for ways to delete or combine thistest. */
2530 if (newtest == true_rtx)
2531 {
2532 /* If test istrue, make this value the default
2533 and discard this + any followingtests. */
2534 len = i;
2535 defval = tests[i + 1];
2536 new_defval = newval;
2537 }
2538
2539 else if (newtest == false_rtx)
2540 {
2541 /* If test isfalse, discard it and its value. */
2542 for (j = i; j < len - 2; j++)
2543 tests[j] = tests[j + 2];
2544 i -= 2;
2545 len -= 2;
2546 }
2547
2548 else if (i > 0 && attr_equal_p(newval, tests[i - 1]))
2549 {
2550 /* If thisvalue and the value for the prev test are the same,
2551 merge the tests. */
2552
2553 tests[i - 2]
2554 = insert_right_side (IOR, tests[i - 2],newtest,
2555 insn_code,insn_index);
2556
2557 /* Delete thistest/value. */
2558 for (j = i; j < len - 2; j++)
2559 tests[j] = tests[j + 2];
2560 len -= 2;
2561 i -= 2;
2562 }
2563
2564 else
2565 tests[i + 1] = newval;
2566 }
在2498行的defval,及在2499行的new_default都是感兴趣属性的缺省值的别名。在2508行的tests保存了该COND对象的余下部分,其中用于值的条件测试部分,由在2521行的simplify_test_exp_in_temp处理。注意,在处理过程中,对于遇到的每个COND,递归调用simplify_cond。
3139 static rtx
3140 simplify_test_exp_in_temp (rtx exp, intinsn_code, int insn_index) in genattrtab.c
3141 {
3142 rtx x;
3143 structobstack *old;
3144 if (ATTR_IND_SIMPLIFIED_P (exp))
3145 return exp;
3146 old = rtl_obstack;
3147 rtl_obstack = temp_obstack;
3148 x = simplify_test_exp (exp, insn_code,insn_index);
3149 rtl_obstack = old;
3150 if (x == exp || rtl_obstack == temp_obstack)
3151 return x;
3152 returnattr_copy_rtx (x);
3153 }
simplify_test_exp_in_temp将间接递归,并且所有运行的simplify_test_exp_in_temp使用同一个栈——temp_obstack。这些函数共享在temp_obstack中的rtx对象,直到顶层的simplify_test_exp_in_temp退出。这时,这个rtx对象一个被拷贝到初始的内存栈(通过attr_copy_rtx)。因此simplify_test_exp在3148开始与temp_obstack一起工作。
3304 static rtx
3305 simplify_test_exp (rtx exp, intinsn_code, int insn_index) in genattrtab.c
3306 {
3307 rtx left, right;
3308 struct attr_desc*attr;
3309 struct attr_value*av;
3310 structinsn_ent *ie;
3311 int i;
3312 rtx newexp = exp;
3313 bool left_alt, right_alt;
3314
3315 /* Don't re-simplifysomething we already simplified. */
3316 if (ATTR_IND_SIMPLIFIED_P (exp) ||ATTR_CURR_SIMPLIFIED_P (exp))
3317 return exp;
3318
3319 switch(GET_CODE (exp))
3320 {
3321 case AND:
3322 left = SIMPLIFY_TEST_EXP (XEXP (exp, 0), insn_code, insn_index);
3323 SIMPLIFY_ALTERNATIVE (left);
3324 if (left == false_rtx)
3325 return false_rtx;
3326 right = SIMPLIFY_TEST_EXP (XEXP (exp, 1), insn_code, insn_index);
3327 SIMPLIFY_ALTERNATIVE (right);
3328 if (left == false_rtx)
3329 return false_rtx;
3330
3331 if (GET_CODE (left) == EQ_ATTR_ALT
3332 && GET_CODE (right) ==EQ_ATTR_ALT)
3333 {
3334 exp = attr_alt_intersection (left, right);
3335 return simplify_test_exp (exp, insn_code, insn_index);
3336 }
3337
3338 /* If eitherside is an IOR and we have (eq_attr "alternative" ..")
3339 present on both sides, apply thedistributive law since this will
3340 yield simplifications. */
3341 if ((GET_CODE (left) == IOR || GET_CODE(right) == IOR)
3342 && compute_alternative_mask (left, IOR)
3343 && compute_alternative_mask (right, IOR))
3344 {
3345 if (GET_CODE (left) == IOR)
3346 {
3347 rtx tem = left;
3348 left = right;
3349 right = tem;
3350 }
3351
3352 newexp = attr_rtx(IOR,
3353 attr_rtx(AND, left, XEXP (right, 0)),
3354 attr_rtx(AND, left, XEXP (right, 1)));
3355
3356 return SIMPLIFY_TEST_EXP (newexp, insn_code, insn_index);
3357 }
3358
3359 /* Try with theterm on both sides. */
3360 right = simplify_and_tree (right, &left, insn_code, insn_index);
3361 if (left == XEXP (exp, 0) && right == XEXP (exp,1))
3362 left = simplify_and_tree (left, &right, insn_code, insn_index);
3363
3364 if (left == false_rtx || right == false_rtx)
3365 return false_rtx;
3366 else if (left == true_rtx)
3367 {
3368 returnright;
3369 }
3370 else if (right == true_rtx)
3371 {
3372 returnleft;
3373 }
3374 /* See if allor all but one of the insn's alternatives are specified
3375 in this tree. Optimize if so. */
3376
3377 if (GET_CODE (left) == NOT)
3378 left_alt = (GET_CODE (XEXP (left,0)) == EQ_ATTR
3379 && XSTR (XEXP (left,0), 0) == alternative_name);
3380 else
3381 left_alt = (GET_CODE (left) ==EQ_ATTR_ALT
3382 && XINT (left, 1));
3383
3384 if (GET_CODE (right) == NOT)
3385 right_alt = (GET_CODE (XEXP (right,0)) == EQ_ATTR
3386 && XSTR (XEXP (right,0), 0) == alternative_name);
3387 else
3388 right_alt = (GET_CODE (right) ==EQ_ATTR_ALT
3389 && XINT (right, 1));
3390
3391 if (insn_code >= 0
3392 && (GET_CODE (left) == AND
3393 || left_alt
3394 || GET_CODE (right) == AND
3395 || right_alt))
3396 {
3397 i = compute_alternative_mask (exp, AND);
3398 if (i & ~insn_alternatives[insn_code])
3399 fatal ("invalid alternativespecified for pattern number %d",
3400 insn_index);
3401
3402 /* If allalternatives are excluded, this is false. */
3403 i ^= insn_alternatives[insn_code];
3404 if (i == 0)
3405 returnfalse_rtx;
3406 else if ((i & (i - 1)) == 0&& insn_alternatives[insn_code]> 1)
3407 {
3408 /* If justone excluded, AND a comparison with that one to the
3409 front of the tree. The others willbe eliminated by
3410 optimization. We do not want to dothis if the insn has one
3411 alternative and we have tested noneof them! */
3412 left = make_alternative_compare (i);
3413 right = simplify_and_tree (exp, &left, insn_code, insn_index);
3414 newexp = attr_rtx(AND, left, right);
3415
3416 returnSIMPLIFY_TEST_EXP (newexp, insn_code, insn_index);
3417 }
3418 }
3419
3420 if (left != XEXP (exp, 0) || right != XEXP (exp,1))
3421 {
3422 newexp = attr_rtx(AND, left, right);
3423 return SIMPLIFY_TEST_EXP (newexp, insn_code, insn_index);
3424 }
3425 break;
3426
3427 case IOR:
3428 left = SIMPLIFY_TEST_EXP (XEXP (exp, 0), insn_code, insn_index);
3429 SIMPLIFY_ALTERNATIVE (left);
3430 if (left == true_rtx)
3431 return true_rtx;
3432 right = SIMPLIFY_TEST_EXP (XEXP (exp, 1), insn_code, insn_index);
3433 SIMPLIFY_ALTERNATIVE (right);
3434 if (right == true_rtx)
3435 return true_rtx;
3436
3437 if (GET_CODE (left) == EQ_ATTR_ALT
3438 && GET_CODE (right) ==EQ_ATTR_ALT)
3439 {
3440 exp = attr_alt_union (left, right);
3441 return simplify_test_exp (exp, insn_code, insn_index);
3442 }
3443
3444 right = simplify_or_tree (right,&left, insn_code, insn_index);
3445 if (left == XEXP (exp, 0) && right == XEXP (exp,1))
3446 left = simplify_or_tree (left,&right, insn_code, insn_index);
3447
3448 if (right == true_rtx || left == true_rtx)
3449 return true_rtx;
3450 else if (left == false_rtx)
3451 {
3452 returnright;
3453 }
3454 else if (right == false_rtx)
3455 {
3456 returnleft;
3457 }
3458
3459 /* Test forsimple cases where the distributive law is useful. I.e.,
3460 convert (ior (and (x) (y))
3461 (and (x) (z)))
3462 to (and (x)
3463 (ior (y) (z)))
3464 */
3465
3466 else if (GET_CODE (left) == AND&& GET_CODE (right) == AND
3467 && attr_equal_p (XEXP (left, 0), XEXP (right, 0)))
3468 {
3469 newexp = attr_rtx(IOR, XEXP (left, 1), XEXP (right, 1));
3470
3471 left = XEXP (left, 0);
3472 right = newexp;
3473 newexp = attr_rtx(AND, left, right);
3474 return SIMPLIFY_TEST_EXP (newexp, insn_code, insn_index);
3475 }
3476
3477 /* See if allor all but one of the insn's alternatives are specified
3478 in this tree. Optimize if so. */
3479
3480 else if (insn_code >= 0
3481 && (GET_CODE (left) == IOR
3482 || (GET_CODE (left) == EQ_ATTR_ALT
3483 && !XINT (left, 1))
3484 || (GET_CODE (left) == EQ_ATTR
3485 && XSTR (left, 0) == alternative_name)
3486 || GET_CODE (right) == IOR
3487 || (GET_CODE (right) == EQ_ATTR_ALT
3488 && !XINT (right, 1))
3489 || (GET_CODE (right) == EQ_ATTR
3490 && XSTR (right, 0) == alternative_name)))
3491 {
3492 i = compute_alternative_mask (exp,IOR);
3493 if (i & ~insn_alternatives[insn_code])
3494 fatal ("invalid alternativespecified for pattern number %d",
3495 insn_index);
3496
3497 /* If allalternatives are included, this is true. */
3498 i ^= insn_alternatives[insn_code];
3499 if (i == 0)
3500 returntrue_rtx;
3501 else if ((i & (i - 1)) == 0 &&insn_alternatives[insn_code]> 1)
3502 {
3503 /* If justone excluded, IOR a comparison with that one to the
3504 front of the tree. The others willbe eliminated by
3505 optimization. We do not want to dothis if the insn has one
3506 alternative and we have tested noneof them! */
3507 left = make_alternative_compare (i);
3508 right = simplify_and_tree (exp, &left, insn_code, insn_index);
3509 newexp = attr_rtx(IOR, attr_rtx (NOT, left), right);
3510
3511 returnSIMPLIFY_TEST_EXP (newexp, insn_code, insn_index);
3512 }
3513 }
3514
3515 if (left != XEXP (exp, 0) || right != XEXP (exp,1))
3516 {
3517 newexp = attr_rtx(IOR, left, right);
3518 return SIMPLIFY_TEST_EXP (newexp, insn_code, insn_index);
3519 }
3520 break;
3521
3522 case NOT:
3523 if (GET_CODE (XEXP (exp, 0)) == NOT)
3524 {
3525 left = SIMPLIFY_TEST_EXP (XEXP (XEXP (exp, 0), 0),
3526 insn_code,insn_index);
3527 SIMPLIFY_ALTERNATIVE (left);
3528 return left;
3529 }
3530
3531 left = SIMPLIFY_TEST_EXP (XEXP (exp, 0), insn_code, insn_index);
3532 SIMPLIFY_ALTERNATIVE (left);
3533 if (GET_CODE (left) == NOT)
3534 return XEXP (left,0);
3535
3536 if (left == false_rtx)
3537 return true_rtx;
3538 if (left == true_rtx)
3539 return false_rtx;
3540
3541 if (GET_CODE (left) == EQ_ATTR_ALT)
3542 {
3543 exp = attr_alt_complement (left);
3544 return simplify_test_exp (exp, insn_code, insn_index);
3545 }
3546
3547 /* Try to applyDe`Morgan's laws. */
3548 if (GET_CODE (left) == IOR)
3549 {
3550 newexp = attr_rtx(AND,
3551 attr_rtx(NOT, XEXP (left, 0)),
3552 attr_rtx(NOT, XEXP (left, 1)));
3553
3554 newexp = SIMPLIFY_TEST_EXP (newexp, insn_code, insn_index);
3555 }
3556 else if (GET_CODE (left) == AND)
3557 {
3558 newexp = attr_rtx(IOR,
3559 attr_rtx(NOT, XEXP (left, 0)),
3560 attr_rtx(NOT, XEXP (left, 1)));
3561
3562 newexp = SIMPLIFY_TEST_EXP (newexp, insn_code, insn_index);
3563 }
3564 else if (left != XEXP (exp, 0))
3565 {
3566 newexp = attr_rtx(NOT, left);
3567 }
3568 break;
3569
3570 caseEQ_ATTR_ALT:
3571 if (current_alternative_string)
3572 returnattr_alt_bit_p (exp, atoi (current_alternative_string)) ? true_rtx: false_rtx;
3573
3574 if (!XINT (exp, 0))
3575 return XINT(exp, 1) ? true_rtx: false_rtx;
3576 break;
3577
3578 caseEQ_ATTR:
3579 if (current_alternative_string && XSTR (exp,0) == alternative_name)
3580 return (XSTR(exp, 1) == current_alternative_string
3581 ? true_rtx : false_rtx);
3582
3583 if (XSTR (exp, 0) == alternative_name)
3584 {
3585 newexp = mk_attr_alt (1 << atoi(XSTR (exp, 1)));
3586 break;
3587 }
3588
3589 /* Look at thevalue for this insn code in the specified attribute.
3590 We normally can replace this comparisonwith the condition that
3591 would give this insn the values beingtested for. */
3592 if (XSTR (exp, 0) != alternative_name
3593 && (attr = find_attr(&XSTR (exp, 0), 0)) != NULL)
3594 for (av =attr->first_value; av; av = av->next)
3595 for(ie = av->first_insn; ie; ie = ie->next)
3596 if (ie->insn_code == insn_code)
3597 {
3598 rtx x;
3599 x = evaluate_eq_attr (exp, av->value, insn_code, insn_index);
3600 x = SIMPLIFY_TEST_EXP (x, insn_code,insn_index);
3601 if (attr_rtx_cost(x) < 20)
3602 returnx;
3603 }
3604 break;
3605
3606 default:
3607 break;
3608 }
3609
3610 /* We have alreadysimplified this expression. Simplifying it again
3611 won't buy anything unless we weren't givena valid insn code
3612 to process (i.e., we are canonicalizingsomething.). */
3613 if (insn_code != -2 /*Seems wrong: && current_alternative_string. */
3614 && ! ATTR_IND_SIMPLIFIED_P (newexp))
3615 returncopy_rtx_unchanging (newexp);
3616
3617 returnnewexp;
3618 }
上面在3322行,宏SIMPLIFY_TEST_EXP具有如下定义。在下面的370行,宏ATTR_CURR_SIMPLIFIED_P访问rtx对象的in_struct域。在这里如果in_struct是1,表示这个rtx对于当前正在处理的指令已经是完全简化的。并且我们知道ATTR_IND_SIMPLIED_P访问unchanging域,其如果是1表示这个rtx是完全不依赖于指令编码简化的。对于两者,不需要尝试简化。
369 #define SIMPLIFY_TEST_EXP(EXP,INSN_CODE,INSN_INDEX)\ in genattrtab.c
370 (ATTR_IND_SIMPLIFIED_P (EXP) || ATTR_CURR_SIMPLIFIED_P (EXP)? (EXP)\
371 : simplify_test_exp (EXP, INSN_CODE, INSN_INDEX))
在3323行,宏SIMPLIFY_ALTERNATIVE具有如下定义。在这个定义中,alternative_name是字符串“alternative”,而current_alternative_string在这个版本中没有使用。它总是0。因此它事实上是空的。
375 #define SIMPLIFY_ALTERNATIVE(EXP) \ ingenattrtab.c
376 if (current_alternative_string \
377 && GET_CODE ((EXP)) == EQ_ATTR \
378 && XSTR ((EXP), 0) == alternative_name) \
379 (EXP) = (XSTR ((EXP), 1) == current_alternative_string \
380 ? true_rtx : false_rtx);
3328行包含了一个bug,left应该是right。这个bug已经在V4中被修正。
在simplify_test_exp的3331行,可能在check_attr_test的943行构建EQ_ATTR_ALT。,其第一个孩子保存了值(1<<alternativenumber),它将被用作一个位图。对于由在check_attr_test中的mk_attr_alt构建的EQ_ATTR_ATL对象,其第二个孩子总是0。
simplify_test_exp对COND对象的条件测试执行前序遍历。为了能清楚地看到它如何工作,假定我们有如下例子。对应某个值的属性条件的rtx对象在图85的左侧(记住我们现在在一个COND对象中,我们正在一个类似swtch-case的跳转中)。对于第一步, simplify_test_exp递归到左侧子树的底部,处理EQ_ATTR_ATL节点。从3574行,由mk_attr_alt创建的EQ_ATTR_ATL在其第一个孩子中将不包含0, 因此EQ_ATTR_ATL对象返回自己,如图形右侧所示。
在3615行,对于每个访问的节点,其in_struct域将被设置,并将不会被下面的simplify_test_exp所处理。

图85:优化属性,步骤1