We have known that define_function_unit describes the chip in the view of function unit. However, this pattern is still majorly in human readable form. We must create data easily handled by the tool to output functions for pipeline hazards recognizer. This old way of chip description is much simpler than the new way; data created here is still attributes.
main (continued)
6128 if (num_units || num_dfa_decls )
6129 {
6130 /* Expand DEFINE_FUNCTION_UNIT information into new attributes. */
6131 expand_units ();
6132 /* Build DFA, output some functions and expand DFA information
6133 into new attributes. */
6134 expand_automata ();
6135 }
For our example, after generated by gen_unit , we can get following data (for field not displayed, just means it is 0).
figure 51 : example of FUNCTION_UNIT
Data with above form is no good for constructing pipeline hazards recognizer easily and directly. We need expand_units to extract informations then make them pernament by placing them into hash table and create attributes accordingly.
1812 static void
1813 expand_units (void) in genattrtab.c
1814 {
1815 struct function_unit *unit, **unit_num;
1816 struct function_unit_op *op, **op_array, ***unit_ops;
1817 rtx unitsmask;
1818 rtx readycost;
1819 rtx newexp;
1820 const char *str;
1821 int i, j, u, num, nvalues;
1822
1823 /* Rebuild the condition for the unit to share the RTL expressions.
1824 Sharing is required by simplify_by_exploding. Build the issue delay
1825 expressions. Validate the expressions we were given for the conditions
1826 and conflict vector. Then make attributes for use in the conflict
1827 function. */
1828
1829 for (unit = units ; unit; unit = unit->next)
1830 {
1831 unit->condexp = check_attr_test (unit->condexp, 0, unit->first_lineno);
1832
1833 for (op = unit->ops; op; op = op->next)
1834 {
1835 rtx issue_delay = make_numeric_value (op->issue_delay);
1836 rtx issue_exp = issue_delay;
1837
1838 /* Build, validate, and simplify the issue delay expression. */
1839 if (op->conflict_exp != true_rtx )
1840 issue_exp = attr_rtx (IF_THEN_ELSE, op->conflict_exp,
1841 issue_exp, make_numeric_value (0));
1842 issue_exp = check_attr_value (make_canonical (NULL_ATTR,
1843 issue_exp),
1844 NULL_ATTR);
1845 issue_exp = simplify_knowing (issue_exp, unit->condexp);
1846 op->issue_exp = issue_exp;
1847
1848 /* Make an attribute for use in the conflict function if needed. */
1849 unit->needs_conflict_function = (unit->issue_delay.min
1850 != unit->issue_delay.max);
1851 if (unit->needs_conflict_function)
1852 {
1853 str = attr_printf ((strlen (unit->name) + sizeof "*_cost_"
1854 + MAX_DIGITS),
1855 "*%s_cost_%d", unit->name, op->num);
1856 make_internal_attr (str, issue_exp, ATTR_SPECIAL);
1857 }
1858
1859 /* Validate the condition. */
1860 op->condexp = check_attr_test (op->condexp, 0, op->lineno);
1861 }
1862 }
As we have seen in 9.3.5.Read in DEFINE_FUNCTION_UNIT pattern , for function unit used by more than one instruction, the condexp part of function_unit will be the OR result of all condexp part of function_unit_op s. So at line 1831 and 1860, check_attr_test is for different purposes indeed.
For check_attr_test , given a test expression for an attribute, the function ensures it is in valid form. Parameter is_const indicates whether the expression is constant for each compiler run (a constant expression may not test any particular instruction). The function converts (eq_attr "att" "a1,a2") to (ior (eq_attr “att” “a1 ) (eq_attr “att” “a2”)) and (eq_attr "att" "!a1") to (not (eq_attr "att" "a1")) . It does the latter conversion first so that (eq_attr "att" "!a1,a2,a3") works as expected. And it updates the string in EQ_ATTR expression to be the same used in the attribute (or alternative_name ) to speed up subsequent find_attr calls and eliminate most strcmp calls. The function returns the new expression, if any.
919 rtx
920 check_attr_test (rtx exp, int is_const, int lineno) in genattrtab.c
921 {
922 struct attr_desc *attr;
923 struct attr_value *av;
924 const char *name_ptr, *p;
925 rtx orexp, newexp;
926
927 switch (GET_CODE (exp))
928 {
929 case EQ_ATTR:
930 /* Handle negation test. */
931 if (XSTR (exp, 1)[0] == '!')
932 return check_attr_test (attr_rtx (NOT,
933 attr_eq (XSTR (exp, 0),
934 &XSTR (exp, 1)[1])),
935 is_const, lineno);
936
937 else if (n_comma_elts (XSTR (exp, 1)) == 1)
938 {
939 attr = find_attr (&XSTR (exp, 0), 0);
940 if (attr == NULL)
941 {
942 if (! strcmp (XSTR (exp, 0), "alternative"))
943 return mk_attr_alt (1 << atoi (XSTR (exp, 1)));
944 else
945 fatal ("unknown attribute `%s' in EQ_ATTR", XSTR (exp, 0));
946 }
947
948 if (is_const && ! attr->is_const)
949 fatal ("constant expression uses insn attribute `%s' in EQ_ATTR",
950 XSTR (exp, 0));
951
952 /* Copy this just to make it permanent,
953 so expressions using it can be permanent too. */
954 exp = attr_eq (XSTR (exp, 0), XSTR (exp, 1));
955
956 /* It shouldn't be possible to simplify the value given to a
957 constant attribute, so don't expand this until it's time to
958 write the test expression. */
959 if (attr->is_const)
960 ATTR_IND_SIMPLIFIED_P (exp) = 1;
961
962 if (attr->is_numeric)
963 {
964 for (p = XSTR (exp, 1); *p; p++)
965 if (! ISDIGIT (*p))
966 fatal ("attribute `%s' takes only numeric values",
967 XSTR (exp, 0));
968 }
969 else
970 {
971 for (av = attr->first_value; av; av = av->next)
972 if (GET_CODE (av->value) == CONST_STRING
973 && ! strcmp (XSTR (exp, 1), XSTR (av->value, 0)))
974 break ;
975
976 if (av == NULL)
977 fatal ("unknown value `%s' for `%s' attribute",
978 XSTR (exp, 1), XSTR (exp, 0));
979 }
980 }
981 else
982 {
983 if (! strcmp (XSTR (exp, 0), "alternative"))
984 {
985 int set = 0;
986
987 name_ptr = XSTR (exp, 1);
988 while ((p = next_comma_elt (&name_ptr)) != NULL)
989 set |= 1 << atoi (p);
990
991 return mk_attr_alt (set);
992 }
993 else
994 {
995 /* Make an IOR tree of the possible values. */
996 orexp = false_rtx ;
997 name_ptr = XSTR (exp, 1);
998 while ((p = next_comma_elt (&name_ptr)) != NULL)
999 {
1000 newexp = attr_eq (XSTR (exp, 0), p);
1001 orexp = insert_right_side (IOR, orexp, newexp, -2, -2);
1002 }
1003
1004 return check_attr_test (orexp, is_const, lineno);
1005 }
1006 }
1007 break ;
1008
1009 case ATTR_FLAG:
1010 break ;
1011
1012 case CONST_INT:
1013 /* Either TRUE or FALSE. */
1014 if (XWINT (exp, 0))
1015 return true_rtx ;
1016 else
1017 return false_rtx ;
1018
1019 case IOR:
1020 case AND:
1021 XEXP (exp, 0) = check_attr_test (XEXP (exp, 0), is_const, lineno);
1022 XEXP (exp, 1) = check_attr_test (XEXP (exp, 1), is_const, lineno);
1023 break ;
1024
1025 case NOT:
1026 XEXP (exp, 0) = check_attr_test (XEXP (exp, 0), is_const, lineno);
1027 break ;
1028
1029 case MATCH_INSN:
1030 case MATCH_OPERAND:
1031 if (is_const)
1032 fatal ("RTL operator /"%s/" not valid in constant attribute test",
1033 GET_RTX_NAME (GET_CODE (exp)));
1034 /* These cases can't be simplified. */
1035 ATTR_IND_SIMPLIFIED_P (exp) = 1;
1036 break ;
1037
1038 case LE: case LT: case GT: case GE:
1039 case LEU: case LTU: case GTU: case GEU:
1040 case NE: case EQ:
1041 if (GET_CODE (XEXP (exp, 0)) == SYMBOL_REF
1042 && GET_CODE (XEXP (exp, 1)) == SYMBOL_REF)
1043 exp = attr_rtx (GET_CODE (exp),
1044 attr_rtx (SYMBOL_REF, XSTR (XEXP (exp, 0), 0)),
1045 attr_rtx (SYMBOL_REF, XSTR (XEXP (exp, 1), 0)));
1046 /* These cases can't be simplified. */
1047 ATTR_IND_SIMPLIFIED_P (exp) = 1;
1048 break ;
1049
1050 case SYMBOL_REF:
1051 if (is_const)
1052 {
1053 /* These cases are valid for constant attributes, but can't be
1054 simplified. */
1055 exp = attr_rtx (SYMBOL_REF, XSTR (exp, 0));
1056 ATTR_IND_SIMPLIFIED_P (exp) = 1;
1057 break ;
1058 }
1059 default :
1060 fatal ("RTL operator /"%s/" not valid in attribute test",
1061 GET_RTX_NAME (GET_CODE (exp)));
1062 }
1063
1064 return exp;
1065 }
Function n_comma_elts counts number of “,” in the string passed in. If the attribute has name “alternative”, it refers to compiler variable which_alternative which must be numeric value. This value is saved in EQ_ATTR_ALT at line 943 via mk_attr_alt . ATTR_IND_SIMPLIFIED_P at line 960 accesses unchanging field of the rtx object. This field if 1, means expression the rtx object representing can’t be simplified. attr_eq creates rtx object of EQ_ATTR with operants saved in attr_hash_table .
763 static rtx
764 attr_eq (const char *name, const char *value) in genattrtab.c
765 {
766 return attr_rtx (EQ_ATTR, DEF_ATTR_STRING (name), DEF_ATTR_STRING (value));
767 }
Then, in expand_units at line 1845, notice that the second parameter of simplify_knowing is condexp field of unit generated by check_attr_test , the condexp is shown in below figure for our example.
figure 52 : condexp generated by check_attr_test
And here in our example the first parameter exp of simplify_knowing is an rtx object equivalent to:
IF op->conflict_exp THEN
op->issue_delay
ELSE
0
Or op->issue_delay. (if conflict_exp is not defined)
Compare above expression with the description in gccinfo, especially that in bold:
CONFLICT-LIST is an optional list giving detailed conflict costs for this unit. If specified, it is a list of condition test expressions to be applied to insns chosen to execute in NAME following the particular insn matching TEST that is already executing in NAME. For each insn in the list, ISSUE-DELAY specifies the conflict cost; for insns not in the list, the cost is zero. If not specified, CONFLICT-LIST defaults to all instructions that use the function unit .
2173 static rtx
2174 simplify_knowing (rtx exp, rtx known_true) in genattrtab.c
2175 {
2176 if (GET_CODE (exp) != CONST_STRING)
2177 {
2178 int unknown = 0, max;
2179 max = max_attr_value (exp, &unknown);
2180 if (! unknown)
2181 {
2182 exp = attr_rtx (IF_THEN_ELSE, known_true, exp,
2183 make_numeric_value (max));
2184 exp = simplify_by_exploding (exp);
2185 }
2186 }
2187 return exp;
2188 }
At line 2179, max_attr_value given an attribute, returns the maximum numeric value found in the attribute, sets UNKNOWNP and returns INT_MAX if the attribute is not of right type. So max it returns is the issue_delay due to conflict if everything is OK.
4850 static int
4851 max_attr_value (rtx exp, int *unknownp) in genattrtab.c
4852 {
4853 int current_max;
4854 int i, n;
4855
4856 switch (GET_CODE (exp))
4857 {
4858 case CONST_STRING:
4859 current_max = atoi (XSTR (exp, 0));
4860 break ;
4861
4862 case COND:
4863 current_max = max_attr_value (XEXP (exp, 1), unknownp);
4864 for (i = 0; i < XVECLEN (exp, 0); i += 2)
4865 {
4866 n = max_attr_value (XVECEXP (exp, 0, i + 1), unknownp);
4867 if (n > current_max)
4868 current_max = n;
4869 }
4870 break ;
4871
4872 case IF_THEN_ELSE:
4873 current_max = max_attr_value (XEXP (exp, 1), unknownp);
4874 n = max_attr_value (XEXP (exp, 2), unknownp);
4875 if (n > current_max)
4876 current_max = n;
4877 break ;
4878
4879 default :
4880 *unknownp = 1;
4881 current_max = INT_MAX;
4882 break ;
4883 }
4884
4885 return current_max;
4886 }
Back expand_units , simplify_knowing is enclosed in a FOR loop and invoked per instruction. At line 2182, in simplify_knowing , it constructs the IF_THEN_ELSE rtx object in equivalent as:
IF unit->condexp THEN
IF op->conflict_exp THEN
op->issue_delay.
ELSE
0
ELSE
op->issue_delay
Or (if op->conflict_exp is null):
IF unit->condexp THEN
op->issue_delay
ELSE
op->issue_delay
The expression given parameters at certain point of execution returns the issue delay upon the function unit. It is the core for the old style pipeline hazards recognizer. However as can be seen, it’s still not simplified form, so at line 2184 simplify_by_exploding is invoked, to make the expression into canonical and simplified form.
3724 static rtx
3725 simplify_by_exploding (rtx exp) in genattrtab.c
3726 {
3727 rtx list = 0, link, condexp, defval = NULL_RTX;
3728 struct dimension *space;
3729 rtx *condtest, *condval;
3730 int i, j, total, ndim = 0;
3731 int most_tests, num_marks, new_marks;
3732 rtx ret;
3733
3734 /* Locate all the EQ_ATTR expressions. */
3735 if (! find_and_mark_used_attributes (exp, &list, &ndim) || ndim == 0)
3736 {
3737 unmark_used_attributes (list, 0, 0);
3738 return exp;
3739 }
find_and_mark_used_attributes just links all EQ_ATTR tegother, macro ATTR_EQ_ATTR_P accesses the volatil field of exp , this field is set at line 3896 to prevent exp to be linked more than once.
3881 static int
3882 find_and_mark_used_attributes (rtx exp, rtx *terms, int *nterms) in genattrtab.c
3883 {
3884 int i;
3885
3886 switch (GET_CODE (exp))
3887 {
3888 case EQ_ATTR:
3889 if (! ATTR_EQ_ATTR_P (exp))
3890 {
3891 rtx link = rtx_alloc (EXPR_LIST);
3892 XEXP (link, 0) = exp;
3893 XEXP (link, 1) = *terms;
3894 *terms = link;
3895 *nterms += 1;
3896 ATTR_EQ_ATTR_P (exp) = 1;
3897 }
3898 return 1;
3899
3900 case CONST_STRING:
3901 case CONST_INT:
3902 return 1;
3903
3904 case IF_THEN_ELSE:
3905 if (! find_and_mark_used_attributes (XEXP (exp, 2), terms, nterms))
3906 return 0;
3907 case IOR:
3908 case AND:
3909 if (!find_and_mark_used_attributes (XEXP (exp, 1), terms, nterms))
3910 return 0;
3911 case NOT:
3912 if (!find_and_mark_used_attributes (XEXP (exp, 0), terms, nterms))
3913 return 0;
3914 return 1;
3915
3916 case COND:
3917 for (i = 0; i < XVECLEN (exp, 0); i++)
3918 if (!find_and_mark_used_attributes (XVECEXP (exp, 0, i), terms, nterms))
3919 return 0;
3920 if (!find_and_mark_used_attributes (XEXP (exp, 1), terms, nterms))
3921 return 0;
3922 return 1;
3923
3924 default :
3925 return 0;
3926 }
3927 }
101 #define ATTR_EQ_ATTR_P (RTX) (RTX_FLAG((RTX), volatil)) in genattrtab.c
Continue with simpilify_by_exploding , now ndim , for our example, is 7 (refer to figure 52 for exp , and assuming it is the only define_funtion_unit describes the unit related - that is no conflict_exp in op ).
simpilfy_by_exploding (continued)
3741 /* Create an attribute space from the list of used attributes. For each
3742 dimension in the attribute space, record the attribute, list of values
3743 used, and number of values used. Add members to the list of values to
3744 cover the domain of the attribute. This makes the expanded COND form
3745 order independent. */
3746
3747 space = xmalloc (ndim * sizeof (struct dimension ));
3748
3749 total = 1;
3750 for (ndim = 0; list; ndim++)
3751 {
3752 /* Pull the first attribute value from the list and record that
3753 attribute as another dimension in the attribute space. */
3754 const char *name = XSTR (XEXP (list, 0), 0);
3755 rtx *prev;
3756
3757 space[ndim].attr = find_attr (&name, 0);
3758 XSTR (XEXP (list, 0), 0) = name;
3759
3760 if (space[ndim].attr == 0
3761 || space[ndim].attr->is_numeric)
3762 {
3763 unmark_used_attributes (list, space, ndim);
3764 return exp;
3765 }
3766
3767 /* Add all remaining attribute values that refer to this attribute. */
3768 space[ndim].num_values = 0;
3769 space[ndim].values = 0;
3770 prev = &list;
3771 for (link = list; link; link = *prev)
3772 if (! strcmp_check (XSTR (XEXP (link, 0), 0), name))
3773 {
3774 space[ndim].num_values++;
3775 *prev = XEXP (link, 1);
3776 XEXP (link, 1) = space[ndim].values;
3777 space[ndim].values = link;
3778 }
3779 else
3780 prev = &XEXP (link, 1);
3781
3782 /* Add sufficient members to the list of values to make the list
3783 mutually exclusive and record the total size of the attribute
3784 space. */
3785 total *= add_values_to_cover (&space[ndim]);
3786 }
dimension at line 3747, has following definition. At line 3757, find_attr creates attribute associated with name in attr_hash_table and returns the attribute. Notice that parameter name is replaced by the counterpart in attr_hash_table too. At line 3758, name of the node is updated. So at line 3772, strcmp_check can just compares the addresses of the two strings.
302 struct dimension in genattrtab.c
303 {
304 struct attr_desc *attr; /* Attribute for this dimension. */
305 rtx values; /* List of attribute values used. */
306 rtx current_value; /* Position in the list for the TRUE value. */
307 int num_values; /* Length of the values list. */
308 }
The whole FOR loop at line 3750, for every iteration, will find out attributes of same name, and link them into same element of space , then invokes add_values_to_cover for the space element (name of attribute is the first child of EQ_ATTR).
For example, orignially we get following data outline. The first node must pass the test at line 3772.
figure 53 : example of define_function_unit handling, figure 1
Then after excuting line 3774 ~ 3777, and line 3771 for next iteration, we can get following. Node 0 is the EQ_ATTR having name “cpu” which is linked into space[0], others are EQ_ATTR having name “type” which are linked into space[1] (see figure 52 ). Notice that for any group of links generated by function unit description pattern, at any point of execution, at most one node in every link will be matched, as attribute can’t take more than one value at one point of time.
figure 54 : example of define_function_unit handling, figure 2
Then add_values_to_cover is invoked to include other unmentioned value of the attribute into the link. By this way, the link becomes integrate for the attribute in interested.
3952 static int
3953 add_values_to_cover (struct dimension *dim) in genattrtab.c
3954 {
3955 struct attr_value *av;
3956 rtx exp, link, *prev;
3957 int nalt = 0;
3958
3959 for (av = dim->attr->first_value; av; av = av->next)
3960 if (GET_CODE (av->value) == CONST_STRING)
3961 nalt++;
3962
3963 if (nalt < dim->num_values)
3964 abort ();
3965 else if (nalt == dim->num_values)
3966 /* OK. */
3967 ;
3968 else if (nalt * 2 < dim->num_values * 3)
3969 {
3970 /* Most all the values of the attribute are used, so add all the unused
3971 values. */
3972 prev = &dim->values;
3973 for (link = dim->values; link; link = *prev)
3974 prev = &XEXP (link, 1);
3975
3976 for (av = dim->attr->first_value; av; av = av->next)
3977 if (GET_CODE (av->value) == CONST_STRING)
3978 {
3979 exp = attr_eq (dim->attr->name, XSTR (av->value, 0));
3980 if (ATTR_EQ_ATTR_P (exp))
3981 continue ;
3982
3983 link = rtx_alloc (EXPR_LIST);
3984 XEXP (link, 0) = exp;
3985 XEXP (link, 1) = 0;
3986 *prev = link;
3987 prev = &XEXP (link, 1);
3988 }
3989 dim->num_values = nalt;
3990 }
3991 else
3992 {
3993 rtx orexp = false_rtx ;
3994
3995 /* Very few values are used, so compute a mutually exclusive
3996 expression. (We could do this for numeric values if that becomes
3997 important.) */
3998 prev = &dim->values;
3999 for (link = dim->values; link; link = *prev)
4000 {
4001 orexp = insert_right_side (IOR, orexp, XEXP (link, 0), -2, -2);
4002 prev = &XEXP (link, 1);
4003 }
4004 link = rtx_alloc (EXPR_LIST);
4005 XEXP (link, 0) = attr_rtx (NOT, orexp);
4006 XEXP (link, 1) = 0;
4007 *prev = link;
4008 dim->num_values++;
4009 }
4010 return dim->num_values;
4011 }
attr field of dimension points to object of attr_desc describing the attribute, in which first_value field maintains a list recording all attribute values. And values field of dimension just records values of this attribute used in the define_function_unit pattern. Of course, values must be a subset of first_value of attr . Here is the way we make the link integrate - if the number of values used is close to the total number of attribute values, adds all rest unreferred attribute values from the tail of link (line 3969 ~ 3989), while if the difference is quite large, creates a new EXPR_LIST to stand for rest values (see it is a NOT expression for all unreferred values), and links it at tail. As indicated in below figure.
figure 55 : example of define_function_unit handling, figure 3
Procedure above of linking attribute of same name tegother and makes the list integrate are repeated until all attributes have been treated. Then below these lists are sorted as constant comes first, then having more values comes first.
simplify_by_exploding (continued)
3788 /* Sort the attribute space so that the attributes go from non-constant
3789 to constant and from most values to least values. */
3790 for (i = 0; i < ndim; i++)
3791 for (j = ndim - 1; j > i; j--)
3792 if ((space[j-1].attr->is_const && !space[j].attr->is_const)
3793 || space[j-1].num_values < space[j].num_values)
3794 {
3795 struct dimension tmp;
3796 tmp = space[j];
3797 space[j] = space[j - 1];
3798 space[j - 1] = tmp;
3799 }
3800
3801 /* Estabusagelish the initial current value. */
3802 for (i = 0; i < ndim; i++)
3803 space[i].current_value = space[i].values;
3804
3805 condtest = xmalloc (total * sizeof (rtx));
3806 condval = xmalloc (total * sizeof (rtx));
3807
3808 /* Expand the tests and values by iterating over all values in the
3809 attribute space. */
3810 for (i = 0;; i++)
3811 {
3812 condtest[i] = test_for_current_value (space, ndim);
3813 condval[i] = simplify_with_current_value (exp, space, ndim);
3814 if (! increment_current_value (space, ndim))
3815 break ;
3816 }
3817 if (i != total - 1)
3818 abort ();
ndim at line 3790 indicates the number of elements of space used, total at line 3805 tells the number of rtx objects needed. At line 3803, current_value fields of space are initialized as the first element of values . test_for_current_value creates initial expression for the test.
4034 static rtx
4035 test_for_current_value (struct dimension *space, int ndim) in genattrtab.c
4036 {
4037 int i;
4038 rtx exp = true_rtx ;
4039
4040 for (i = 0; i < ndim; i++)
4041 exp = insert_right_side (AND, exp, XEXP (space[i].current_value, 0),
4042 -2, -2);
4043
4044 return exp;
4045 }
Note that in fact current_value always refers to the unprocessed part of exp . Thus array condtest exhausts all possible test expressions related. Then simplify_with_current_value reduces the expression exp .
4052 static rtx
4053 simplify_with_current_value (rtx exp, struct dimension *space, int ndim) in genattrtab.c
4054 {
4055 int i;
4056 rtx x;
4057
4058 /* Mark each current value as TRUE. */
4059 for (i = 0; i < ndim; i++)
4060 {
4061 x = XEXP (space[i].current_value, 0);
4062 if (GET_CODE (x) == EQ_ATTR)
4063 ATTR_EQ_ATTR_P (x) = 0;
4064 }
4065
4066 exp = simplify_with_current_value_aux (exp);
4067
4068 /* Change each current value back to FALSE. */
4069 for (i = 0; i < ndim; i++)
4070 {
4071 x = XEXP (space[i].current_value, 0);
4072 if (GET_CODE (x) == EQ_ATTR)
4073 ATTR_EQ_ATTR_P (x) = 1;
4074 }
4075
4076 return exp;
4077 }
In find_and_mark_used_attributes , during creating the list, volital field of its nodes has been set as 1. At line 4061, current_value always refers to the unprocessed part of exp . And if current_value is an EQ_ATTR, we set the ATTR_EQ_ATTR_P as 0, then below at line 4094 in simplify_with_current_value_aux , true_rtx will be returned accordingly, thus can generate value of condval for corresponding condtest . The visit order of members of EXP is roughly displayed in below (the order is shown by the number in rectangle).
(Note: the object dotted pointer points to is IOR object. XEXP(exp, 0) in fact points to node of tree in figure 52 , becaure rectangles above are shared with rtx objects and spaces. Node1 is the second child of the first IOR object, node2 is the second child of following IOR object which is pointed by the first child of former IOR object, and so on. However, the relation between node7 and node8 is AND. So the dotted pointers gives out the visit order)
figure 56 : example of define_function_unit handling, figure 4