9.4.2. 处理 DEFINE_FUNCTION_UNIT 模式
我们已经知道 define_function_unit 从功能单元的角度来描述芯片。不过,这个模式仍然主要是人类可读的形式。我们必须构建可以容易被工具处理,来为流水线危险识别器输出函数的数据。这个旧式的芯片描述比新式的要简单得多,这里构建的数据仍然是属性。
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 }
对于我们的例子,在由 gen_unit 生成之后,我们可以得到如下数据(至于没有显示的域,表示其内容为 0 )。
图 51 : FUNCTION_UNIT 的例子
以上形式的数据并不适合简单、直接地用于构建流水线危险识别器。我们需要 expand_units 来获取信息,然后通过把这些信息放入哈希表及构建相应的属性,使它们永久化。
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 }
正如我们在 读入 DEFINE_FUNCTION_UNIT模式 一节中所看到的,对于被多条指令所使用的功能单元, function_unit 的 condexp 部分将是所有的 function_unit_op 的 condexp 部分 OR 操作的结果。因此在 1831 及 1860 行, check_attr_test 实际用于不同的目的。
至于 check_attr_test ,给定一个属性的测试表达式,该函数确保它是一个有效形式。参数 is_const 显示,对于每次编译器运行,该表达式是否为常量(一个常量表达式不可能测试任意具体的指令)。这个函数把 (eq_attr "att" "a1,a2") 转换为 (ior (eq_attr “att” “a1 ) (eq_attr “att” “a2”)) ,以及把 (eq_attr "att" "!a1") 转换为 (not (eq_attr "att" "a1")) 。它首先执行后一个的转换,因此 (eq_attr "att" "!a1,a2,a3") 可以按预期的工作。并且它把在 EQ_ATTR 表达式中的字符串为,在属性所使用的相同的字符串(或 alternative_name ),来加速后面调用的 find_attr ,以及消除绝大多数的 strcmp 调用。这个函数返回新的表达式,如果有的话。
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 }
函数 n_comma_elts 计算在传入字符串中“ , ”的数目。如果该属性具有名字“ alternative ”,它指向编译器变量 which_alternative ,这个变量必须是一个数值。这个值在 943 行通过 mk_attr_alt 保存入 EQ_ATTR_ALT 。在 960 行的 ATTR_IND_SIMPLIFIED_P 访问这个 rtx 对象的 unchanging 域。这个域如果是 1 ,表示该 rtx 对象所代表的表达式不能被简化。 attr_eq 则构建操作数保存在 attr_hash_table 的 EQ_ATTR 对象。
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 }
然后,在 expand_units 的 1845 行,注意到 simplify_knowing 的第二个参数是由 check_attr_test 生成的 unit 的 condexp 域,我们例子中的 condexp 显示在下图。
图 52 :由 check_attr_test 生成的 condexp
此处在我们的例子中, simplify_knowing 的第一个参数 exp 是一个 rtx 对象,它等效于:
IF op->conflict_exp THEN
op->issue_delay
ELSE
0
或者 op->issue_delay 。(如果没有定义 conflict_exp )
比较上面的表达式与 gccint 中的描述,特别是黑体部分:
CONFLICT-LIST 是一个可选的列表,它给出了这个单元详细的冲突代价。如果指定了,它就是一个条件测试表达式列表,这些表达式将应用到被选择在 NAME 中执行的指令上,而这些指令跟在匹配 TEST 并且正在 NAME 中执行的指令后。对于在该列表中的每条指令, ISSUE-DELAY 指出了冲突代价;而对于不在列表中的指令,这个代价为 0 。如果没有指定, CONFLICT-LIST 默认用于所有使用这个功能单元的指令。
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 }
在 2179 行, max_attr_value ,给定一个属性,返回在该属性里找到的最大的数值,如果该属性不是正确的类型,设置 UNKNOWNP 并返回 INT_MAX 。因此它返回的 max 是由于冲突导致的 issue_delay ,如果一切顺利的话。
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 }
回到 expand_units , simplify_knowing 被包含在一个 FOR 循环里,并且为每一条指令进行调用。在 simplify_knowing 的 2182 行,它构建了 IF_THEN_ELSE 的 rtx 对象,它等效于:
IF unit->condexp THEN
IF op->conflict_exp THEN
op->issue_delay.
ELSE
0
ELSE
op->issue_delay
或者(如果 op->conflict_exp 是 null ):
IF unit->condexp THEN
op->issue_delay
ELSE
op->issue_delay
该表达式,在执行的某个点上给定参数,返回在该功能单元上的发布延迟。这是旧式流水线危险识别器的核心。不过正如所见的,它还不是简化的形式,因此在 2184 行调用 simplify_by_exploding 来把这个表达式转换为规范及简化的形式。
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 只是把所有的 EQ_ATTR 链接在一起, ATTR_EQ_ATTR_P 访问 exp 的 volatil 域,该域在 3896 行设置,以防止 exp 被多次链接。
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
继续 simpilify_by_exploding ,现在 ndim ,对于我们的例子,是 7 ( exp 参考 图 52 ,并假定它是仅有的描述相关单元的 define_funtion_unit ——即在 op 中没有 conflict_exp )。
simplify_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 }
在 3747 行的 dimension 具有如下的定义。在 3757 行, find_attr 构建了与 attr_hash_table 中的 name 关联的属性,并返回之。注意参数 name 为在 attr_hash_table 中的对等对象所替换。在 3758 行,这个节点的 name 被更新。因此在 3772 行, strcmp_check 可以仅比较这两个字符串的地址。
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 }
在 3750 行的整个 FOR 循环,其每次循环将找出同名的属性,并把它们链接入 space 的 同一个元素里,然后为这个 space 的元素调用 add_values_to_cover (属性名是 EQ_ATTR 的第一个孩子的)。
例如,一开始我们得到如下的布局。第一个节点必定通过 3772 行的测试。
图 53 : define_function_unit 处理的案例,图 1
在执行了 3774 ~ 3777 行的代码,以及下一次循环时 3771 行后,我们可以得到如下布局。节点 0 是具有名字“ cpu ”的 EQ_ATTR ,它被链入 space[0] ,其它节点是具有名字“ type ”的 EQ_ATTR ,它们被链入 space[1] (参见 图 52 )。注意到,任意由功能单元描述模式所产生的链表组,在执行的任一点上,每个链表最多有一个节点被匹配,因为属性在一个时间点上不能取多个值。
图 54 : define_function_unit 处理的案例,图 2
然后调用 add_values_to_cover 来把该属性其它未被提及的数值链入这个链表。通过这个方式,这个链表完整代表了这个令人感兴趣的属性。
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 }
dimension 的 attr 域指向描述该属性的 attr_desc 对象,其中的 first_value 域维护记录了所有属性值的一个链表。而 dimension 的 values 域只是记录了用在这个 define_function_unit 模式里的属性的值。显然, values 必定是 attr 的 first_value 的一个子集。这里是我们整合该链表的方式——如果所使用值的数目接近于属性值的总数,把余下未引用的属性值加到链表末尾( 3969 ~ 3989 行),而如果差别相当大的话,则构建一个新的 EXPR_LIST 来代表余下的值(看到它是一个对于所有未被引用值的 NOT 表达式),并从末尾链入。如下图所示。
图 55 : define_function_unit 处理的案例,图 3
上面的把同名属性链接起来,还有整合链表的过程,一再重复,直到所有的属性都得到处理。然后在下面这些链表被排序,常量及数值多优先。
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 ();
在 3790 行的 ndim 表示 space 被使用的元素数目,在 3805 行的 total 则显示了所需的 rtx 对象的数目。在 3803 行, space 的 current_value 域被初始化为 values 的第一个元素。 test_for_current_value 为这个测试构建初始化表达式。
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 }
注意实际上 current_value 总是指向 exp 当前未被处理的部分。因此 condtest 数组穷举了所有的测试表达式。接着 simplify_with_current_value 开始约简表达式 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 }
在 find_and_mark_used_attributes 中,在构建这个链表的时候,其节点的 volital 域已经被设置为 1 。在 4061 行, current_value 总是指向 exp 当前未被处理的部分。如果 current_value 是一个 EQ_ATTR ,我们把 ATTR_EQ_ATTR_P 设为 0 ,在下面 simplify_with_current_value_aux 的 4094 行将依此返回 true_rtx ,假定已经被处理部分的值为 true ,这样才能产生与 condtest 对应的 condval 的值。 EXP 元素的访问次序大致地显示如下(方框内的数字表示序号)。
(注意:由虚线指针指向的是 IOR 对象。 XEXP(exp, 0) 指向的实际上是 图 52 中的树节点,因为上面的方框是由 rtx 对象及 space 共享的。节点 1 是第一个 IOR 对象的第二个孩子,节点 2 是被第一个 IOR 对象的第一个孩子指向的 IOR 对象的第二个孩子,依此类推。不过,节点 7 与节点 8 之间的关系是 AND 。因此虚线指针给出了访问的次序)
图 56 : define_function_unit 处理的案例,图 4