simplify_with_current_value_aux 遍历整个表达式,通过消除不可到达部分来约简这个表达式。
4082 static rtx
4083 simplify_with_current_value_aux (rtx exp) in genattrtab.c
4084 {
4085 int i;
4086 rtx cond;
4087
4088 switch (GET_CODE (exp))
4089 {
4090 case EQ_ATTR:
4091 if (ATTR_EQ_ATTR_P (exp))
4092 return false_rtx ;
4093 else
4094 return true_rtx ;
4095 case CONST_STRING:
4096 case CONST_INT:
4097 return exp;
4098
4099 case IF_THEN_ELSE:
4100 cond = simplify_with_current_value_aux (XEXP (exp, 0));
4101 if (cond == true_rtx )
4102 return simplify_with_current_value_aux (XEXP (exp, 1));
4103 else if (cond == false_rtx )
4104 return simplify_with_current_value_aux (XEXP (exp, 2));
4105 else
4106 return attr_rtx (IF_THEN_ELSE, cond,
4107 simplify_with_current_value_aux (XEXP (exp, 1)),
4108 simplify_with_current_value_aux (XEXP (exp, 2)));
4109
4110 case IOR:
4111 cond = simplify_with_current_value_aux (XEXP (exp, 1));
4112 if (cond == true_rtx )
4113 return cond;
4114 else if (cond == false_rtx )
4115 return simplify_with_current_value_aux (XEXP (exp, 0));
4116 else
4117 return attr_rtx (IOR, cond,
4118 simplify_with_current_value_aux (XEXP (exp, 0)));
4119
4120 case AND:
4121 cond = simplify_with_current_value_aux (XEXP (exp, 1));
4122 if (cond == true_rtx )
4123 return simplify_with_current_value_aux (XEXP (exp, 0));
4124 else if (cond == false_rtx )
4125 return cond;
4126 else
4127 return attr_rtx (AND, cond,
4128 simplify_with_current_value_aux (XEXP (exp, 0)));
4129
4130 case NOT:
4131 cond = simplify_with_current_value_aux (XEXP (exp, 0));
4132 if (cond == true_rtx )
4133 return false_rtx ;
4134 else if (cond == false_rtx )
4135 return true_rtx ;
4136 else
4137 return attr_rtx (NOT, cond);
4138
4139 case COND:
4140 for (i = 0; i < XVECLEN (exp, 0); i += 2)
4141 {
4142 cond = simplify_with_current_value_aux (XVECEXP (exp, 0, i));
4143 if (cond == true_rtx )
4144 return simplify_with_current_value_aux (XVECEXP (exp, 0, i + 1));
4145 else if (cond == false_rtx )
4146 continue ;
4147 else
4148 abort (); /* With all EQ_ATTR's of known value, a case should
4149 have been selected. */
4150 }
4151 return simplify_with_current_value_aux (XEXP (exp, 1));
4152
4153 default :
4154 abort ();
4155 }
4156 }
从 图 51 , 图 52 及 图 56 ,由 EXP(exp, 0) 指向的表达式,可以首先被约简到节点 8 。它等于 true_rtx ,然后我们得到 op 的 issue_delay 作为最终的结果。
4016 static int
4017 increment_current_value (struct dimension *space, int ndim) in genattrtab.c
4018 {
4019 int i;
4020
4021 for (i = ndim - 1; i >= 0; i--)
4022 {
4023 if ((space[i].current_value = XEXP (space[i].current_value, 1)) == 0)
4024 space[i].current_value = space[i].values;
4025 else
4026 return 1;
4027 }
4028 return 0;
4029 }
还是在 simplify_by_exploding 里, increment_current_value 连同 test_for_current_value 以及 simplify_with_current_value 都包含在 3810 行的 FOR 循环中。 increment_current_value 把 current_value 更新为下一部分测试。注意到,对于 space[1] ,“ OTH EPR ”节点实际上是一个为“ NOT(EQ_ATTR(“cpu, k6”) ”的节点。在 simplify_with_current_value_aux 的第二次运行中,链表节点更新为如下:
图 57 : define_function_unit 处理的案例,图 5
注意 NOT(EQ_ATTR(“cpu, k6”) 不在由 XEXP(exp, 0) 开始的链表上(虚线指针的链表)。在 图 57 中,假定节点 8 为 FALSE ,而不是 TRUE 。此处,我们可以看到 add_values_to_cover 的一个目的:通过添加的额外的节点,我们可以所有可能的值来评估这个表达式。
当所有的 space 都到达末尾时, increment_current_value 将返回 0 。为了使算法正确,我们需要按 space 大小降序的次序排序。这就是为什么我们在上面 3790 行进行排序。
那么在 simplify_with_current_value_aux 的第三次运行中,将被访问的节点更新为如下图所示。
图 58 : define_function_unit 处理的案例,图 6
这一次, XEXP(exp, 0) 链表可以被化简为 true_rtx ,并返回 op 的 issue_delay 。依此类推,所有可能的情形都可以被遇见,并加以记录。接着我们回到 simplify_exploding 。
simpilfy_by_exploding (continued)
3820 /* We are now finished with the original expression. */
3821 unmark_used_attributes (0, space, ndim);
3822 free (space);
3823
3824 /* Find the most used constant value and make that the default. */
3825 most_tests = -1;
3826 for (i = num_marks = 0; i < total; i++)
3827 if (GET_CODE (condval[i]) == CONST_STRING
3828 && ! ATTR_EQ_ATTR_P (condval[i]))
3829 {
3830 /* Mark the unmarked constant value and count how many are marked. */
3831 ATTR_EQ_ATTR_P (condval[i]) = 1;
3832 for (j = new_marks = 0; j < total; j++)
3833 if (GET_CODE (condval[j]) == CONST_STRING
3834 && ATTR_EQ_ATTR_P (condval[j]))
3835 new_marks++;
3836 if (new_marks - num_marks > most_tests)
3837 {
3838 most_tests = new_marks - num_marks;
3839 defval = condval[i];
3840 }
3841 num_marks = new_marks;
3842 }
3843 /* Clear all the marks. */
3844 for (i = 0; i < total; i++)
3845 ATTR_EQ_ATTR_P (condval[i]) = 0;
3846
3847 /* Give up if nothing is constant. */
3848 if (num_marks == 0)
3849 ret = exp;
3850
3851 /* If all values are the default, use that. */
3852 else if (total == most_tests)
3853 ret = defval;
3854
3855 /* Make a COND with the most common constant value the default. (A more
3856 complex method where tests with the same value were combined didn't
3857 seem to improve things.) */
3858 else
3859 {
3860 condexp = rtx_alloc (COND);
3861 XVEC (condexp, 0) = rtvec_alloc ((total - most_tests) * 2);
3862 XEXP (condexp, 1) = defval;
3863 for (i = j = 0; i < total; i++)
3864 if (condval[i] != defval)
3865 {
3866 XVECEXP (condexp, 0, 2 * j) = condtest[i];
3867 XVECEXP (condexp, 0, 2 * j + 1) = condval[i];
3868 j++;
3869 }
3870 ret = condexp;
3871 }
3872 free (condtest);
3873 free (condval);
3874 return ret;
3875 }
unmark_used_attributes 重置了所有表达式 EQ_ATTR 中的 ATTR_EQ_ATTR_P 标记。在 3866 及 3867 行, condtest[i] 记录了属性所有可能的值的集合,而 condval[i] 则记录了对应于 condtest[i] 的 issue_delay 。
3932 static void
3933 unmark_used_attributes (rtx list, struct dimension *space, int ndim) in genattrtab.c
3934 {
3935 rtx link, exp;
3936 int i;
3937
3938 for (i = 0; i < ndim; i++)
3939 unmark_used_attributes (space[i].values, 0, 0);
3940
3941 for (link = list; link; link = XEXP (link, 1))
3942 {
3943 exp = XEXP (link, 0);
3944 if (GET_CODE (exp) == EQ_ATTR)
3945 ATTR_EQ_ATTR_P (exp) = 0;
3946 }
3947 }
至于 simplify_by_exploding 的余下部分 , 我们已经看到所有的 condval 共享由 find_and_mark_used_attributes 从起初由机器描述文件生成的 rtx 对象构建出来的 rtx 对象——即在 condval 中的每个 rtx 对象都是唯一的。因此有可能在遍历 condval 时, 计算某个 rtx 对象出现的次数。不过当前仅考虑 CONST_STRING 的 rtx 对象,因为这是一个简单的节点。 如果能找出默认值,我们可以把 condexp 转换为更高效的形式,把最常用的值放在最前面。
expand_units (continued)
1864 /* Compute the mask of function units used. Initially, the unitsmask is
1865 zero. Set up a conditional to compute each unit's contribution. */
1866 unitsmask = make_numeric_value (0);
1867 newexp = rtx_alloc (IF_THEN_ELSE);
1868 XEXP (newexp, 2) = make_numeric_value (0);
1869
1870 /* If we have just a few units, we may be all right expanding the whole
1871 thing. But the expansion is 2**N in space on the number of opclasses,
1872 so we can't do this for very long -- Alpha and MIPS in particular have
1873 problems with this. So in that situation, we fall back on an alternate
1874 implementation method. */
1875 #define NUM_UNITOP_CUTOFF 20
1876
1877 if (num_unit_opclasses < NUM_UNITOP_CUTOFF)
1878 {
1879 /* Merge each function unit into the unit mask attributes. */
1880 for (unit = units ; unit; unit = unit->next)
1881 {
1882 XEXP (newexp, 0) = unit->condexp;
1883 XEXP (newexp, 1) = make_numeric_value (1 << unit->num);
1884 unitsmask = operate_exp (OR_OP, unitsmask, newexp);
1885 }
1886 }
1887 else
1888 {
1889 /* Merge each function unit into the unit mask attributes. */
1890 for (unit = units ; unit; unit = unit->next)
1891 {
1892 XEXP (newexp, 0) = unit->condexp;
1893 XEXP (newexp, 1) = make_numeric_value (1 << unit->num);
1894 unitsmask = operate_exp (ORX_OP, unitsmask, attr_copy_rtx (newexp));
1895 }
1896 }
1897
1898 /* Simplify the unit mask expression, encode it, and make an attribute
1899 for the function_units_used function. */
1900 unitsmask = simplify_by_exploding (unitsmask);
1901
1902 if (num_unit_opclasses < NUM_UNITOP_CUTOFF)
1903 unitsmask = encode_units_mask (unitsmask);
1904 else
1905 {
1906 /* We can no longer encode unitsmask at compile time, so emit code to
1907 calculate it at runtime. Rather, put a marker for where we'd do
1908 the code, and actually output it in write_attr_get(). */
1909 unitsmask = attr_rtx (FFS, unitsmask);
1910 }
1911
1912 make_internal_attr ("*function_units_used", unitsmask,
1913 (ATTR_NEGATIVE_OK | ATTR_FUNC_UNITS));
正如我们知道 function_unit 的 num 域是独一无二的,并且是序列号,在这里 operate_exp 尝试把所有的单元描述链接入一个表达式。例如,我们总共有 4 个单元(号码从 0 到 3 )。在第一次循环中,我们从 operate_exp 获得如下的结果:
if (condexp of unit3)
0x10
else
0
在第二次循环中,我们得到:
if (condexp of unit3)
if(condexp 0f unit2)
0x18
else
0x10
else
if (condexp of unit2)
0x8
else
0
在第三次循环中,我们得到:
if (condexp of unit3)
if (condexp 0f unit2)
if (condexp of unit1)
0x1b
else
0x18
else
if (condexp of unit1)
0x14
else
0x10
else
if (condexp of unit2)
if (condexp of unit1)
0xb
else
0x8
else
if (condexp of uint1)
0x4
else
0
显然,在这里这个函数给出了所有可能的单元组合的掩码。
1618 static rtx
1619 operate_exp (enum operator op, rtx left, rtx right) in genattrtab.c
1620 {
1621 int left_value, right_value;
1622 rtx newexp;
1623 int i;
1624
1625 /* If left is a string, apply operator to it and the right side. */
1626 if (GET_CODE (left) == CONST_STRING)
1627 {
1628 /* If right is also a string, just perform the operation. */
1629 if (GET_CODE (right) == CONST_STRING)
1630 {
1631 left_value = atoi (XSTR (left, 0));
1632 right_value = atoi (XSTR (right, 0));
1633 switch (op)
1634 {
1635 case PLUS_OP:
1636 i = left_value + right_value;
1637 break ;
1638
1639 case MINUS_OP:
1640 i = left_value - right_value;
1641 break ;
1642
1643 case POS_MINUS_OP: /* The positive part of LEFT - RIGHT. */
1644 if (left_value > right_value)
1645 i = left_value - right_value;
1646 else
1647 i = 0;
1648 break ;
1649
1650 case OR_OP:
1651 case ORX_OP:
1652 i = left_value | right_value;
1653 break ;
1654
1655 case EQ_OP:
1656 i = left_value == right_value;
1657 break ;
1658
1659 case RANGE_OP:
1660 i = (left_value << (HOST_BITS_PER_INT / 2)) | right_value;
1661 break ;
1662
1663 case MAX_OP:
1664 if (left_value > right_value)
1665 i = left_value;
1666 else
1667 i = right_value;
1668 break ;
1669
1670 case MIN_OP:
1671 if (left_value < right_value)
1672 i = left_value;
1673 else
1674 i = right_value;
1675 break ;
1676
1677 default :
1678 abort ();
1679 }
1680
1681 if (i == left_value)
1682 return left;
1683 if (i == right_value)
1684 return right;
1685 return make_numeric_value (i);
1686 }
1687 else if (GET_CODE (right) == IF_THEN_ELSE)
1688 {
1689 /* Apply recursively to all values within. */
1690 rtx newleft = operate_exp (op, left, XEXP (right, 1));
1691 rtx newright = operate_exp (op, left, XEXP (right, 2));
1692 if (rtx_equal_p (newleft, newright))
1693 return newleft;
1694 return attr_rtx (IF_THEN_ELSE, XEXP (right, 0), newleft, newright);
1695 }
1696 else if (GET_CODE (right) == COND)
1697 {
1698 int allsame = 1;
1699 rtx defval;
1700
1701 newexp = rtx_alloc (COND);
1702 XVEC (newexp, 0) = rtvec_alloc (XVECLEN (right, 0));
1703 defval = XEXP (newexp, 1) = operate_exp (op, left, XEXP (right, 1));
1704
1705 for (i = 0; i < XVECLEN (right, 0); i += 2)
1706 {
1707 XVECEXP (newexp, 0, i) = XVECEXP (right, 0, i);
1708 XVECEXP (newexp, 0, i + 1)
1709 = operate_exp (op, left, XVECEXP (right, 0, i + 1));
1710 if (! rtx_equal_p (XVECEXP (newexp, 0, i + 1),
1711 defval))
1712 allsame = 0;
1713 }
1714
1715 /* If the resulting cond is trivial (all alternatives
1716 give the same value), optimize it away. */
1717 if (allsame)
1718 return operate_exp (op, left, XEXP (right, 1));
1719
1720 return newexp;
1721 }
1722 else
1723 fatal ("badly formed attribute value");
1724 }
1725
1726 /* A hack to prevent expand_units from completely blowing up: ORX_OP does
1727 not associate through IF_THEN_ELSE. */
1728 else if (op == ORX_OP && GET_CODE (right) == IF_THEN_ELSE)
1729 {
1730 return attr_rtx (IOR, left, right);
1731 }
1732
1733 /* Otherwise, do recursion the other way. */
1734 else if (GET_CODE (left) == IF_THEN_ELSE)
1735 {
1736 rtx newleft = operate_exp (op, XEXP (left, 1), right);
1737 rtx newright = operate_exp (op, XEXP (left, 2), right);
1738 if (rtx_equal_p (newleft, newright))
1739 return newleft;
1740 return attr_rtx (IF_THEN_ELSE, XEXP (left, 0), newleft, newright);
1741 }
1742 else if (GET_CODE (left) == COND)
1743 {
1744 int allsame = 1;
1745 rtx defval;
1746
1747 newexp = rtx_alloc (COND);
1748 XVEC (newexp, 0) = rtvec_alloc (XVECLEN (left, 0));
1749 defval = XEXP (newexp, 1) = operate_exp (op, XEXP (left, 1), right);
1750
1751 for (i = 0; i < XVECLEN (left, 0); i += 2)
1752 {
1753 XVECEXP (newexp, 0, i) = XVECEXP (left, 0, i);
1754 XVECEXP (newexp, 0, i + 1)
1755 = operate_exp (op, XVECEXP (left, 0, i + 1), right);
1756 if (! rtx_equal_p (XVECEXP (newexp, 0, i + 1),
1757 defval))
1758 allsame = 0;
1759 }
1760
1761 /* If the cond is trivial (all alternatives give the same value),
1762 optimize it away. */
1763 if (allsame)
1764 return operate_exp (op, XEXP (left, 1), right);
1765
1766 /* If the result is the same as the LEFT operand,
1767 just use that. */
1768 if (rtx_equal_p (newexp, left))
1769 return left;
1770
1771 return newexp;
1772 }
1773
1774 else
1775 fatal ("badly formed attribute value");
1776 /* NOTREACHED */
1777 return NULL;
1778 }
在上面,如果两个参数的地址相同, rtx_equal_p 只是返回 true 。然后在 expand_units 的 1900 行, simplify_by_exploding 尝试以最常用的值放在最前面来转换这个 unitsmask 表达式。接着在 encode_units_mask 中把这些掩码记录为属性。
2195 static rtx
2196 encode_units_mask (rtx x) in genattrtab.c
2197 {
2198 int i;
2199 int j;
2200 enum rtx_code code;
2201 const char *fmt;
2202
2203 code = GET_CODE (x);
2204
2205 switch (code)
2206 {
2207 case CONST_STRING:
2208 i = atoi (XSTR (x, 0));
2209 if (i < 0)
2210 /* The sign bit encodes a one's complement mask. */
2211 abort ();
2212 else if (i != 0 && i == (i & -i))
2213 /* Only one bit is set, so yield that unit number. */
2214 for (j = 0; (i >>= 1) != 0; j++)
2215 ;
2216 else
2217 j = ~i;
2218 return attr_rtx (CONST_STRING, attr_printf (MAX_DIGITS, "%d", j));
2219
2220 case REG:
2221 case QUEUED:
2222 case CONST_INT:
2223 case CONST_DOUBLE:
2224 case CONST_VECTOR:
2225 case SYMBOL_REF:
2226 case CODE_LABEL:
2227 case PC:
2228 case CC0:
2229 case EQ_ATTR:
2230 case EQ_ATTR_ALT:
2231 return x;
2232
2233 default :
2234 break ;
2235 }
2236
2237 /* Compare the elements. If any pair of corresponding elements
2238 fail to match, return 0 for the whole things. */
2239
2240 fmt = GET_RTX_FORMAT (code);
2241 for (i = GET_RTX_LENGTH (code) - 1; i >= 0; i--)
2242 {
2243 switch (fmt[i])
2244 {
2245 case 'V':
2246 case 'E':
2247 for (j = 0; j < XVECLEN (x, i); j++)
2248 XVECEXP (x, i, j) = encode_units_mask (XVECEXP (x, i, j));
2249 break ;
2250
2251 case 'e':
2252 XEXP (x, i) = encode_units_mask (XEXP (x, i));
2253 break ;
2254 }
2255 }
2256 return x;
2257 }
继续 expand_units ,其它数据也将被填入属性。
expand_units (continued)
1915 /* Create an array of ops for each unit. Add an extra unit for the
1916 result_ready_cost function that has the ops of all other units. */
1917 unit_ops = xmalloc ((num_units + 1) * sizeof (struct function_unit_op **));
1918 unit_num = xmalloc ((num_units + 1) * sizeof (struct function_unit *));
1919
1920 unit_num[num_units ] = unit = xmalloc (sizeof (struct function_unit));
1921 unit->num = num_units ;
1922 unit->num_opclasses = 0;
1923
1924 for (unit = units ; unit; unit = unit->next)
1925 {
1926 unit_num[num_units ]->num_opclasses += unit->num_opclasses;
1927 unit_num[unit->num] = unit;
1928 unit_ops[unit->num] = op_array =
1929 xmalloc (unit->num_opclasses * sizeof (struct function_unit_op *));
1930
1931 for (op = unit->ops; op; op = op->next)
1932 op_array[op->num] = op;
1933 }
1934
1935 /* Compose the array of ops for the extra unit. */
1936 unit_ops[num_units ] = op_array =
1937 xmalloc (unit_num[num_units ]->num_opclasses
1938 * sizeof (struct function_unit_op *));
1939
1940 for (unit = units , i = 0; unit; i += unit->num_opclasses, unit = unit->next)
1941 memcpy (&op_array[i], unit_ops[unit->num],
1942 unit->num_opclasses * sizeof (struct function_unit_op *));
1943
1944 /* Compute the ready cost function for each unit by computing the
1945 condition for each non-default value. */
1946 for (u = 0; u <= num_units ; u++)
1947 {
1948 rtx orexp;
1949 int value;
1950
1951 unit = unit_num[u];
1952 op_array = unit_ops[unit->num];
1953 num = unit->num_opclasses;
1954
1955 /* Sort the array of ops into increasing ready cost order. */
1956 for (i = 0; i < num; i++)
1957 for (j = num - 1; j > i; j--)
1958 if (op_array[j - 1]->ready < op_array[j]->ready)
1959 {
1960 op = op_array[j];
1961 op_array[j] = op_array[j - 1];
1962 op_array[j - 1] = op;
1963 }
上面直到 2007 行 , 构建了如下的数据结构。新构建的数组 unit_num 的元素指向 units 的 function_unit , 除了最后的那个。它是一个包含了所有 function_unit 的全部 function_unit_op 的伪对象 ( 参见 1940 行 ) 。 unit_ops 为所有 function_unit 保存全部的 function_unit_op 。注意在 1956 行,被 unit_ops 指向的数组以就绪代价降序排序。我们在下图显示了这些数据间的关系(看到 unit_num 与 unit_ops 是独立的数组,相同索引的项指向同一个 define_function_unit 模式,不过是不同的部分)。
图 59 : define_function_unit 处理的案例,图 7
expand_units (continued)
1965 /* Determine how many distinct non-default ready cost values there
1966 are. We use a default ready cost value of 1. */
1967 nvalues = 0; value = 1;
1968 for (i = num - 1; i >= 0; i--)
1969 if (op_array[i]->ready > value)
1970 {
1971 value = op_array[i]->ready;
1972 nvalues++;
1973 }
1974
1975 if (nvalues == 0)
1976 readycost = make_numeric_value (1);
1977 else
1978 {
1979 /* Construct the ready cost expression as a COND of each value from
1980 the largest to the smallest. */
1981 readycost = rtx_alloc (COND);
1982 XVEC (readycost, 0) = rtvec_alloc (nvalues * 2);
1983 XEXP (readycost, 1) = make_numeric_value (1);
1984
1985 nvalues = 0;
1986 orexp = false_rtx ;
1987 value = op_array[0]->ready;
1988 for (i = 0; i < num; i++)
1989 {
1990 op = op_array[i];
1991 if (op->ready <= 1)
1992 break ;
1993 else if (op->ready == value)
1994 orexp = insert_right_side (IOR, orexp, op->condexp, -2, -2);
1995 else
1996 {
1997 XVECEXP (readycost, 0, nvalues * 2) = orexp;
1998 XVECEXP (readycost, 0, nvalues * 2 + 1)
1999 = make_numeric_value (value);
2000 nvalues++;
2001 value = op->ready;
2002 orexp = op->condexp;
2003 }
2004 }
2005 XVECEXP (readycost, 0, nvalues * 2) = orexp;
2006 XVECEXP (readycost, 0, nvalues * 2 + 1) = make_numeric_value (value);
2007 }
在以就绪代价排序后,对于每个 function_unit_op 数组,包括最后的那个伪对象, 1967 ~ 2007 行如下构建 readycost 表达式,在这里我们假定某个具有 4 个 ready 域分别为 5 , 5 , 2 , 1 的 function_unit_op 的 function_unit 链接在 ops 域。正如我们从 gen_unit 及上面的注释中看到的, function_unit_op 代表使用这个功能单元的指令,而这个指令被 function_unit_op 的 condexp 域所识别。现在假定这个 condexp 指向 condexp1 , condexp2 , condexp3 , condexp4 。
对于这个例子,在 1975 行的 nvalues 将是 2. 那么 readycost 看起来就像如下。
图 60 : define_function_unit 处理的案例,图 8
假定这个 function_unit 的 condexp 域是简化后的表达式 IOR (condexp1 (IOR (condexp2 (IOR (condexp3 condexp4))))) 。在 2059 行的 FOR 循环,正如在它前面的注释所解释的,构建了属性,来为所有使用这个单元的指令,记录 READY-COST 数据。
expand_units (continued)
2009 if (u < num_units )
2010 {
2011 rtx max_blockage = 0, min_blockage = 0;
2012
2013 /* Simplify the readycost expression by only considering insns
2014 that use the unit. */
2015 readycost = simplify_knowing (readycost, unit->condexp);
2016
2017 /* Determine the blockage cost the executing insn (E) given
2018 the candidate insn (C). This is the maximum of the issue
2019 delay, the pipeline delay, and the simultaneity constraint.
2020 Each function_unit_op represents the characteristics of the
2021 candidate insn, so in the expressions below, C is a known
2022 term and E is an unknown term.
2023
2024 We compute the blockage cost for each E for every possible C.
2025 Thus OP represents E, and READYCOST is a list of values for
2026 every possible C.
2027
2028 The issue delay function for C is op->issue_exp and is used to
2029 write the `<name>_unit_conflict_cost' function. Symbolically
2030 this is "ISSUE-DELAY (E,C)".
2031
2032 The pipeline delay results form the FIFO constraint on the
2033 function unit and is "READY-COST (E) + 1 - READY-COST (C)".
2034
2035 The simultaneity constraint is based on how long it takes to
2036 fill the unit given the minimum issue delay. FILL-TIME is the
2037 constant "MIN (ISSUE-DELAY (*,*)) * (SIMULTANEITY - 1)", and
2038 the simultaneity constraint is "READY-COST (E) - FILL-TIME"
2039 if SIMULTANEITY is nonzero and zero otherwise.
2040
2041 Thus, BLOCKAGE (E,C) when SIMULTANEITY is zero is
2042
2043 MAX (ISSUE-DELAY (E,C),
2044 READY-COST (E) - (READY-COST (C) - 1))
2045
2046 and otherwise
2047
2048 MAX (ISSUE-DELAY (E,C),
2049 READY-COST (E) - (READY-COST (C) - 1),
2050 READY-COST (E) - FILL-TIME)
2051
2052 The `<name>_unit_blockage' function is computed by determining
2053 this value for each candidate insn. As these values are
2054 computed, we also compute the upper and lower bounds for
2055 BLOCKAGE (E,*). These are combined to form the function
2056 `<name>_unit_blockage_range'. Finally, the maximum blockage
2057 cost, MAX (BLOCKAGE (*,*)), is computed. */
2058
2059 for (op = unit->ops; op; op = op->next)
2060 {
2061 rtx blockage = op->issue_exp;
2062 blockage = simplify_knowing (blockage, unit->condexp);
2063
2064 /* Add this op's contribution to MAX (BLOCKAGE (E,*)) and
2065 MIN (BLOCKAGE (E,*)). */
2066 if (max_blockage == 0)
2067 max_blockage = min_blockage = blockage;
2068 else
2069 {
2070 max_blockage
2071 = simplify_knowing (operate_exp (MAX_OP, max_blockage,
2072 blockage),
2073 unit->condexp);
2074 min_blockage
2075 = simplify_knowing (operate_exp (MIN_OP, min_blockage,
2076 blockage),
2077 unit->condexp);
2078 }
2079
2080 /* Make an attribute for use in the blockage function. */
2081 str = attr_printf ((strlen (unit->name) + sizeof "*_block_"
2082 + MAX_DIGITS),
2083 "*%s_block_%d", unit->name, op->num);
2084 make_internal_attr (str, blockage, ATTR_SPECIAL);
2085 }
2086
2087 /* Record MAX (BLOCKAGE (*,*)). */
2088 {
2089 int unknown;
2090 unit->max_blockage = max_attr_value (max_blockage, &unknown);
2091 }
2092
2093 /* See if the upper and lower bounds of BLOCKAGE (E,*) are the
2094 same. If so, the blockage function carries no additional
2095 information and is not written. */
2096 newexp = operate_exp (EQ_OP, max_blockage, min_blockage);
2097 newexp = simplify_knowing (newexp, unit->condexp);
2098 unit->needs_blockage_function
2099 = (GET_CODE (newexp) != CONST_STRING
2100 || atoi (XSTR (newexp, 0)) != 1);
2101
2102 /* If the all values of BLOCKAGE (E,C) have the same value,
2103 neither blockage function is written. */
2104 unit->needs_range_function
2105 = (unit->needs_blockage_function
2106 || GET_CODE (max_blockage) != CONST_STRING);
2107
2108 if (unit->needs_range_function)
2109 {
2110 /* Compute the blockage range function and make an attribute
2111 for writing its value. */
2112 newexp = operate_exp (RANGE_OP, min_blockage, max_blockage);
2113 newexp = simplify_knowing (newexp, unit->condexp);
2114
2115 str = attr_printf ((strlen (unit->name)
2116 + sizeof "*_unit_blockage_range"),
2117 "*%s_unit_blockage_range", unit->name);
2118 make_internal_attr (str, newexp, (ATTR_STATIC|ATTR_BLOCKAGE|ATTR_UNSIGNED));
2119 }
2120
2121 str = attr_printf (strlen (unit->name) + sizeof "*_unit_ready_cost",
2122 "*%s_unit_ready_cost", unit->name);
2123 make_internal_attr (str, readycost, ATTR_STATIC);
2124 } // end if u < nim_units
2125 else
2126 {
2127 /* Make an attribute for the ready_cost function. Simplifying
2128 further with simplify_by_exploding doesn't win. */
2129 str = "*result_ready_cost";
2130 make_internal_attr (str, readycost, ATTR_NONE);
2131 }
2132 }
在 2061 行的 op->issue_exp ,正如我们在 1842 ~ 1847 所见,逻辑上它等同于:
IF op->conflict_exp THEN
op->issue_delay
ELSE
op->issue_delay (1)
或者 op->issue_delay (1’)
那么在 2062 行,首先在逻辑上在 simplify_knowing 里 构建如下的 blockage :
IF (unit->condexp) THEN
IF op->conflict_exp THEN
op->issue_delay
ELSE
0
ELSE
op->issue_delay (2)
或者
IF (unit->condexp) THEN
op->issue_delay
ELSE
op->issue_delay (2’)
然后 FOR 循环找出具有最大 issue_delay 或者最小 issue_delay 的表达式。而以下的代码则把数据记录入相应的属性。 注意它们是 blockage , readycost 及 blockage range ( 如果可能的话 ) 。
expand_units (continued)
2134 /* For each unit that requires a conflict cost function, make an attribute
2135 that maps insns to the operation number. */
2136 for (unit = units ; unit; unit = unit->next)
2137 {
2138 rtx caseexp;
2139
2140 if (! unit->needs_conflict_function
2141 && ! unit->needs_blockage_function)
2142 continue ;
2143
2144 caseexp = rtx_alloc (COND);
2145 XVEC (caseexp, 0) = rtvec_alloc ((unit->num_opclasses - 1) * 2);
2146
2147 for (op = unit->ops; op; op = op->next)
2148 {
2149 /* Make our adjustment to the COND being computed. If we are the
2150 last operation class, place our values into the default of the
2151 COND. */
2152 if (op->num == unit->num_opclasses - 1)
2153 {
2154 XEXP (caseexp, 1) = make_numeric_value (op->num);
2155 }
2156 else
2157 {
2158 XVECEXP (caseexp, 0, op->num * 2) = op->condexp;
2159 XVECEXP (caseexp, 0, op->num * 2 + 1)
2160 = make_numeric_value (op->num);
2161 }
2162 }
2163
2164 /* Simplifying caseexp with simplify_by_exploding doesn't win. */
2165 str = attr_printf (strlen (unit->name) + sizeof "*_cases",
2166 "*%s_cases", unit->name);
2167 make_internal_attr (str, caseexp, ATTR_SPECIAL);
2168 }
2169 }
Unit 的 num_opclasses 域记录了在相关 function_unit 中 ops 的数目(即共享这个单元的指令数目)。 expand_units 的余下代码则构建属性来记录类似于 switch-case 的表达式——或称之为指令号码映射表达式。
现在我们有了用于 define_function_unit 模式,记录结构化数据的属性,这些属性 在后面将被用来输出流水线危险识别器的辅助函数。