simplify_with_current_value_aux traverses the whole expression, and reduces the expression by eliminating unreachable parts.
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 }
From figure 51 , figure 52 , and figure 56 , expression referred by EXP(exp, 0) can first be reduced to node8 which equals to true_rtx , then we get issue_delay of op as final result.
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 }
Still in simplify_by_exploding , increment_current_value tegother with test_for_current_value and simplify_with_current_value are enclosed in FOR loop at line 3810. increment_current_value updates current_value as the next part of the test. Notice that in space[1] the “OTH EPR” node is a single node of NOT(EQ_ATTR(“cpu, k6”). In the second run of simplify_with_current_value_aux , the nodes are updated as below.
figure 57 : example of define_function_unit handling, figure 5
See that NOT(EQ_ATTR(“cpu, k6”) can’t be accessed following link headed by XEXP(exp, 0) (via dotted pointers). In figure 57 node 8 is assumed as FALSE instead as TRUE. Here, we can see one of purpose of add_values_to_cover : with extra nodes appended, we can evaluate the expression with all possible set of values.
increment_current_value will return 0 when all space s arrives their end, to make the alogrithm correct, we need sort the space s with size in decreasing order. That is why we do sorting above at line 3790.
So in the third run of simplify_with_current_value_aux , the nodes to be visited are updated as following.
figure 58 : example of define_function_unit handling, figure 6
This time, XEXP(exp, 0) list can be reduced to true_rtx and issue_delay of op is returned. And so on, all possible situations can be encounted and recorded. After that we go back to 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 resets the ATTR_EQ_ATTR_P flag in all EQ_ATTR expressions. At line 3866 and line 3867, condtest[i] records the all possible sets of values of attributes, and condval[i] records issue_delay corresponding to condtest[i] .
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 }
For the last part of simplify_by_exploding , we have seen that condval s share rtx objects created by find_and_mark_used_attributes from the rtx objects which are originally created from machine description file – that is every rtx object in condval s is unique. So it is possible to count how many time certain rtx object encountered during tranversing condval s. However currently only rtx object of CONST_STRING is considered, as it is a simple node. If default value can be found out, we can reform condexp into a more efficient form with most used values appear first.
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));
As we know that the num field of function_unit is unique and it is sequence number, here operate_exp tries to link all unit description into a expression. For example, we have 4 units in all (number from 0 to 3). In first iteration, we get following from operate_exp :
if (condexp of unit3)
0x10
else
0
With second iteration, we get:
if (condexp of unit3)
if(condexp 0f unit2)
0x18
else
0x10
else
if (condexp of unit2)
0x8
else
0
With third iteration, we get:
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
Obvioulsy, here the function gives out bit masks for all possible units association.
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 }
Above, rtx_equal_p just returns true if two parameters are of same address. Then at line 1900 in expand_units , simplify_by_exploding tries to reform this unitsmask expression with most used value appears first. Then records these bit masks as attribute in 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 }
Continue with expand_units , other data also will be filled into attributes.
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 }
Above, till line 2007, data structure of following is created. Elements of new created array unit_num point to function_unit of units except the last one which is a fake ones containing all function_unit_op of all function_unit (see line 1940). unit_ops holds all function_unit_op for all function_unit. Notice that at line 1956 the array pointed by unit_ops is sorted by ready cost in decreasing order. We show the relationship among these data in below figure (see that unit_num and unit_ops are separate arrays, items at the same index point to same define_function_unit pattern but to different parts).
figure 59 : example of define_function_unit handling, figure 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 }
After sorted by ready cost, for every array of function_unit_op including the last fake one, line 1967 – 2007 constructs readycost expression as below, here we assume certain function_unit has 4 function_unit_ops linked by ops field, which have ready field with value 5, 5, 2, 1. As we see from gen_unit , and the comment above, function_unit_op presenting the instruction using this function unit, and the instruction is identified by condexp field of function_unit_op. Now assumes the condexp points to condexp1, condexp2, condexp3, condexp4 correspondingly.
For this example, nvalues at line 1975 will be 2. Then readycost looks like following.
figure 60 : example of define_function_unit handling, figure 8
Assuming the condexp field of the function_unit is simplified expression of IOR (condexp1 (IOR (condexp2 (IOR (condexp3 condexp4))))) . The FOR block at line 2059, as explained by the comment above it, creates attribute to record READY-COST data for all instructions using the unit.
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 }
At line 2061, op->issue_exp , as we see at line 1842 – 1847, it is logical the same as:
IF op->conflict_exp THEN
op->issue_delay
ELSE
op->issue_delay (1)
Or op->issue_delay (1’)
Then at line 2062, blockage first is built in logical as below in simplify_knowing .
IF (unit->condexp) THEN
IF op->conflict_exp THEN
op->issue_delay
ELSE
0
ELSE
op->issue_delay (2)
Or
IF (unit->condexp) THEN
op->issue_delay
ELSE
op->issue_delay (2’)
Then the FOR block finds out the expression has max issue_delay or min issue_delay. And following code records the data into corresponding attributes. Notice that they are blockage, readycost, and blockage range (if possible).
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 }
num_opclasses field of unit records the number of ops in related function_unit (that is number the instructions sharing the unit). The left code of expand_units builds attributes that records switch-case alike expression – or call it instruction number mapping expression.
Now we have attributes recording structured data for define_function_unit patterns, these attributes will later be used to output helper functions for pipeline hazards recognizer.